2632c460 by simon

默认提交

0 parents
Showing 397 changed files with 3443 additions and 0 deletions
1 root = true;
2
3 [*]
4 # indent_style = tab
5 indent_style = space
6 # indent_size = 4
7 indent_size = 2
8 tab_width = 2
9 end_of_line = lf
10 trim_trailing_whitespace = true
11 insert_final_newline = true
12
13 # [*.{json,yml,wxml,html}]
14 # indent_style = tab
15 # indent_size = 4
16 # tab_width = 2
17
18
19 [README.md]
20 trim_trailing_whitespace = ignore
1 .idea
2 .DS_Store
3 dist
4 tmp
5 node_modules
6 _old
7 config.custom.js
8
9 src/assets/images/filetype.png
10
11 src/assets/images/filetype@2x.png
1 .gitignore
2 .editorconfig
3 .eslintrc
4 .idea
5 node_modules/
6 npm-debug.log
7 CHANGELOG.md
8 test
9 examples
10 gulpfile.js
11 .travis.yml
12 appveyor.yml
13 .DS_Store
14 dist
15 tmp
16 _old
17 config.custom.js
18 src/assets/images/filetype.png
19 src/assets/images/filetype@2x.png
1 sudo: false
2 language: node_js
3 node_js:
4 - "6"
5 - "7"
6 - "8"
7 - "stable"
8 before_script:
9 - npm install -g gulp@next
1 MIT License
2
3 Copyright (c) 2017 Jeff Ma
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in all
13 copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 SOFTWARE.
1 ## 介绍
2
3 mp-gulp-framework 是一个专门为开发微信小程序打造的前端开发工作流,基于Gulp 4 开发,旨在通过工作流的方式解决微信小程序开发过程中写前端代码的痛点。
4
5 借鉴于:[https://github.com/Jeff2Ma/WeApp-Workflow](https://github.com/Jeff2Ma/WeApp-Workflow)
6 在此基础上作修改。
7
8 ## 功能
9
10 ### SCSS 实时编译为 WXSS
11
12 使用Sass 预处理器,让写CSS 更加顺畅。`.scss`文件会实时编译为微信小程序支持的`.wxss`文件。
13
14 ### WXSS(CSS) 中px 单位转小程序单位rpx
15
16 以官方推荐的iPhone 6 为标准设计格式,开发中直接写`px` 即可自动转换为`rpx`
17
18 其中屏幕铺满为750px。
19
20 ```css
21 // Input: src/pages/index/index.scss
22 .index__header {
23 font-size: 14px;
24 margin-top: 20PX; /* 如果为大写的`PX`单位则不会转换 */
25 }
26
27 // Output: dist/pages/index/index.wxss
28 .index__header {
29 font-size: 28rpx;
30 margin-top: 20PX; /* 如果为大写的`PX`单位则不会转换 */
31 }
32
33 ```
34
35 ### 图片压缩
36
37 实时压缩图片并采用增量方式防止被重复压缩。
38
39 ### 自动上传图片到CDN 并更新路径为https 绝对路径
40
41 小程序不支持相对路径的图片引用,仅支持带`https`协议头的绝对路径。本工作流可以将WXML 以及WXSS 文件中引用的相对路径图片上传到云存储CDN 或通过FTP/SFTP 协议上传到个人服务器空间。目前支持腾讯云,七牛云。
42
43 ```html
44 // Input: src/pages/index/index.wxml
45 <image src="%ASSETS_IMG%/t.png"></image>
46
47 // Output: dist/pages/index/index.wxml
48 <image src="https://cdn.devework.com/weapp/devework/t.png"></image>
49 ```
50
51 ### Font 文件转为base64 编码
52
53 小程序不支持相对路径的字体文件,本工作流可将CSS 中引用到的Font 文件转码为base64 并替换原路径。
54
55 ```
56 // Input: src/pages/index/index.scss
57 @font-face {
58 font-family: 'fontello';
59 src: url("assets/fonts/fontello.ttf") format('truetype');
60 }
61
62 // Output: dist/pages/index/index.wxss
63 @font-face {
64 font-family: 'fontello';
65 src: url(data:application/font-sfnt;charset=utf-8;base64,AAEAAAAPAIAA....FsASNsQIARAAA) format("truetype");
66 }
67
68 ```
69 ### 全自动构建雪碧图及生成相应CSS
70
71 本功能由[postcss-lazysprite](https://github.com/Jeff2Ma/postcss-lazysprite) 插件驱动。开发中准备好图片后仅仅写一句类似`@lazysprite "xxxx"`的代码,即可全自动构建雪碧图及生成相应CSS。
72
73 ```css
74 // Input: src/app.scss
75 @lazysprite "filetype";
76
77 // Output: dist/app.wxss
78 .icon-filetype-doc {
79 background-image: url(../sprites/filetype.png);
80 background-position: 0 0;
81 width: 80px;
82 height: 80px;
83 }
84
85 .icon-filetype-pdf {
86 background-image: url(../sprites/filetype.png);
87 background-position: -90px 0;
88 width: 80px;
89 height: 80px;
90 }
91
92 @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio:2) {
93 .icon-filetype-doc {
94 background-image: url(../sprites/filetype@2x.png);
95 background-position: 0 0;
96 background-size: 170px 170px;
97 }
98
99 .icon-filetype-pdf {
100 background-image: url(../sprites/filetype@2x.png);
101 background-position: -90px 0;
102 background-size: 170px 170px;
103 }
104 }
105 ```
106
107
108 ## 项目结构
109
110 ```
111 .
112 ├── config.custom.js // gulp自定义配置,会覆盖config.js
113 ├── config.js // gulp 配置文件
114 ├── gulpfile.js
115 ├── package.json
116 ├── src // 开发目录
117 │   ├── app.js
118 │   ├── app.json
119 │   ├── app.scss
120 │   ├── assets // 开发相关的静态文件原始资源
121 │  │   ├── fonts //字体文件
122 │  │   ├── images // 图片文件,可被上传到CDN
123 │  │   ├── scss // 一般放置SCSS 的minxins 等被import 的SCSS 文件
124 │  │   └── sprites // 生成雪碧图小图的目录
125 │   ├── image // 小程序专用的图片资源(如tabbar icon)目录
126 │   ├── pages
127 │   └── utils
128 ├── tmp // 通过src 目录编译后生成的缓存目录
129 └── dist // 通过src 目录编译后生成的文件目录,也是小程序开发的项目目录
130
131 ```
1 # Notes:
2 # - Minimal appveyor.yml file is an empty file. All sections are optional.
3 # - Indent each level of configuration with 2 spaces. Do not use tabs!
4 # - All section names are case-sensitive.
5 # - Section names should be unique on each level.
6
7 #---------------------------------#
8 # general configuration #
9 #---------------------------------#
10
11 # branches to build
12 #branches:
13 # # whitelist
14 # only:
15 # - master
16 # - test
17
18 # Do not build on tags (GitHub and BitBucket)
19 skip_tags: true
20
21 # Do not build feature branch with open Pull Requests
22 skip_branch_with_pr: true
23
24 # Build worker image (VM template)
25 image: Visual Studio 2015
26
27 environment:
28 matrix:
29 - nodejs_version: 4.7.0
30
31 # scripts that run after cloning repository
32 install:
33 # to run script as a PowerShell command prepend it with ps:
34 - ps: Install-Product node $env:nodejs_version
35 # batch commands start from cmd:
36 - npm cache clean
37 - npm i
38 - npm install -g gulp@next
39
40 # to run your custom scripts instead of automatic tests
41 test_script:
42 # Output useful info for debugging.
43 - node --version && npm --version
44 - npm i
45 - pwd
46 - gulp test
47
48 # Don't actually build.
49 build: off
50
51 matrix:
52 fast_finish: true
53
54 cache:
55 # local npm modules
56 - C:\Users\appveyor\AppData\Roaming\npm-cache -> package.json # npm cache
57 - node_modules -> package.json
1 /**
2 * ------------------------------------------------------------------
3 * 配置文件
4 *
5 * 建议复制一份并重命名为 config.custom.js ,即可在config.custom.js 上根据需求进行配置
6 * ------------------------------------------------------------------
7 *
8 */
9
10 module.exports = {
11 "enabledQcloud": false, //是否开启腾讯云COS 上传功能
12 // 腾讯云COS 上传功能配置表
13 "qcloud": {
14 "appid": "1111111",
15 "secretId": "xxx",
16 "secretKey": "xxxxx",
17 "bucket": "xxxx",
18 "region": "sh",
19 "prefix": "what-ever/you-want",
20 "overWrite": true,
21 "headers": {
22 "Cache-Control": "max-age=5184000"
23 }
24 },
25 // 静态资源CDN 域名,配合CDN 功能实用,线上请确保在mp管理端已经注册域名
26 "assetsCDN": "https://res.jianhui.org/"
27 };
1 # chmod u+x git.sh
2 unset msg
3
4 read -p "请输入commit提交的描述: " msg
5
6 if [[ $msg == "" ]]; then
7 msg="默认提交"
8 fi
9 git add -A
10 git commit -m $msg
11 git push
12 git status
1 /**
2 * ------------------------------------------------------------------
3 * gulpfile 文件
4 * ------------------------------------------------------------------
5 */
6
7 var path = require('path');
8 var gulp = require('gulp');
9 var changed = require('gulp-changed');
10 var sass = require('gulp-sass');
11 var rename = require('gulp-rename');
12 var imagemin = require('gulp-imagemin');
13 var sftp = require('gulp-sftp');
14 var del = require('del');
15 var replace = require('gulp-replace');
16 var postcss = require('gulp-postcss');
17 var qcloudUpload = require('gulp-qcloud-upload');
18 var gulpif = require('gulp-if');
19 var gutil = require('gulp-util');
20 var newer = require('gulp-newer');
21 var cache = require('gulp-cached');
22 var debug = require('gulp-debug');
23 var pxtorpx = require('postcss-px2rpx');
24 // var base64 = require('postcss-font-base64');
25 // var lazysprite = require('postcss-lazysprite');
26 var argv = require('yargs').argv;
27 var config = null;
28
29 // 获取用户配置
30 try {
31 config = require('./config.custom.js');
32 } catch (e) {
33 try {
34 config = require('./config.js');
35 } catch (e) {
36 log(gutil.colors.red('丢失配置文件(config.js/config.custom.js)'));
37 }
38 }
39
40 // 相关路径配置
41 var paths = {
42 src: {
43 baseDir: 'src',
44 imgDir: 'src/image',
45 spriteDir: 'src/assets/sprites',
46 scssDir: 'src/assets/scss',
47 imgFiles: 'src/image/**/*',
48 scssFiles: 'src/**/*.scss',
49 baseFiles: ['src/**/*.{png,js,json,wxml,wxss,wxs,ts,woff2}', '!src/assets/**/*', '!src/image/**/*'],
50 busFiles: ['src/**/*.{js,json}', '!src/assets/**/*', '!src/image/**/*', '!src/ui/**/*'],
51 assetsDir: 'src/assets',
52 assetsImgFiles: 'src/assets/images/**/*.{png,jpg,jpeg,svg,gif}',
53 wxmlFiles: ['src/**/*.wxml'],
54 jsFiles: 'src/**/*.js'
55 },
56 dist: {
57 baseDir: 'dist',
58 imgDir: 'dist/image',
59 wxssFiles: 'dist/**/*.wxss',
60 },
61 tmp: {
62 baseDir: 'tmp',
63 imgDir: 'tmp/assets/images',
64 imgFiles: 'tmp/assets/images/**/*.{png,jpg,jpeg,svg,gif}'
65 }
66 };
67
68 // 雪碧图的配置
69 var lazyspriteConfig = {
70 imagePath: paths.src.spriteDir,
71 stylesheetInput: paths.src.scssDir,
72 stylesheetRelative: paths.src.assetsDir,
73 spritePath: paths.src.assetsDir + '/images',
74 smartUpdate: false,
75 cssSeparator: '-',
76 outputExtralCSS: true,
77 nameSpace: 'icon-'
78 };
79
80 // Log for output msg.
81 function log() {
82 var data = Array.prototype.slice.call(arguments);
83 gutil.log.apply(false, data);
84 }
85
86 // 压缩图片
87 function imageMin() {
88 // return gulp.src(paths.src.imgFiles, {si≤nce: gulp.lastRun(imageMin)})
89 return gulp.src(paths.src.imgFiles)
90 .pipe(newer(paths.dist.imgDir))
91 .pipe(imagemin({
92 progressive: true,
93 svgoPlugins: [{
94 removeViewBox: false
95 }]
96 }))
97 .pipe(gulp.dest(paths.dist.imgDir));
98 }
99
100 // assets 文件夹下的图片处理
101 function assetsImgMin() {
102 return gulp.src(paths.src.assetsImgFiles)
103 .pipe(newer(paths.tmp.imgDir))
104 .pipe(imagemin({
105 progressive: true,
106 svgoPlugins: [{
107 removeViewBox: false
108 }]
109 }))
110 .pipe(gulp.dest(paths.tmp.imgDir))
111 }
112
113 // Sass 编译
114 function sassCompile() {
115 var res = config.assetsCDN + config.qcloud.prefix + '/';
116 // 缩放比例 1为750
117 var pxtorpxOpts = {
118 times: 1
119 };
120 return gulp.src(paths.src.scssFiles)
121 .pipe(sass({
122 errLogToConsole: true,
123 outputStyle: 'expanded'
124 })
125 .on('error', sass.logError))
126 .pipe(gulpif(Boolean(argv.debug), debug({
127 title: '`sassCompile` Debug:'
128 })))
129 // .pipe(postcss([lazysprite(lazyspriteConfig), pxtorpx(pxtorpxOpts), base64()]))
130 .pipe(postcss([pxtorpx(pxtorpxOpts)]))
131 .pipe(rename({
132 'extname': '.wxss'
133 }))
134 .pipe(replace('.scss', '.wxss'))
135 // .pipe(replace('%ASSETS_IMG%/', res))
136 // .pipe(replace('src/assets/images', res)) // 雪碧图CSS RUL 中的图片路径
137 .pipe(gulp.dest(paths.dist.baseDir))
138 }
139
140 // 复制业务文件 只复制修改过的文件
141 function copyModifyFiles() {
142 return gulp.src(paths.src.busFiles)
143 .pipe(changed(paths.dist.baseDir))
144 .pipe(gulp.dest(paths.dist.baseDir));
145 }
146
147 // 复制基础文件
148 function copyBasicFiles() {
149 return gulp.src(paths.src.baseFiles, {})
150 .pipe(gulp.dest(paths.dist.baseDir));
151 }
152
153 // 复制 WXML
154 function copyWXML() {
155 return gulp.src(paths.src.wxmlFiles, {})
156 .pipe(gulp.dest(paths.dist.baseDir));
157 }
158
159
160 // 重写WXML 中 image 标签中的图片路径
161 function wxmlImgRewrite() {
162 var res = config.assetsCDN + config.qcloud.prefix + '/';
163 return gulp.src(paths.src.wxmlFiles)
164 // .pipe(replace('%ASSETS_IMG%/', res))
165 .pipe(gulp.dest(paths.dist.baseDir))
166 }
167
168 // clean 任务, dist 目录
169 function cleanDist() {
170 return del(paths.dist.baseDir);
171 }
172
173 // clean tmp 目录
174 function cleanTmp() {
175 return del(paths.tmp.baseDir);
176 }
177
178 // 腾讯云上传任务
179 function qcloudCDN(cb) {
180 if (config.enabledQcloud) {
181 // return gulp.src(paths.src.assetsImgFiles, {since: gulp.lastRun(qcloudCDN)})
182 return gulp.src(paths.tmp.imgFiles)
183 .pipe(cache('qcloudCache'))
184 .pipe(qcloudUpload({
185 appid: config.qcloud.appid,
186 secretId: config.qcloud.secretId,
187 secretKey: config.qcloud.secretKey,
188 bucket: config.qcloud.bucket,
189 region: config.qcloud.region,
190 prefix: config.qcloud.prefix,
191 overWrite: config.qcloud.overWrite,
192 headers: config.qcloud.headers
193 }));
194 }
195 cb();
196 }
197
198
199 var watchHandler = function (type, file) {
200 var extname = path.extname(file);
201 // SCSS 文件
202 if (extname === '.scss') {
203 if (type === 'removed') {
204 var tmp = file.replace('src/', 'dist/').replace(extname, '.wxss');
205 del([tmp]);
206 } else {
207 sassCompile();
208 }
209 }
210 // 图片文件
211 else if (extname === '.png' || extname === '.jpg' || extname === '.jpeg' || extname === '.svg' || extname === '.gif') {
212 if (type === 'removed') {
213 if (file.indexOf('assets') > -1) {
214 del([file.replace('src/', 'tmp/')]);
215 } else {
216 del([file.replace('src/', 'dist/')]);
217 }
218 } else {
219 imageMin();
220 // assetsImgMin();
221 // qcloudCDN();
222 wxmlImgRewrite();
223 }
224 }
225
226 // wxml
227 else if (extname === '.wxml') {
228 if (type === 'removed') {
229 var tmp = file.replace('src/', 'dist/')
230 del([tmp]);
231 } else {
232 copyWXML();
233 wxmlImgRewrite();
234 }
235 }
236
237 // 其余文件
238 else {
239 if (type === 'removed') {
240 var tmp = file.replace('src/', 'dist/');
241 del([tmp]);
242 } else {
243 // copyBasicFiles();
244 copyModifyFiles(); // 复制修改过的业务文件
245 // copyWXML();
246 wxmlImgRewrite();
247 }
248 }
249 };
250
251 //监听文件
252 function watch(cb) {
253 var watcher = gulp.watch([
254 paths.src.baseDir,
255 paths.tmp.imgDir
256 ], {
257 ignored: /[\/\\]\./
258 });
259 watcher
260 .on('change', function (file) {
261 log(gutil.colors.yellow(file) + ' is changed');
262 watchHandler('changed', file);
263 })
264 .on('add', function (file) {
265 log(gutil.colors.yellow(file) + ' is added');
266 watchHandler('add', file);
267 })
268 .on('unlink', function (file) {
269 log(gutil.colors.yellow(file) + ' is deleted');
270 watchHandler('removed', file);
271 });
272
273 cb();
274 }
275
276 //注册默认任务
277 gulp.task('default', gulp.series(
278 cleanTmp,
279 copyBasicFiles,
280 gulp.parallel(
281 sassCompile,
282 imageMin,
283 copyWXML
284 ),
285 wxmlImgRewrite,
286 // assetsImgMin,
287 // qcloudCDN,
288 watch
289 ));
290
291 //注册测试任务
292 gulp.task('test', gulp.series(
293 cleanTmp,
294 copyBasicFiles,
295 gulp.parallel(
296 sassCompile,
297 imageMin,
298 copyWXML
299 ),
300 wxmlImgRewrite,
301 // assetsImgMin,
302 // qcloudCDN
303 ));
304
305 // 删除任务
306 gulp.task('clean', gulp.parallel(
307 cleanTmp,
308 cleanDist
309 ));
This diff could not be displayed because it is too large.
1 {
2 "name": "mp-gulp-frame-work",
3 "version": "0.0.5",
4 "description": "A workflow for better weapp developing.",
5 "main": "index.js",
6 "scripts": {
7 "test": "gulp test",
8 "dev": "gulp"
9 },
10 "repository": {
11 "type": "git",
12 "url": "http://admin@www.simonfungc.com:10086/r/mp/mp-gulp-framework.git"
13 },
14 "keywords": [
15 "gulp",
16 "gulpjs",
17 "workflow",
18 "weapp",
19 "wexin",
20 "wechat",
21 "css",
22 "wxml",
23 "wxss"
24 ],
25 "author": "SimonFungc",
26 "license": "MIT",
27 "bugs": {
28 "url": "https://www.simonfungc.com/"
29 },
30 "homepage": "https://www.simonfungc.com/",
31 "devDependencies": {
32 "del": "^4.0.0",
33 "gulp": "^4.0.0",
34 "gulp-changed": "^4.0.2",
35 "gulp-cached": "^1.1.1",
36 "gulp-debug": "^4.0.0",
37 "gulp-if": "^2.0.2",
38 "gulp-imagemin": "^5.0.0",
39 "gulp-newer": "^1.3.0",
40 "gulp-postcss": "^8.0.0",
41 "gulp-qcloud-upload": "^2.2.0",
42 "gulp-rename": "^1.2.2",
43 "gulp-replace": "^1.0.0",
44 "gulp-sass": "^4.0.0",
45 "gulp-sftp": "^0.1.5",
46 "gulp-util": "^3.0.8",
47 "postcss-font-base64": "^1.0.4",
48 "postcss-lazysprite": "^2.0.0",
49 "postcss-px2rpx": "0.0.4",
50 "yargs": "^13.1.0"
51 }
52 }
1 {
2 "client": "./dist",
3 "svr": "./server",
4 "setting": {
5 "urlCheck": false,
6 "es6": true,
7 "postcss": true,
8 "minified": true,
9 "newFeature": true
10 },
11 "appid": "wxc57ed87f2569f701",
12 "projectname": "gulp-example",
13 "condition": {}
14 }
1 //app.js
2 let fetchApi = require('./http/fetch-api.js');
3 let api = require('./http/api');
4 let config = require('./config');
5 let router = require('./router/index');
6 let store = require('./utils/stroage');
7
8 require('./http/mock-data');
9
10 App({
11 get: fetchApi.fetch,
12 post: (params) => {
13 params.method = 'post';
14 return fetchApi.fetch(params);
15 },
16 api: api,
17 config: config,
18 router: router,
19 store: store,
20 onLaunch(options) {
21 let scene = options.scene;
22 // 根据场景值判断分享入口
23 // https://developers.weixin.qq.com/miniprogram/dev/reference/scene-list.html
24 // 小程序由分享进入
25 // if (scene == 1007 || scene == 1008 || scene == 1011 || scene == 1012 || scene == 1013) {
26 // this.globalData.share = true
27 // } else {
28 // this.globalData.share = false
29 // };
30 const MenuRect = wx.getMenuButtonBoundingClientRect();
31 const statusBarHeight = wx.getSystemInfoSync().statusBarHeight;
32 const height = (MenuRect.top - statusBarHeight) * 2 + MenuRect.height + MenuRect.top;
33 this.globalData.statusBarHeight = wx.getSystemInfoSync().statusBarHeight;
34 this.globalData.barHeight = height;
35 this.share();
36 },
37 globalData: {
38 share: false,
39 indexInfo: null,
40 userInfo: null,
41 wxcode: store.getItem("wxcode"),
42 tlMemberCode: "",
43 },
44 //重写分享方法
45 share: function () {
46 //监听路由切换
47 //间接实现全局设置分享内容
48 wx.onAppRoute(function (res) {
49 //获取加载的页面
50 let pages = getCurrentPages();
51 //获取当前页面的对象
52 let view = pages[pages.length - 1];
53 let data;
54 if (view) {
55 data = view.data;
56 if (!data.isOverShare) {
57 data.isOverShare = true;
58 view.onShareAppMessage = function (res) {
59 //分享配置
60 return {
61 title: '模板标题',
62 path: 'pages/index/index',
63 // imageUrl: ''
64 };
65 };
66 }
67 }
68 })
69 },
70 })
1 {
2 "pages": [
3 "pages/index/index",
4 "pages/more/more",
5 "pages/poster-example/poster-example",
6 "pages/authorize/authorize",
7 "pages/demo/demo"
8 ],
9 "window": {
10 "backgroundTextStyle": "light",
11 "navigationBarBackgroundColor": "#fff",
12 "navigationBarTitleText": "mp-gulp-framework",
13 "navigationBarTextStyle": "black"
14 },
15 "tabBar": {
16 "color": "#7A7E83",
17 "selectedColor": "#CF4646",
18 "borderStyle": "black",
19 "backgroundColor": "#ffffff",
20 "list": [{
21 "pagePath": "pages/index/index",
22 "iconPath": "image/tabbar/home_D.png",
23 "selectedIconPath": "image/tabbar/home.png",
24 "text": "介绍"
25 },
26 {
27 "pagePath": "pages/more/more",
28 "iconPath": "image/tabbar/set_D.png",
29 "selectedIconPath": "image/tabbar/set.png",
30 "text": "更多"
31 }
32 ]
33 },
34 "usingComponents": {
35 "authorize-comp": "../../component/authorize-comp/authorize-comp",
36 "empty-tips": "../../component/empty-tips/empty-tips",
37 "van-popup": "../../ui/vant-weapp/popup/index"
38 }
39 }
1 /**
2 * ------------------------------------------------------------------
3 * app.scss 入口文件
4 *
5 * ------------------------------------------------------------------
6 *
7 */
8
9 // 支持文件
10 @import "assets/scss/support";
11
12 // 原子类
13 @import "assets/scss/utils";
14
15 // 图标
16 // @import 'styles/iconfont.wxss';
17
18 // 雪碧图
19 // @lazysprite "filetype";
20
21 // .test {
22 // background-image: url(%ASSETS_IMG%/qr-r.jpg);
23 // }
24
25 .app {
26 height: 100%;
27 justify-content: space-between;
28 // text-align: center;
29 box-sizing: border-box;
30 font-family: -apple-system-font, Helvetica Neue, Helvetica, sans-serif, FZY3JW-GB1-0;
31 }
32
33 .app__width {
34 width: 750px;
35 }
36
37 .app__width {
38 width: 750px;
39 }
40
41 .app__inner {
42 margin: 20px;
43 }
44
45 .app__title {
46 font-size: $fontSize;
47 line-height: $fontSize + 4px;
48 font-weight: bold;
49 padding-bottom: 10px;
50 margin-bottom: 20px;
51 border-bottom: .5px solid #EEEEEE;
52 }
53
54 .app__desc {
55 font-size: $fontSizeSmaller;
56 line-height: $fontSizeSmaller +2px;
57 margin-bottom: 20px;
58 color: $colorGray;
59 }
60
61 .app__bgc {
62 position: fixed;
63 background-color: #ffffff;
64 width: 100%;
65 height: 100%;
66 }
67
68 .app__bg {
69 position: absolute;
70 width: 100%;
71 height: 100%;
72 }
73
74 .app__top-shadow {
75 position: fixed;
76 width: 750px;
77 height: 1px;
78 box-shadow: 0px 4px 0.9px 0.1px rgba(6, 0, 1, 0.07);
79 background-color: #ffffff;
80 }
81
82 .app__content {
83 position: relative;
84 }
85
86
87 // web font icon
88
89 @font-face {
90 font-family: "iconfont";
91 src:url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAOsAAsAAAAAB6gAAANdAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDBgqDDIJmATYCJAMMCwgABCAFhG0HORuvBsgOJUHBwIABAAlgPHyN/f7c3UVEk0mi+3QSQxJNJCoexUrxUhhKIyT4UsKbL89+kizTNWb3wyt7UkR96ayA4xev1q04fZzIa32ey/Gt5wc26luWy5iT9qKFAcYBBbQ3RgEFWiAJesPYlRdxn0C9YccRqxl5ZcBCYSwLxJFS3gwsUk6lpj7UCtUle4t4Yqo2XaeXAHj0vx//QUhYkFRlxtq1w/Q2kPRz+iOmhipDoM51Gx7PD3aIjBlAITZLgxuoMDODUq8YTerLqxUhjRU3GgFfqeqrzT88kiCqGbWNYAJlEz+nbQmJP1h91rUZVMPcGeAZM51XhqohJw97O/vO23paqy3T6coNhsqQ1esr3nVWF19mTZ3YnOwtWwPk5bvMfvYCQV11V+xUzZx02tPO6H02TtP0y4dn5a7M9ravfPvs/poNl43TTmVrW87O66dcKzd3myo2Tjo5rW07l6+fcXXd3KmUDdBKXH240GtvAAw49qfa2BeatkTevUsumTJX5pzRRVy781FXe+YP15YALi0+kkDHQRm8OLz2sP/U1NGjIPxKdyVpafxHpKWvbajtddvnaxmZHLP0XGY1d2wvLarJWrd3LMD6Q1DiSPHusrPgvOxtlAKDyt7bk32nH3emP+npcwo2dKU/Vj040Jn2+HTvAU5VFtOf5vZDf683NVrpbEvIO7N3IX421A40MRbmdVIPQGXQhMi7/+o3vjanTBtt4/7Vygr4/p/GIHW7aqBWorXqz7QVQMVYCK4xXLnISlup57Ntpvcth3Ju8j8aod2b/tauu8+FWl0xkhpDyGqNEIWZQZUG86hWawH1pmUebtBBQolShynjAKHVFSTNPpG1ekUU5jWqdPuGaq1Bod56OJ7ZYCyUdKqEmjFqgy3dUNkqCozlwXRQX4Lk7VyzlNT4XAWSNMo4DA4IyuYzkYCkMTZoOuQhGDOQkUQeZoDHEMeJUC2JKtSKAxQYq2MCA5myFwW0ijygrZAgzTCkDdSiG6TUSiRg3MEYnft8CUSuHaeZVNNTka6ASDSUo0PBAgS1IDKNQquea3lGo4NcCAxjQAyJiAdlgFkIhyOC1OWzVJBWWABFj5RajECzH9PWGDC/mX++Q1DPGJsjRY6i5hgx1hSNwhTxatwNAAAAAA==') format('woff2'),
92 }
93
94 .iconfont {
95 font-family: "iconfont" !important;
96 font-size: 16px;
97 font-style: normal;
98 -webkit-font-smoothing: antialiased;
99 -moz-osx-font-smoothing: grayscale;
100 }
101
102 .iconrefresh:before {
103 content: "\e874";
104 }
105
106 .iconempty:before {
107 content: "\e6a6";
108 }
109
110 .drop-down-item :last-child {
111 border-bottom: none;
112 }
1 // 居中按钮样式
2 @mixin btn-center($width, $height) {
3 width: $width;
4 height: $height;
5 line-height: $height;
6 text-align: center;
7 }
8
9 // 超过多少行自动省略 默认一行
10 @mixin ellipsis($line:1) {
11 display: -webkit-box;
12 word-break: break-all;
13 -webkit-box-orient: vertical;
14 -webkit-line-clamp: $line;
15 overflow: hidden;
16 text-overflow: ellipsis;
17 }
18
19 // 文字截取
20 @mixin text-overflow() {
21 overflow: hidden;
22 white-space: normal;
23 text-overflow: ellipsis;
24 word-break: break-all;
25 word-wrap: normal;
26 }
27
28 @mixin word-break() {
29 word-break: break-all;
30 word-wrap: break-word;
31 white-space: normal;
32 }
33
34 // No wrap
35 @mixin no-wrap() {
36 word-break: normal;
37 word-wrap: normal;
38 white-space: nowrap;
39 }
40
41 // 清除浮动
42 @mixin clearfix() {
43
44 &:before,
45 &:after {
46 content: " "; // 1
47 display: table; // 2
48 }
49
50 &:after {
51 clear: both;
52 }
53 }
54
55 // Single side border-radius
56 @mixin border-top-radius($radius) {
57 border-top-right-radius: $radius;
58 border-top-left-radius: $radius;
59 }
60
61 @mixin border-right-radius($radius) {
62 border-bottom-right-radius: $radius;
63 border-top-right-radius: $radius;
64 }
65
66 @mixin border-bottom-radius($radius) {
67 border-bottom-right-radius: $radius;
68 border-bottom-left-radius: $radius;
69 }
70
71 @mixin border-left-radius($radius) {
72 border-bottom-left-radius: $radius;
73 border-top-left-radius: $radius;
74 }
75
76 // Center-align a block level element
77 @mixin center-block() {
78 display: block;
79 margin-left: auto;
80 margin-right: auto;
81 }
82
83 // CSS image replacement
84 // Source: https://github.com/h5bp/html5-boilerplate/commit/aa0396eae757
85 @mixin hide-text() {
86 font-size: 0;
87 line-height: 0;
88 color: transparent;
89 text-shadow: none;
90 background-color: transparent;
91 border: 0;
92 }
93
94
95 // 居中按钮样式
96 @mixin btc($width, $height) {
97 width: $width;
98 height: $height;
99 line-height: $height;
100 text-align: center;
101 }
102
103
104 // 通用按钮
105 @mixin cb($width:320px, $height:84px, $fontSize:32px) {
106 color: #FFFFFF;
107 position: relative;
108 width: $width;
109 height: $height;
110 line-height: $height;
111 text-align: center;
112 font-size: $fontSize;
113 border-radius: 8px;
114 background-color: #3680EB;
115 }
116
117 // 通用按钮
118 @mixin cb2($width:320px, $height:84px, $fontSize:32px) {
119 position: relative;
120 width: $width;
121 height: $height;
122 line-height: $height;
123 text-align: center;
124 font-size: $fontSize;
125 border-radius: 8px;
126 color: #3680EB;
127 border: solid 1PX #3680EB;
128 }
129
130
131 @mixin app-width() {
132 width: 750px;
133 }
1
2 @import "mixins";
3
4 @import "var";
1 @import "support";
2
3 // // Margin
4 // .u-mt-smaller {
5 // margin-top: $marginTopSmaller;
6 // }
7
8 // .u-mt-small {
9 // margin-top: $marginTopSmall;
10 // }
11
12 // .u-mt-medium {
13 // margin-top: $marginTopMedium;
14 // }
15
16 // .u-mt-large {
17 // margin-top: $marginTopLarge;
18 // }
19
20 // .u-mt-larger {
21 // margin-top: $marginTopLarger;
22 // }
23
24 // .u-mb-smaller {
25 // margin-bottom: $marginTopSmaller;
26 // }
27
28 // .u-mb-small {
29 // margin-bottom: $marginTopSmall;
30 // }
31
32 // .u-mb-medium {
33 // margin-bottom: $marginTopMedium;
34 // }
35
36 // .u-mb-large {
37 // margin-bottom: $marginTopLarge;
38 // }
39
40 // .u-mb-larger {
41 // margin-bottom: $marginTopLarger;
42 // }
43
44 // // Padding
45 // .u-pt-smaller {
46 // padding-top: $paddingTopSmaller;
47 // }
48
49 // .u-pt-small {
50 // padding-top: $paddingTopSmall;
51 // }
52
53 // .u-pt-medium {
54 // padding-top: $paddingTopMedium;
55 // }
56
57 // .u-pt-large {
58 // padding-top: $paddingTopLarge;
59 // }
60
61 // .u-pt-larger {
62 // padding-top: $paddingTopLarger;
63 // }
64
65 // .u-pb-smaller {
66 // padding-bottom: $paddingTopSmaller;
67 // }
68
69 // .u-pb-small {
70 // padding-bottom: $paddingTopSmall;
71 // }
72
73 // .u-pb-medium {
74 // padding-bottom: $paddingTopMedium;
75 // }
76
77 // .u-pb-large {
78 // padding-bottom: $paddingTopLarge;
79 // }
80
81 // .u-pb-larger {
82 // padding-bottom: $paddingTopLarger;
83 // }
84
85 // // 布局方位
86 // .u-ta-c {
87 // text-align: center !important;
88 // }
89
90 // .u-ta-l {
91 // text-align: left !important;
92 // }
93
94 // .u-ta-r {
95 // text-align: right !important;
96 // }
97
98 // .u-fl-l {
99 // float: left;
100 // }
101
102 // .u-fl-n {
103 // float: none;
104 // }
105
106 // .u-fl-r {
107 // float: right;
108 // }
109
110 // .u-d-b {
111 // display: block;
112 // }
113
114 // .u-d-i {
115 // display: inline !important;
116 // }
117
118 // .u-d-ib {
119 // display: inline-block !important;
120 // }
121
122 // .u-d-n {
123 // display: none !important;
124 // }
125
126 // .u-d-t {
127 // display: table;
128 // table-layout: fixed;
129 // }
130
131 // .u-d-tc {
132 // display: table-cell;
133 // }
134
135 // .u-va-b {
136 // vertical-align: bottom;
137 // }
138
139 // .u-va-m {
140 // vertical-align: middle;
141 // }
142
143 // .u-va-t {
144 // vertical-align: top;
145 // }
146
147 // // clearfix
148 // .u-clearfix {
149 // @include clearfix;
150 // }
151
152 // // 虚拟格式
153 // .u-cur-d {
154 // cursor: default;
155 // }
156
157 // .u-cur-p {
158 // cursor: pointer;
159 // }
160
161 // // flex
162 // .u-flex {
163 // display: -webkit-box;
164 // display: -webkit-flex;
165 // display: flex;
166 // }
167
168 // .u-flex-item {
169 // -webkit-box-flex: 1;
170 // -webkit-flex: 1;
171 // flex: 1;
172 // }
173
174 // // 小程序中模拟ul、li
175 // .u-ul {
176 // padding-left: 30px;
177 // text-align: left;
178 // display: block;
179 // }
180
181 // .u-li {
182 // position: relative;
183 // font-size: $fontSizeSmall;
184 // line-height: $fontSizeSmall + 4px;
185 // margin-bottom: $marginTopSmall;
186 // &:before {
187 // position: absolute;
188 // content: " ";
189 // top: 14px;
190 // left: -20px;
191 // width: 8px;
192 // height: 8px;
193 // border-radius: 8px;
194 // background-color: $colorBlack;
195 // }
196 // }
197
198
199
200 .bis {
201 background-repeat: no-repeat;
202 background-size: 100% 100%;
203 }
204
205
206 //flex 布局和 子元素 对其方式
207 .fl {
208 display: flex;
209 }
210
211 .fj {
212 display: flex;
213 justify-content: space-between;
214 }
215
216
217
218 .fje {
219 display: flex;
220 justify-content: flex-end;
221 }
222
223 //水平和垂直居中
224 .fcc {
225 display: flex;
226 justify-content: center;
227 align-items: center;
228 }
229
230 // 为元素设定的宽度和高度决定了元素的边框盒。
231 .bb {
232 box-sizing: border-box;
233 }
234
235 // 满屏
236 .fullp {
237 width: 100%;
238 height: 100%;
239 }
240
241 .shadow {
242 box-shadow: 0 6px 18px 0 rgba(0, 0, 0, 0.10);
243 border-radius: 8px;
244 }
245
246 .linear {
247 background-image: linear-gradient(to right, #1bade8, #3680EB);
248 }
1
2
3 // // Margin
4 // $marginTopSmaller: 20px;
5 // $marginTopSmall: 30px;
6 // $marginTopMedium: 40px;
7 // $marginTopLarge: 60px;
8 // $marginTopLarger: 80px;
9
10 // // Padding
11 // $paddingTopSmaller: 20px;
12 // $paddingTopSmall: 30px;
13 // $paddingTopMedium: 40px;
14 // $paddingTopLarge: 60px;
15 // $paddingTopLarger: 80px;
16
17 // // Color
18 $colorBlue: #20A0FF;
19 $colorGreen: #13CE66;
20 $colorGray: #475669;
21 $colorBlack: #000;
22 $colorRed: #FF4949;
23 $colorYellow: #F7BA2A;
24
25 $color: #787878;
26 // $colorLink: #1D8CE0;
27
28 // $backGroundColor: #fff;
29
30 // // Font
31 $fontSize: 32px;
32 $fontSizeSmall: 28px;
33 $fontSizeSmaller: 24px;
34 $fontSizeLarge: 36px;
35 $fontSizeLarger: 44px;
36
37
38 // // 主题颜色
39 $colorMain:#3680EB;
40
41 $pageBottom:80px;
1 let app = getApp();
2 Component({
3 properties: {
4 // 这里定义了innerText属性,属性值可以在组件使用时指定
5 innerText: {
6 type: String,
7 value: 'default value',
8 },
9 // 用户拒绝授权后是否后退页面
10 cancelBack: {
11 type: Boolean,
12 value: false,
13 },
14 // 用户拒绝授权后描述
15 cancelDesc: {
16 type: String,
17 value: "同意授权才能获得更多体验哦~",
18 }
19 },
20 data: {
21 // 这里是一些组件内部数据
22 someData: {}
23 },
24 methods: {
25 // 这里是一个自定义方法
26 customMethod() {
27 this.triggerEvent('evtcomp', {
28 name: "_evt_custom"
29 })
30 },
31 // 隐藏蒙层
32 hideMask() {
33 this.triggerEvent('evtcomp', {
34 name: "_evt_hide_mask"
35 });
36 },
37
38 // 授权成功事件
39 authComplete() {
40 this.triggerEvent('evtcomp', {
41 name: "_evt_auth_complete"
42 });
43
44
45 },
46
47 // 点击暂不授权按钮
48 cancelAuth(e) {
49 this.hideMask();
50 // this.triggerEvent('evtcomp', {
51 // name: "_evt_auth_cancel"
52 // });
53 // if (this.properties.cancelBack) {
54 // wx.navigateBack({
55 // delta: 1
56 // });
57 // }
58 },
59
60 // 点击确认授权按钮
61 bindGetUserInfo(e) {
62 wx.showLoading();
63 this.getUserInfo(e.detail);
64 },
65
66 // 授权操作
67 getUserInfo(e) {
68 let _this = this;
69 if (e.encryptedData && e.iv) {
70 // 同意授权
71 app.post({
72 url: app.api.register,
73 sid: false,
74 data: {
75 encryptedData: e.encryptedData,
76 iv: e.iv,
77 code: app.store.getItem("wxcode"),
78 tlMemberCode: app.globalData.tlMemberCode
79 }
80 }).then((res2) => {
81 wx.hideLoading();
82 if (res2 && res2.sessionId) {
83 app.store.setItem('sessionId', res2.sessionId);
84 }
85 _this.hideMask();
86 _this.authComplete();
87 _this.initPage();
88 }).catch((err) => {})
89 } else {
90 // 取消授权
91 if (_this.properties.cancelBack) {
92 wx.navigateBack({
93 delta: 1
94 });
95 } else {
96 if (_this.properties.cancelDesc) {
97 wx.showToast({
98 title: _this.properties.cancelDesc,
99 icon: "none"
100 })
101 }
102 }
103 }
104 },
105
106 /**
107 * 尝试重拉信息
108 */
109 initPage() {
110 let pages = getCurrentPages();
111 let view = pages[pages.length - 1];
112 console.log("@authorize-comp view:", view);
113 if (view) {
114 try {
115 view.hideMask();
116 console.log("@authorize-comp || hideMask");
117 } catch (error) {}
118 try {
119 view.initData();
120 console.log("@authorize-comp || initData");
121 } catch (error) {}
122 }
123 }
124 }
125 })
1 @import '../../assets/scss/mixins';
2 @import '../../assets/scss/utils';
3
4
5 .comp-item {
6 width: 650px;
7 min-height: 496px;
8 border-radius: 10px;
9 background-color: #ffffff;
10
11 .cspace {
12 height: 80px;
13 }
14
15 .cont {
16 text-align: center;
17 width: 520px;
18 margin: 0 auto;
19
20 .logo {
21 margin: 0 auto;
22 width: 200px;
23 height: 153px;
24
25 image {
26 width: 200px;
27 height: 153px;
28 }
29 }
30
31 .tit {
32 font-size: 40px;
33 color: #333333;
34 }
35
36 .tips {
37 margin-top: 28px;
38 font-size: 32px;
39 color: #333333;
40 padding-bottom: 244px;
41 }
42 }
43
44 .btn-wrap {
45 position: absolute;
46 left: 0;
47 right: 0;
48 bottom: 80px;
49 margin: 0 auto;
50 display: flex;
51 justify-content: center;
52 }
53
54 .btn {
55 @include cb(240px, 80px);
56 margin: 0 24px;
57 }
58
59
60 .btn2 {
61 @include cb2(240px, 80px);
62 }
63
64 }
1 <view class="comp-item">
2 <view class="cspace"></view>
3 <view class="cont">
4 <!-- <view class="logo">
5 <image mode="widthFix" src="../../image/logo.png" />
6 </view> -->
7 <view class="tit">深士照明</view>
8 <view class="tips">
9 <text>需要获取您的微信昵称等信息才可以获取积分和兑换奖品哦</text>
10 </view>
11 </view>
12 <view class="btn-wrap">
13 <button class="btn btn2" bindtap="cancelAuth">暂不授权</button>
14 <button class="btn" open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">确认授权</button>
15 </view>
16 </view>
1 Component({
2 properties: {
3 // 这里定义了innerText属性,属性值可以在组件使用时指定
4 innerText: {
5 type: String,
6 value: 'default value',
7 },
8 bottomVisible: {
9 type: Boolean,
10 value: false
11 }
12 },
13 data: {
14 // 这里是一些组件内部数据
15 someData: {}
16 },
17 methods: {
18 // 这里是一个自定义方法
19 customMethod() {}
20 }
21 })
1 // 底线
2 .bottom-tips {
3 position: relative;
4 padding: 40px 0;
5 width: 100%;
6 text-align: center;
7 color: #666666;
8
9 .line {
10 border-bottom: dashed 1px #cccccc;
11 width: 80%;
12 position: absolute;
13 top: 50%;
14 left: 0;
15 right: 0;
16 margin: 0 auto;
17 }
18
19 .tips-wrap {
20 position: relative;
21 font-size: 28px;
22
23 .tips {
24 padding: 0 20px;
25 background-color: #ffffff;
26 }
27 }
28 }
1 <view class="bottom-tips" wx:if="{{bottomVisible}}">
2 <view class="line"></view>
3 <view class="tips-wrap">
4 <text class="tips">我是有底线的</text>
5 </view>
6 </view>
1 let app = getApp();
2 Component({
3 // 样式隔离
4 // 详见 https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html
5 // isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值);
6 // apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;
7 // shared 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用。)
8 options: {
9 styleIsolation: 'isolated'
10 },
11 properties: {
12 // 这里定义了innerText属性,属性值可以在组件使用时指定
13 innerText: {
14 type: String,
15 value: 'default value',
16 }
17 },
18 data: {
19 // 这里是一些组件内部数据
20 someData: {}
21 },
22 methods: {
23 // 这里是一个自定义方法
24 customMethod() {
25 this.triggerEvent('evtcomp', {
26 name: "_evt_custom"
27 })
28 },
29 // 隐藏蒙层
30 hideMask() {
31 this.triggerEvent('evtcomp', {
32 name: "_evt_hide_product_detail_mask"
33 });
34 }
35 }
36 })
1 <view class="demo-item">demo-item</view>
1 Component({
2 options: {
3 styleIsolation: 'apply-shared' // 接受外部样式
4 },
5 properties: {
6 // 这里定义了innerText属性,属性值可以在组件使用时指定
7 innerText: {
8 type: String,
9 value: 'default value',
10 },
11 emptyVisible: {
12 type: Boolean,
13 value: false
14 }
15 },
16 data: {
17 // 这里是一些组件内部数据
18 someData: {}
19 },
20 methods: {
21 // 这里是一个自定义方法
22 customMethod() {}
23 }
24 })
1 //用的fixed 请确保 内容为空
2 .empty-tips {
3 position: fixed;
4 text-align: center;
5 color: #666666;
6 font-size: 32px;
7 width: 100%;
8 height: 100%;
9 display: flex;
10 justify-content: center;
11 top:35%;
12
13 .iconfont{
14 font-size: 100px;
15 }
16
17 .tips {
18 padding: 20px;
19 }
20 }
1 <view class="empty-tips" wx:if="{{emptyVisible}}">
2 <view class="tips">
3 <span class="iconfont iconempty"></span>
4 <view class="tips">这里空空如也~</view>
5 </view>
6 </view>
1 const app = getApp()
2 Component({
3 options: {
4 styleIsolation: 'apply-shared'
5 },
6 properties: {
7 navbarData: { //navbarData 由父页面传递的数据,变量名字自命名
8 type: Object,
9 value: {},
10 // observer: function (newVal, oldVal) {}
11 },
12 share: {
13 type: Boolean,
14 value: false
15 }
16 },
17 data: {
18 height: '',
19 barHeight: app.globalData.barHeight,
20 //默认值 默认显示左上角
21 // navbarData: {
22 // showCapsule: 1,
23 // }
24 },
25 attached: function () {
26 // 获取是否是通过分享进入的小程序
27 // this.setData({
28 // share: app.globalData.share
29 // })
30 // 定义导航栏的高度 方便对齐
31 this.setData({
32 statusBarHeight: app.globalData.statusBarHeight,
33 height: app.globalData.barHeight
34 })
35 },
36 methods: {
37 // 返回上一页面
38 _navback() {
39 wx.navigateBack()
40 },
41 //返回到首页
42 _backhome() {
43 app.router.push({
44 path: "index",
45 openType: "reLaunch"
46 })
47 // wx.navigateBack({
48 // delta: 999999
49 // })
50 }
51 },
52 ready() {
53 // console.log("navbarData.title}:", this.properties.navbarData.title);
54 }
55
56 })
1 {
2 "component": true
3 }
1 /* 顶部要固定定位 标题要居中 自定义按钮和标题要和右边微信原生的胶囊上下对齐 */
2 .nav-wrap {
3 position: fixed;
4 width: 100%;
5 top: 0;
6 background: #fff;
7 color: #000;
8 z-index: 999999;
9 }
10
11 /* 标题要居中 */
12 .nav-title {
13 position: absolute;
14 text-align: center;
15 max-width: 400px;
16 overflow: hidden;
17 text-overflow: ellipsis;
18 white-space: nowrap;
19 top: 0;
20 left: 0;
21 right: 0;
22 bottom: 0;
23 margin: auto;
24 font-size: 32px;
25 color: #2c2b2b;
26 font-weight: 600;
27 }
28
29 .nav-capsule {
30 display: flex;
31 align-items: center;
32 margin-left: 30px;
33 width: 120px;
34 justify-content: space-between;
35 height: 100%;
36 }
37
38 .navbar-v-line {
39 width: 1px;
40 height: 32px;
41 background-color: #e5e5e5;
42 }
43
44 .back-pre,
45 .back-home {
46 width: 32px;
47 height: 36px;
48 line-height: 36px;
49 margin-top: 4px;
50 padding: 10px;
51 }
52
53 .nav-capsule .back-home {
54 width: 36px;
55 height: 40px;
56 margin-top: 3px;
57 }
58
59 .iconfont {
60 font-size: 40px;
61 }
1 <view class='nav-wrap' style='height: {{height}}px;'>
2 <view class='nav-title' style='line-height: {{height+statusBarHeight}}px;'>{{navbarData.title}}</view>
3 <view style='display: flex; justify-content: space-around;flex-direction: column'>
4 <view class='nav-capsule' style='height: {{height+statusBarHeight}}px;' wx:if='{{navbarData.showCapsule}}'>
5 <view bindtap='_navback' wx:if='{{!share}}'>
6 <span class="iconfont iconbackicon1"></span>
7 </view>
8 <view class='navbar-v-line' wx:if='{{!share}}'></view>
9 <view bindtap='_backhome'>
10 <span class="iconfont iconhome"></span>
11 </view>
12 </view>
13 </view>
14 </view>
1 let ENV_CONFIG = require('./env/index');
2
3 const APPID = ''
4 /** ====每次发布版本记得修改此环境配置==== */
5 const ENV = 'dev'; // Dev Prod
6 const NET_CONFIG = ENV_CONFIG[ENV];
7 const MOCKAPI = ENV_CONFIG.mockApi;
8
9 module.exports = {
10 APPID,
11 ENV,
12 NET_CONFIG,
13 MOCKAPI
14 }
1 module.exports = {
2 mockApi: 'http://mock.simonfungc.com',
3 Dev: {
4 baseApi: 'https://ow.go.qudone.com/xxx',
5 commonApi: 'https://api.k.wxpai.cn/bizproxy'
6 },
7 Test: {
8 baseApi: 'https://test-api.xxx.com'
9 },
10 Slave: {
11 baseApi: 'https://slave-api.xxx.com'
12 },
13 Prod: {
14 baseApi: 'https://api.k.wxpai.cn/bizproxy/xxx',
15 commonApi: 'https://api.k.wxpai.cn/bizproxy'
16 }
17 }
1 # chmod u+x git.sh
2 unset msg
3
4 read -p "请输入commit提交的描述: " msg
5
6 if [[ $msg == "" ]]; then
7 msg="默认提交"
8 fi
9 git add -A
10 git commit -m $msg
11 git push
12 git status
1 module.exports = {
2 login: "/login", // post 通过wxcode换取sessionId
3 register: '/register', // post 注册(用户授权)
4
5 dataList: '/dataList', // 测试接口
6
7 /**
8 * 通用接口
9 * 请求时 "mode"传"custom"
10 */
11 areaQuery: 'https://api.k.wxpai.cn/bizproxy/kdapi/area', // post 区域查询
12 }
1 let config = require('./../config');
2 let Store = require('./../utils/stroage');
3 let Router = require('./../router/index');
4 const errMsg = '服务异常,请稍后重试';
5
6 // let isWxLogin = false;
7
8 function wxLogin() {
9 return new Promise((resolve, reject) => {
10 wx.login({
11 success: function (res) {
12 // isWxLogin = true;
13 Store.setItem('wxcode', res.code);
14 resolve();
15 }
16 });
17 });
18 }
19
20
21 // 检查并获取sessionid
22 function checkSessionId(sid) {
23 return new Promise((resolve, reject) => {
24 if (!sid) {
25 resolve();
26 return;
27 }
28 let sessionId = Store.getItem('sessionId');
29 if (sessionId) {
30 resolve();
31 } else {
32 // 没有sessionId则获取并埋值
33 login().then((result) => {
34 resolve();
35 }).catch((err) => {
36 reject();
37 });
38 }
39 });
40 }
41
42 // session丢失
43 function login() {
44 return new Promise((resolve, reject) => {
45 wxLogin().then((result) => {
46 let baseUrl = config.NET_CONFIG.baseApi;
47 wx.request({
48 url: baseUrl + '/login',
49 sid: false,
50 data: {
51 code: Store.getItem('wxcode')
52 },
53 method: 'POST',
54 success: function (res2) {
55 let {
56 code,
57 content
58 } = res2.data;
59 if (code == 200 && content.sessionId) {
60 Store.setItem('sessionId', content.sessionId);
61 resolve();
62 } else {
63 wx.hideLoading();
64 let pages = getCurrentPages();
65 let view = pages[pages.length - 1];
66 if (view) {
67 try {
68 wx.login({
69 success: function (res) {
70 Store.setItem('wxcode', res.code);
71 view.showAuth();
72 }
73 });
74 } catch (error) {}
75 }
76 reject();
77 }
78 }
79 })
80 })
81
82 });
83 }
84
85 const fetch = function ({
86 loading = true,
87 toast = true,
88 sid = true,
89 auth = true,
90 mode,
91 isMock,
92 url,
93 data,
94 method
95 }) {
96 if (loading && mode != 'log') wx.showLoading();
97 // 新建promise对象
98 let promise = new Promise((resolve, reject) => {
99 /**
100 * isMock设置单个接口Mock开启
101 * mode:目前针对不同业务的接口进行处理,log标识本地埋点上传
102 */
103 let baseUrl = config.NET_CONFIG.baseApi;
104 if (isMock && mode != 'log') {
105 baseUrl = config.MOCKAPI; //环境配置
106 }
107 // 使用通用接口前缀
108 if (mode == "common") {
109 baseUrl = config.NET_CONFIG.commonApi
110 }
111 // 自定义前缀,即不使用前缀
112 if (mode == "custom") {
113 baseUrl = ""
114 }
115 checkSessionId(sid).then((result) => {
116 wx.request({
117 url: baseUrl + url, //请求地址
118 data: data, //自定义参数
119 method: method || 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
120 header: {
121 sessionId: Store.getItem("sessionId")
122 },
123 success: function (result) {
124 // 日志上传不需要处理结果
125 if (mode == 'log') return;
126 let res = result.data;
127 // 登陆失效拦截,根据项目需要添加自己的配置
128 if (res.code == 404) {
129 //登陆失效的回调
130 Store.clear("sessionId");
131 // wx.reLaunch({
132 // url: '/pages/index/index'
133 // })
134 // 404后拉取登陆后再做一次
135 login().then((resultLogin) => {
136 wx.request({
137 url: baseUrl + url, //请求地址
138 data: data, //自定义参数
139 method: method || 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
140 header: {
141 sessionId: Store.getItem("sessionId")
142 },
143 success: function (result) {
144 // 日志上传不需要处理结果
145 if (mode == 'log') return;
146 let res = result.data;
147 if (res.code === 200) {
148 if (loading) {
149 wx.hideLoading();
150 }
151 resolve(res.content);
152 } else {
153 // 有些特殊状况不需要toast 需要弹窗
154 if (toast) {
155 wx.showToast({
156 title: res.errMsg || errMsg,
157 icon: 'none'
158 })
159 } else {
160 wx.hideLoading();
161 }
162 // 返回错误信息
163 reject(res);
164 }
165 }
166 });
167 })
168 return;
169 }
170 // 内部统一的成功code拦截码
171 if (res.code === 200) {
172 if (loading) {
173 wx.hideLoading();
174 }
175 resolve(res.content);
176 } else {
177 // 有些特殊状况不需要toast 需要弹窗
178 if (toast) {
179 wx.showToast({
180 title: res.errMsg || errMsg,
181 icon: 'none'
182 })
183 } else {
184 wx.hideLoading();
185 }
186 // 返回错误信息
187 reject(res);
188 }
189 },
190 fail: function (e = {
191 CODE: -1,
192 msg: errMsg,
193 errMsg
194 }) {
195 let msg = e.errMsg;
196 if (e.errMsg == 'request:fail timeout') {
197 msg = '服务请求超时,请稍后重试'
198 }
199 wx.showToast({
200 title: msg,
201 icon: 'none'
202 });
203 reject(e)
204 },
205 complete: function () {
206 // complete
207 }
208 })
209 })
210 });
211 return promise;
212 }
213
214 module.exports = {
215 fetch
216 }
1 // https://github.com/webx32/WxMock
2
3 let Mock = require('../utils/mockSdk.js');
4
5 let config = require('../config')
6 let env = config.MOCKAPI;
7
8 Mock.mock(env + '/eatClassifyService', {
9 data: {
10 resultCode: 0,
11 content: function () {
12 return Mock.Random.ip();
13 }
14 }
15 });
1 let app = getApp();
2
3 Page({
4 data: {
5 barHeight: app.globalData.barHeight,
6 navbarData: {
7 showCapsule: 0, //是否显示左上角图标 1表示显示 0表示不显示
8 title: '微信授权' //导航栏 中间的标题
9 },
10 loginData: null,
11 authorized: false,
12 canIUse: wx.canIUse('button.open-type.getUserInfo'),
13 parentMemberCode: "",
14 },
15 onLoad(options) {},
16 onReady() {
17 app.store.clear("sessionId");
18 let _this = this;
19 wx.login({
20 success: function (res) {
21 _this.data.loginData = res;
22 }
23 });
24 },
25 bindGetUserInfo(e) {
26 wx.showLoading();
27 this.getUserInfo(e.detail);
28 },
29 getUserInfo(e) {
30 let _this = this;
31 app.globalData.userInfo = e.userInfo;
32 // console.log("loginData:",_this.data.loginData);
33 app.post({
34 url: app.api.register,
35 sid: false,
36 data: {
37 encryptedData: e.encryptedData,
38 iv: e.iv,
39 code: _this.data.loginData.code,
40 parentMemberCode: _this.data.parentMemberCode,
41 }
42 }).then((res2) => {
43 app.store.setItem('sessionId', res2.sessionId);
44 _this.setData({
45 authorized: true
46 })
47 _this.toIndex();
48 }).catch((err) => {
49 console.log("@authorize || err:", err);
50 })
51 },
52 toIndex() {
53 console.log("@authorize || toIndex ");
54 setTimeout(() => {
55 app.router.push({
56 path: "index",
57 query: {},
58 openType: "redirect"
59 })
60 wx.hideLoading();
61 }, 2000);
62 }
63 })
1 {
2 "usingComponents": {
3 "navbar": "../../component/navbar/index"
4 },
5 "navigationStyle": "custom"
6 }
1 @import '../../assets/scss/mixins';
2
3 .page {
4 position: relative;
5 overflow: hidden;
6
7 .bgc {
8 // background-color: transparent;
9 // background-color: black;
10 background-color: #fafafc;
11 }
12
13
14 .main {
15
16 position: relative;
17
18 .top-space {
19 height: 60px;
20 }
21
22
23 .login {
24 position: relative;
25 width: 650px;
26 margin: 0 auto;
27 text-align: center;
28
29 &-logo {
30 width: 140px;
31 height: 140px;
32 }
33
34 &-name {
35 margin-top: 32px;
36 font-size: 32px;
37 color: #333333;
38 }
39
40 &-line {
41 margin-top: 70px;
42 width: 650px;
43 height: 2px;
44 background-color: #eaeaec;
45 }
46
47 &-title {
48 margin-top: 40px;
49 font-size: 32px;
50 text-align: left;
51 color: #333333;
52 }
53
54
55 &-tips {
56 margin-top: 28px;
57 font-size: 26px;
58 text-align: left;
59 color: #666666;
60 }
61
62 &-btn {
63 margin-top: 102px;
64 width: 650px;
65 height: 90px;
66 line-height: 90px;
67 border-radius: 8px;
68 background-color: #00c200;
69 font-size: 32px;
70 color: #ffffff;
71 }
72
73 }
74
75 }
76
77 }
1 <navbar navbar-data='{{navbarData}}'></navbar>
2 <view style='height: {{barHeight}}px'></view>
3 <view class="page-authorize page">
4 <view class="app__bgc bgc"></view>
5 <view class="app__bg bg"></view>
6 <!-- <view class="app__top-shadow"></view> -->
7 <view class="app__content main">
8 <view class="top-space"></view>
9 <view class="login">
10 <image class="login-logo" src="../../image/logo.png" mode="aspectFit" />
11 <view class="login-name">美赞臣</view>
12 <view class="login-line"></view>
13 <view class="login-title">完整体验小程序功能,需要您的微信授权哦</view>
14 <view class="login-tips">· 获取您的公开信息(昵称、头像等)</view>
15 <button type="default" class="login-btn" wx:if="{{!authorized}}" open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">
16 确认授权
17 </button>
18 </view>
19 </view>
20 </view>
1 let app = getApp();
2
3 Page({
4 data: {
5 barHeight: app.globalData.barHeight,
6 navbarData: {
7 showCapsule: 0, //是否显示左上角图标 1表示显示 0表示不显示
8 title: '微信授权' //导航栏 中间的标题
9 },
10 loginData: null,
11 authorized: false,
12 canIUse: wx.canIUse('button.open-type.getUserInfo'),
13 parentMemberCode: "",
14 },
15 onLoad(options) {},
16 onReady() {
17 app.store.clear("sessionId");
18 let _this = this;
19 wx.login({
20 success: function (res) {
21 _this.data.loginData = res;
22 }
23 });
24 },
25 bindGetUserInfo(e) {
26 wx.showLoading();
27 this.getUserInfo(e.detail);
28 },
29 getUserInfo(e) {
30 let _this = this;
31 app.globalData.userInfo = e.userInfo;
32 // console.log("loginData:",_this.data.loginData);
33 app.post({
34 url: app.api.register,
35 sid: false,
36 data: {
37 encryptedData: e.encryptedData,
38 iv: e.iv,
39 code: _this.data.loginData.code,
40 parentMemberCode: _this.data.parentMemberCode,
41 }
42 }).then((res2) => {
43 app.store.setItem('sessionId', res2.sessionId);
44 _this.setData({
45 authorized: true
46 })
47 _this.toIndex();
48 }).catch((err) => {
49 console.log("@authorize || err:", err);
50 })
51 },
52 toIndex() {
53 console.log("@authorize || toIndex ");
54 setTimeout(() => {
55 app.router.push({
56 path: "index",
57 query: {},
58 openType: "redirect"
59 })
60 wx.hideLoading();
61 }, 2000);
62 }
63 })
1 {
2 "navigationStyle": "custom"
3 }
1 @import '../../assets/scss/mixins';
2 @import '../../assets/scss/utils';
3
4 .page {
5 position: relative;
6 overflow: hidden;
7
8 .bgc {}
9
10 .bg {
11 @include app-width;
12
13 image {
14 @include app-width;
15 }
16 }
17
18 // 右下角图标背景内容补充
19 .br-wrap {
20 $brWidth: 168px;
21 $brHeight: 172px;
22 width: $brWidth;
23 height: $brHeight;
24 position: fixed;
25 bottom: 0;
26 right: 0;
27 background-color: transparent;
28
29 image {
30 width: $brWidth;
31 height: $brHeight;
32 }
33 }
34
35
36
37 .main {
38 position: relative;
39 min-height: 1206px;
40
41 .content {
42 position: relative;
43 }
44
45 .login-wrap {
46 padding-top: 886px;
47
48 .terms-wrap {
49 margin-top: 24px;
50 display: flex;
51 justify-content: center;
52 margin-bottom: 16px;
53 font-size: 28px;
54 color: #333333;
55
56 .terms {
57 text-align: center;
58 padding: 0 12px;
59
60 .t1 {
61 color: #4bc2ed;
62 display: inline-block;
63 }
64 }
65 }
66
67
68
69 .login-btn {
70 width: 340px;
71 height: 80px;
72 line-height: 80px;
73 border-radius: 40px;
74 border: solid 3px #4bc2ed;
75 margin: 0 auto;
76 font-size: 36px;
77 color: #4bc2ed;
78 text-align: center;
79 background-color: transparent;
80 }
81
82 .gray {
83 color: #8f8f8f;
84 border-color: #8f8f8f;
85 }
86 }
87 }
88
89 }
90
91 .space1 {
92 height: 116px;
93 }
94
95
96 .terms-cont {
97 width: 690px;
98 height: 1000px;
99 position: relative;
100 background-color: #fff;
101
102 .cont {
103 position: relative;
104 width: 690px;
105 height: 900px;
106 overflow: auto;
107 padding: 28px;
108 @extend .bb;
109 font-size: 24px;
110
111
112 .tit {
113 text-align: center;
114 font-size: 32px;
115 font-weight: bold;
116 }
117
118 .desc {}
119
120 .t1 {
121 color: #4bc2ed;
122 display: inline-block;
123 margin-top: 16px;
124 }
125 }
126
127 .btn {
128
129 position: absolute;
130 bottom: 0;
131 left: 0;
132 right: 0;
133 }
134 }
1 <view class="page-authorize page">
2 <view class="app__bgc bgc"></view>
3 <view class="app__bg bg"></view>
4 <!-- <view class="app__top-shadow"></view> -->
5 <view class="app__content main">
6 <view class="top-space"></view>
7 <view class="login">
8 <image class="login-logo" src="../../image/logo.png" mode="aspectFit" />
9 <view class="login-name">小程序</view>
10 <view class="login-line"></view>
11 <view class="login-title">完整体验小程序功能,需要您的微信授权哦</view>
12 <view class="login-tips">· 获取您的公开信息(昵称、头像等)</view>
13 <button type="default" class="login-btn" wx:if="{{!authorized}}" open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">
14 确认授权
15 </button>
16 </view>
17 </view>
18 </view>
1 import {
2 getBindtapData
3 } from '../../utils/util';
4
5 let app = getApp();
6 Page({
7 data: {
8 authorizeVisible: false,
9 total: 0,
10 page: 1,
11 size: 10,
12 productList: [], // 产品列表
13 indexInfo: {},
14 userInfo: {},
15 },
16 onShareAppMessage() {},
17 showAuth() {
18 this.setData({
19 authorizeVisible: true
20 })
21 },
22 onLoad(options) {},
23
24 /**
25 * 基础方法
26 * 授权完毕重拉数据用
27 */
28 initData() {
29
30 },
31 /**
32 * 到达底部
33 * 做加载更多操作
34 */
35 onReachBottom() {
36 if (this.data.dataList.length < this.data.total) {
37 this.setData({
38 page: this.data.page + 1
39 });
40 this.queryDataList();
41 }
42 },
43
44 // 重置页面列表 点击搜索条件时需要
45 resetPage() {
46 this.setData({
47 page: 1,
48 dataList: []
49 })
50 },
51
52 /**
53 * 请求DataList
54 */
55 queryDataList() {
56 return;
57 return new Promise((resolve, reject) => {
58 app.post({
59 sid: false,
60 url: app.api.dataList,
61 data: {
62 page: this.data.page,
63 size: this.data.size,
64 },
65 }).then((result) => {
66 let dataList = result.list;
67 dataList = this.data.dataList.concat(dataList);
68 this.setData({
69 dataList: dataList,
70 total: result.total
71 })
72 resolve();
73 })
74 });
75 },
76
77 /**
78 * 隐藏蒙层
79 */
80 hideMask() {
81 this.setData({
82 productDetailVisible: false,
83 authorizeVisible: false,
84 })
85 },
86 /**
87 * 子组件事件
88 * @param {*} evt
89 */
90 evtcomp(evt) {
91 let {
92 name,
93 data
94 } = evt.detail;
95 switch (name) {
96
97 // 隐藏蒙层
98 case "_evt_hide_mask":
99 this.hideMask();
100 break;
101
102 /**
103 * 重拉数据已在
104 */
105 case "_evt_auth_complete":
106 // this.initData();
107 this.hideMask();
108 break;
109
110 default:
111 break;
112 }
113 },
114 })
1 {
2 "navigationBarTitleText": ""
3 }
1 @import '../../assets/scss/mixins';
2 @import '../../assets/scss/utils';
3
4 .page {
5 .bgc {}
6
7 .bg {}
8
9 .main {
10 .top-space {
11 height: 0px;
12 }
13
14 .content {
15 position: relative;
16 }
17 }
18 }
1 <view class="page">
2 <view class="app__bgc bgc"></view>
3 <view class="app__bg bg"></view>
4 <view class="app__content main">
5 <view class="top-space"></view>
6 <view class="content"></view>
7 </view>
8 </view>
1 let app = getApp();
2 Page({
3 data: {},
4 onLoad(options) {
5 }
6 })
1 {
2 "navigationBarTitleText": "首页"
3 }
1 @import '../../assets/scss/mixins';
2 @import '../../assets/scss/utils';
3
4 .page {
5 .bgc {}
6
7 .bg {}
8
9 .main {
10 .top-space {
11 height: 0px;
12 }
13
14 .content {
15 position: relative;
16 }
17 }
18 }
1 <view class="page">
2 <view class="app__bgc bgc"></view>
3 <view class="app__bg bg"></view>
4 <!-- <view class="app__top-shadow"></view> -->
5 <view class="app__content main">
6 <view class="top-space"></view>
7 <view class="content">index</view>
8 </view>
9 </view>
1 let app = getApp();
2 Page({
3 data: {},
4 onLoad(options) {}
5 })
1 {
2 "navigationBarTitleText": "demo"
3 }
1 @import '../../assets/scss/mixins';
2 @import '../../assets/scss/utils';
3
4 .page {
5 .bgc {}
6
7 .bg {}
8
9 .main {
10 .top-space {
11 height: 0px;
12 }
13
14 .content {
15 position: relative;
16 }
17 }
18 }
1 <view class="page">
2 <view class="app__bgc bgc"></view>
3 <view class="app__bg bg"></view>
4 <!-- <view class="app__top-shadow"></view> -->
5 <view class="app__content main">
6 <view class="top-space"></view>
7 <view class="content"></view>
8 </view>
9 </view>
1 import {
2 getBindtapData
3 } from '../../utils/util';
4 // 二维码
5 import QR from '../../utils/qrcode'
6 // 海报
7 import Poster from '../../plugin/poster/poster/poster';
8
9 let app = getApp();
10 Page({
11 data: {
12 authorizeVisible: false,
13 },
14 onShareAppMessage() {},
15 showAuth() {
16 this.setData({
17 authorizeVisible: true
18 })
19 },
20 onLoad(options) {},
21 initData() {
22 this.initPoster();
23 this.initQrcode();
24 },
25
26 // 创建海报
27 initPoster() {
28 // 获取海报数据
29 let posterData = this.getPosterConfig();
30 // 绘制设置海报
31 this.onCreatePoster(posterData);
32 },
33
34 // 创建二维码
35 initQrcode() {
36 createQrCode('wxapp-qrcode', 'qrcode', 300, 300)
37 },
38
39 // ---- START 海报合成 ----
40 // 详情见: https://github.com/jasondu/wxa-plugin-canvas
41
42 // 海报合成成功
43 onPosterSuccess(e) {
44 wx.hideLoading();
45 const {
46 detail
47 } = e;
48 this.setData({
49 imageUrl: detail
50 })
51 },
52
53 // 合成失败
54 onPosterFail(err) {
55 wx.hideLoading();
56 console.error(err);
57 },
58
59 // 异步生成海报
60 onCreatePoster(posterConfig) {
61 this.setData({
62 posterConfig: posterConfig
63 }, () => {
64 Poster.create(true); // 入参:true为抹掉重新生成
65 });
66 },
67
68 // 获取海报数据
69 getPosterConfig() {
70 let blocks = [{
71 x: 0,
72 y: 0,
73 width: 690,
74 height: 900,
75 backgroundColor: "#ffffff",
76 borderRadius: 10,
77 }];
78 let images = [];
79 let lines = [];
80 let texts = [{
81 x: 690 / 2,
82 y: 192,
83 width: 690,
84 fontSize: 36,
85 color: "#3680EB",
86 textAlign: "center",
87 zIndex: 11,
88 text: "nickname",
89 }];
90
91 let posterData = {
92 width: 690,
93 height: 900,
94 debug: false,
95 blocks: blocks,
96 images: images,
97 lines: lines,
98 texts: texts,
99 }
100 return posterData;
101 },
102
103 // ---- END 海报合成 ----
104
105
106
107 /**
108 ---------------- 分界线 ----------------
109 */
110
111
112
113 // ---- START 二维码生成 ----
114 // 详情见: https://github.com/demi520/wxapp-qrcode
115
116 // 创建二维码
117 createQrCode(content, canvasId, cavW, cavH) {
118 //调用插件中的draw方法,绘制二维码图片
119 QR.api.draw(content, canvasId, cavW, cavH);
120 this.canvasToTempImage(canvasId);
121 },
122 //获取临时缓存图片路径,存入data中
123 canvasToTempImage(canvasId) {
124 let that = this;
125 wx.canvasToTempFilePath({
126 canvasId, // 这里canvasId即之前创建的canvas-id
127 success: function (res) {
128 let tempFilePath = res.tempFilePath;
129 console.log(tempFilePath);
130 that.setData({ // 如果采用mpvue,即 this.imagePath = tempFilePath
131 qrImagePath: tempFilePath,
132 });
133 },
134 fail: function (res) {
135 console.log(res);
136 }
137 });
138 },
139 //适配不同屏幕大小的canvas
140 setCanvasSize(sz) {
141 var size = {};
142 try {
143 var res = wx.getSystemInfoSync();
144 var scale = 750 / sz; //不同屏幕下canvas的适配比例;设计稿是750宽
145 var width = res.windowWidth / scale;
146 var height = width; //canvas画布为正方形
147 size.w = width;
148 size.h = height;
149 } catch (e) {
150 // Do something when catch error
151 console.log("获取设备信息失败" + e);
152 }
153 return size;
154 },
155 // ---- END 二维码生成 ----
156
157
158 })
1 {
2 "navigationBarTitleText": "海报合成/二维码示例",
3 "usingComponents": {
4 "poster": "/plugin/poster/poster/index"
5 }
6 }
1 @import '../../assets/scss/mixins';
2 @import '../../assets/scss/utils';
3
4 .page {
5 .bgc {}
6
7 .bg {}
8
9 .main {
10 .top-space {
11 height: 0px;
12 }
13
14 .content {
15 position: relative;
16 }
17 }
18 }
1 <poster id="poster" hide-loading="{{true}}" preload="{{false}}" config="{{posterConfig}}" bind:success="onPosterSuccess" bind:fail="onPosterFail"></poster>
2 <canvas canvas-id="qrcode" style="width: 200rpx;height: 200rpx;background:#0f0f0f;" />
3 <view class="page">
4 <view class="app__bgc bgc"></view>
5 <view class="app__bg bg"></view>
6 <view class="app__content main">
7 <view class="top-space"></view>
8 <view class="content">poster</view>
9 </view>
10 </view>
1 let app = getApp();
2 Page({
3 data: {
4 isShow: false, // 控制组件显示隐藏
5 url: ''
6 },
7 onLoad: function (options = {}) {
8 let url = options.url;
9 if (url) {
10 this.setData({
11 url: url,
12 isShow: true
13 })
14 } else {
15 wx.showToast({
16 title: '未找到页面地址',
17 title: 'none',
18 });
19 }
20 }
21 })
1 {
2 "navigationBarTitleText": "webview"
3 }
1 <view class="loading-wrap">
2 <view class="loading">
3 <view class="icon"></view>
4 <view class="text">加载中...</view>
5 </view>
6 </view>
7 <web-view wx:if="{{isShow}}" src="{{url}}" bindload="loadSucc"/>
1 {
2 "component": true
3 }
...\ No newline at end of file ...\ No newline at end of file
1 <!--index.wxml-->
2 <view class="container">
3 <canvas canvas-id='canvasid' class="canvas {{debug ? 'debug' : 'pro'}}" style='width: {{pxWidth}}px; height: {{pxHeight}}px;'></canvas>
4 </view>
1 .canvas {
2 width: 750rpx;
3 height: 750rpx;
4 }
5 .canvas.pro {
6 position: absolute;
7 bottom: 0;
8 left: 0;
9 transform: translate3d(-9999rpx, 0, 0);
10 }
11 .canvas.debug {
12 position: absolute;
13 bottom: 0;
14 left: 0;
15 border: 1rpx solid #ccc;
16 }
...\ No newline at end of file ...\ No newline at end of file
1 Component({
2 properties: {
3 config: {
4 type: Object,
5 value: {},
6 },
7 preload: { // 是否预下载图片资源
8 type: Boolean,
9 value: false,
10 },
11 hideLoading: { // 是否隐藏loading
12 type: Boolean,
13 value: false,
14 }
15 },
16 ready() {
17 if (this.data.preload) {
18 const poster = this.selectComponent('#poster');
19 this.downloadStatus = 'doing';
20 poster.downloadResource(this.data.config.images).then(() => {
21 this.downloadStatus = 'success';
22 this.trigger('downloadSuccess');
23 }).catch((e) => {
24 this.downloadStatus = 'fail';
25 this.trigger('downloadFail', e);
26 });
27 }
28 },
29 methods: {
30 trigger(event, data) {
31 if (this.listener && typeof this.listener[event] === 'function') {
32 this.listener[event](data);
33 }
34 },
35 once(event, fun) {
36 if (typeof this.listener === 'undefined') {
37 this.listener = {};
38 }
39 this.listener[event] = fun;
40 },
41 downloadResource(reset) {
42 return new Promise((resolve, reject) => {
43 if (reset) {
44 this.downloadStatus = null;
45 }
46 const poster = this.selectComponent('#poster');
47 if (this.downloadStatus && this.downloadStatus !== 'fail') {
48 if (this.downloadStatus === 'success') {
49 resolve();
50 } else {
51 this.once('downloadSuccess', () => resolve());
52 this.once('downloadFail', (e) => reject(e));
53 }
54 } else {
55 poster.downloadResource(this.data.config.images)
56 .then(() => {
57 this.downloadStatus = 'success';
58 resolve();
59 })
60 .catch((e) => reject(e));
61 }
62 })
63 },
64 onCreate(reset = false) {
65 !this.data.hideLoading && wx.showLoading({ mask: true, title: '生成中' });
66 return this.downloadResource(typeof reset === 'boolean' && reset).then(() => {
67 !this.data.hideLoading && wx.hideLoading();
68 const poster = this.selectComponent('#poster');
69 poster.create(this.data.config);
70 })
71 .catch((err) => {
72 !this.data.hideLoading && wx.hideLoading();
73 wx.showToast({ icon: 'none', title: err.errMsg || '生成失败' });
74 console.error(err);
75 this.triggerEvent('fail', err);
76 })
77 },
78 onCreateSuccess(e) {
79 const { detail } = e;
80 this.triggerEvent('success', detail);
81 },
82 onCreateFail(err) {
83 console.error(err);
84 this.triggerEvent('fail', err);
85 }
86 }
87 })
...\ No newline at end of file ...\ No newline at end of file
1 {
2 "component": true,
3 "usingComponents": {
4 "we-canvas": "../index/index"
5 }
6 }
...\ No newline at end of file ...\ No newline at end of file
1 <view bindtap='onCreate'>
2 <slot/>
3 </view>
4 <we-canvas id="poster" bind:success="onCreateSuccess" bind:fail="onCreateFail"/>
...\ No newline at end of file ...\ No newline at end of file
1 const defaultOptions = {
2 selector: '#poster'
3 };
4
5 function Poster(options = {}) {
6 options = {
7 ...defaultOptions,
8 ...options,
9 };
10
11 const pages = getCurrentPages();
12 const ctx = pages[pages.length - 1];
13
14 const poster = ctx.selectComponent(options.selector);
15 delete options.selector;
16
17 return poster;
18 };
19
20 Poster.create = (reset = false) => {
21 const poster = Poster();
22 if (!poster) {
23 console.error('请设置组件的id="poster"!!!');
24 } else {
25 return Poster().onCreate(reset);
26 }
27 }
28
29 export default Poster;
...\ No newline at end of file ...\ No newline at end of file
1 const routerPath = {
2 index: '/pages/index/index',
3 authorize: '/pages/authorize/authorize', // 授权
4 example: '/pages/example/example',
5 more: '/pages/more/more',
6 }
7
8 function parse(data) {
9 let tempArr = [];
10 for (let key in data) {
11 tempArr.push(key + '=' + encodeURIComponent(data[key]));
12 }
13 return tempArr.join('&');
14 }
15
16 function push(path, option = {}) {
17 if (typeof path == 'string') {
18 option.path = path; //兼容无参数路径
19 } else {
20 option = path;
21 }
22 // console.log("option:", option);
23 // 配置key值找到对应path
24 let url = routerPath[option.path] || routerPath['index'];
25 // console.log("url:", url);
26 // 读取传入的配置参数
27 let {
28 query = {}, openType = 'navigate', duration = 0
29 } = option;
30 // json 转换为 字符串拼接参数
31 let params = parse(query)
32 // console.log("params:", params);
33 if (params) {
34 url = url + '?' + params;
35 }
36 // 是否需要延时跳转
37 duration ? setTimeout(() => {
38 to(openType, url);
39 }, duration) : to(openType, url);
40 }
41
42 function to(openType, url) {
43 let obj = {
44 url
45 };
46
47 if (openType == 'redirect') {
48 wx.redirectTo(obj);
49 } else if (openType == 'reLaunch') {
50 wx.reLaunch(obj);
51 } else if (openType == 'switchTab') {
52 wx.switchTab(obj);
53 } else if (openType == 'back') {
54 wx.navigateBack({
55 delta: 1
56 });
57 } else {
58 wx.navigateTo(obj);
59 }
60 }
61
62 module.exports = {
63 parse,
64 push,
65 to
66 }
1 import { VantComponent } from '../common/component';
2 import { safeArea } from '../mixins/safe-area';
3 VantComponent({
4 mixins: [safeArea()],
5 props: {
6 show: Boolean,
7 title: String,
8 cancelText: String,
9 zIndex: {
10 type: Number,
11 value: 100
12 },
13 actions: {
14 type: Array,
15 value: []
16 },
17 overlay: {
18 type: Boolean,
19 value: true
20 },
21 closeOnClickOverlay: {
22 type: Boolean,
23 value: true
24 }
25 },
26 methods: {
27 onSelect(event) {
28 const { index } = event.currentTarget.dataset;
29 const item = this.data.actions[index];
30 if (item && !item.disabled && !item.loading) {
31 this.$emit('select', item);
32 }
33 },
34 onCancel() {
35 this.$emit('cancel');
36 },
37 onClose() {
38 this.$emit('close');
39 }
40 }
41 });
1 {
2 "component": true,
3 "usingComponents": {
4 "van-icon": "../icon/index",
5 "van-popup": "../popup/index",
6 "van-loading": "../loading/index"
7 }
8 }
1 <wxs src="../wxs/utils.wxs" module="utils" />
2
3 <van-popup
4 show="{{ show }}"
5 position="bottom"
6 z-index="{{ zIndex }}"
7 overlay="{{ overlay }}"
8 custom-class="van-action-sheet"
9 safe-area-inset-bottom="{{ safeAreaInsetBottom }}"
10 close-on-click-overlay="{{ closeOnClickOverlay }}"
11 bind:close="onClose"
12 >
13 <view wx:if="{{ title }}" class="van-hairline--bottom van-action-sheet__header">
14 {{ title }}
15 <van-icon
16 name="close"
17 custom-class="van-action-sheet__close"
18 bind:click="onClose"
19 />
20 </view>
21 <view wx:if="{{ actions && actions.length }}">
22 <!-- button外包一层view,防止actions动态变化,导致渲染时button被打散 -->
23 <button
24 wx:for="{{ actions }}"
25 wx:key="index"
26 open-type="{{ item.openType }}"
27 class="{{ utils.bem('action-sheet__item', { disabled: item.disabled || item.loading }) }} van-hairline--top {{ item.className || '' }}"
28 hover-class="van-action-sheet__item--hover"
29 data-index="{{ index }}"
30 bind:tap="onSelect"
31 >
32 <block wx:if="{{ !item.loading }}">
33 {{ item.name }}
34 <text wx:if="{{ item.subname }}" class="van-action-sheet__subname" >{{ item.subname }}</text>
35 </block>
36 <van-loading wx:else size="20px" />
37 </button>
38 </view>
39 <slot />
40 <view
41 wx:if="{{ cancelText }}"
42 class="van-action-sheet__cancel"
43 hover-class="van-action-sheet__cancel--hover"
44 hover-stay-time="70"
45 bind:tap="onCancel"
46 >
47 {{ cancelText }}
48 </view>
49 </van-popup>
1 @import '../common/index.wxss';.van-action-sheet{max-height:90%!important;color:#333}.van-action-sheet__cancel,.van-action-sheet__item{height:50px;font-size:16px;line-height:50px;text-align:center;background-color:#fff}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5}.van-action-sheet__cancel{height:60px}.van-action-sheet__cancel:before{display:block;height:10px;background-color:#f8f8f8;content:" "}.van-action-sheet__item--disabled{color:#c9c9c9}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:#fff}.van-action-sheet__subname{margin-left:5px;font-size:12px;color:#7d7e80}.van-action-sheet__header{font-size:16px;font-weight:500;line-height:44px;text-align:center}.van-action-sheet__close{position:absolute!important;top:0;right:0;padding:0 15px;font-size:18px!important;line-height:inherit!important;color:#999}
...\ No newline at end of file ...\ No newline at end of file
1 import { VantComponent } from '../common/component';
2 VantComponent({
3 classes: ['active-class', 'toolbar-class', 'column-class'],
4 props: {
5 title: String,
6 value: String,
7 loading: Boolean,
8 cancelButtonText: String,
9 confirmButtonText: String,
10 itemHeight: {
11 type: Number,
12 value: 44
13 },
14 visibleItemCount: {
15 type: Number,
16 value: 5
17 },
18 columnsNum: {
19 type: [String, Number],
20 value: 3
21 },
22 areaList: {
23 type: Object,
24 value: {}
25 }
26 },
27 data: {
28 columns: [{ values: [] }, { values: [] }, { values: [] }],
29 displayColumns: [{ values: [] }, { values: [] }, { values: [] }]
30 },
31 watch: {
32 value(value) {
33 this.code = value;
34 this.setValues();
35 },
36 areaList: 'setValues',
37 columnsNum(value) {
38 this.set({
39 displayColumns: this.data.columns.slice(0, +value)
40 });
41 }
42 },
43 methods: {
44 getPicker() {
45 if (this.picker == null) {
46 this.picker = this.selectComponent('.van-area__picker');
47 }
48 return this.picker;
49 },
50 onCancel(event) {
51 this.emit('cancel', event.detail);
52 },
53 onConfirm(event) {
54 this.emit('confirm', event.detail);
55 },
56 emit(type, detail) {
57 detail.values = detail.value;
58 delete detail.value;
59 this.$emit(type, detail);
60 },
61 onChange(event) {
62 const { index, picker, value } = event.detail;
63 this.code = value[index].code;
64 this.setValues().then(() => {
65 this.$emit('change', {
66 picker,
67 values: picker.getValues(),
68 index
69 });
70 });
71 },
72 getConfig(type) {
73 const { areaList } = this.data;
74 return (areaList && areaList[`${type}_list`]) || {};
75 },
76 getList(type, code) {
77 let result = [];
78 if (type !== 'province' && !code) {
79 return result;
80 }
81 const list = this.getConfig(type);
82 result = Object.keys(list).map(code => ({
83 code,
84 name: list[code]
85 }));
86 if (code) {
87 // oversea code
88 if (code[0] === '9' && type === 'city') {
89 code = '9';
90 }
91 result = result.filter(item => item.code.indexOf(code) === 0);
92 }
93 return result;
94 },
95 getIndex(type, code) {
96 let compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6;
97 const list = this.getList(type, code.slice(0, compareNum - 2));
98 // oversea code
99 if (code[0] === '9' && type === 'province') {
100 compareNum = 1;
101 }
102 code = code.slice(0, compareNum);
103 for (let i = 0; i < list.length; i++) {
104 if (list[i].code.slice(0, compareNum) === code) {
105 return i;
106 }
107 }
108 return 0;
109 },
110 setValues() {
111 const county = this.getConfig('county');
112 let code = this.code || Object.keys(county)[0] || '';
113 const province = this.getList('province');
114 const city = this.getList('city', code.slice(0, 2));
115 const picker = this.getPicker();
116 if (!picker) {
117 return;
118 }
119 const stack = [];
120 stack.push(picker.setColumnValues(0, province, false));
121 stack.push(picker.setColumnValues(1, city, false));
122 if (city.length && code.slice(2, 4) === '00') {
123 ;
124 [{ code }] = city;
125 }
126 stack.push(picker.setColumnValues(2, this.getList('county', code.slice(0, 4)), false));
127 return Promise.all(stack)
128 .catch(() => { })
129 .then(() => picker.setIndexes([
130 this.getIndex('province', code),
131 this.getIndex('city', code),
132 this.getIndex('county', code)
133 ]))
134 .catch(() => { });
135 },
136 getValues() {
137 const picker = this.getPicker();
138 return picker ? picker.getValues().filter(value => !!value) : [];
139 },
140 getDetail() {
141 const values = this.getValues();
142 const area = {
143 code: '',
144 country: '',
145 province: '',
146 city: '',
147 county: ''
148 };
149 if (!values.length) {
150 return area;
151 }
152 const names = values.map((item) => item.name);
153 area.code = values[values.length - 1].code;
154 if (area.code[0] === '9') {
155 area.country = names[1] || '';
156 area.province = names[2] || '';
157 }
158 else {
159 area.province = names[0] || '';
160 area.city = names[1] || '';
161 area.county = names[2] || '';
162 }
163 return area;
164 },
165 reset() {
166 this.code = '';
167 return this.setValues();
168 }
169 }
170 });
1 {
2 "component": true,
3 "usingComponents": {
4 "van-picker": "../picker/index"
5 }
6 }
1 <van-picker
2 class="van-area__picker"
3 active-class="active-class"
4 toolbar-class="toolbar-class"
5 column-class="column-class"
6 show-toolbar
7 value-key="name"
8 title="{{ title }}"
9 loading="{{ loading }}"
10 columns="{{ displayColumns }}"
11 item-height="{{ itemHeight }}"
12 visible-item-count="{{ visibleItemCount }}"
13 cancel-button-text="{{ cancelButtonText }}"
14 confirm-button-text="{{ confirmButtonText }}"
15 bind:change="onChange"
16 bind:confirm="onConfirm"
17 bind:cancel="onCancel"
18 />
1 @import '../common/index.wxss';
...\ No newline at end of file ...\ No newline at end of file
This diff could not be displayed because it is too large.