├── .babelrc ├── .editorconfig ├── .gitignore ├── .postcssrc.js ├── .vscode └── settings.json ├── README.md ├── build ├── build.js ├── check-versions.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js └── prod.env.js ├── index.html ├── package-lock.json ├── package.json ├── project.config.json ├── src ├── App.vue ├── action │ └── action.js ├── app.json ├── assets │ ├── global.scss │ └── iconfont.less ├── components │ ├── card.vue │ └── sep-line.vue ├── constants │ ├── commonType.js │ ├── errorCodeMap.js │ ├── hostConfig.js │ ├── pathConfig.js │ └── responseCode.js ├── main.js ├── middlewares │ └── index.js ├── network │ ├── cache │ │ └── cache.js │ └── request │ │ ├── HttpExtension.js │ │ └── HttpRequest.js ├── pages │ ├── addAddress │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── addressList │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── categoryList │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── citySearch │ │ ├── index.vue │ │ └── main.js │ ├── citys │ │ ├── index.vue │ │ └── main.js │ ├── commentList │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── couponList │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── dicedActivity │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── expiredCoupon │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── expiredRedPacket │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── feedback │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── home │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── index │ │ ├── index.vue │ │ └── main.js │ ├── me │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── orderDetail │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── orderList │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── pickProtocol │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── protocol │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── redPacket │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── remark │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── searchList │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── selectAddress │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── share │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ ├── shoppingCart │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json │ └── submitOrder │ │ ├── data.js │ │ ├── index.vue │ │ ├── main.js │ │ └── main.json ├── store │ ├── index.js │ ├── modules │ │ ├── shoppingCart.js │ │ └── submitOrder.js │ └── mutations-type.js └── utils │ ├── arrayExtension.js │ ├── bus.js │ ├── deepClone.js │ ├── deviceInfo.js │ ├── formatTime.js │ ├── index.js │ ├── mta_analysis.js │ ├── regex.js │ ├── stringExtension.js │ ├── style.js │ ├── toast.js │ └── wxapi.js └── static ├── .gitkeep └── images ├── icon_tabbar_home@3x.png ├── icon_tabbar_home_selected@3x.png ├── icon_tabbar_mine@3x.png ├── icon_tabbar_mine_selected@3x.png ├── icon_tabbar_order@3x.png └── icon_tabbar_order_selected@3x.png /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-runtime"], 12 | "env": { 13 | "test": { 14 | "presets": ["env", "stage-2"], 15 | "plugins": ["istanbul"] 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | *.suo 11 | *.ntvs* 12 | *.njsproj 13 | *.sln -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-mpvue-wxss": {} 6 | } 7 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mpvue-meituan 2 | > mpvue-meituan 是一款使用mpvue开发的实战小程序项目,完全仿制美团官方外卖点餐小程序开发而成,项目的框架结构完全按照企业开发架构搭建而成。结合了原生小程序的开发能力和Vue能力,使小程序开发起来更加便捷高效,项目使用了比较流行的Vuex框架来作为全局的状态数据管理,使数据交互更加的便捷,结合了sass的使用让写Css样式更加的得心应手。目前市面上有很多使用mpvue开发的示例Demo,但是那些示例Demo都过于简单,没有提供一套系统的框架结构,借鉴的意义不是很大。所以作者就开源了一个企业级框架开发的小程序供大家学习参考,总之是一个极力推荐学习的小程序实战项目。 3 | 4 | **掘金专栏文章详解:[mpvue-meituan](https://juejin.im/post/5bbb6198f265da0ac962ba00)** 5 | 6 | # 目录 7 | * [项目简介](#项目简介) 8 | * [主要功能](#主要功能) 9 | * [预览效果图](#预览效果图) 10 | * [安装调试](#安装调试) 11 | * [API数据来源](#API数据来源) 12 | * [技术要点](#技术要点) 13 | * [核心组件库](#核心组件库) 14 | * [开发中遇到的坑](#开发中遇到的坑) 15 | * [待完成功能](#待完成功能) 16 | * [待优化bug](#待优化bug) 17 | * [目录结构](#目录结构) 18 | * [总结](#总结) 19 | 20 | # 项目简介 21 | > mpvue-meituan 是一款使用mpvue开发的小程序,完全仿制美团官方外卖小程序。目前市面上大部分的小程序开发还是使用微信原生的开发能力,原生的开发能力约束太多,导致小程序开发成本变高。于是市面上衍生出不少小程序开发框架,其中最为流行的有下面三个框架:`wepy` `taro` `mpvue`。这三个框架出自不同的大厂,之前不太了解的小伙伴们可以自行查阅资料。本项目主要介绍如何使用vue来快速开发一款复杂的小程序项目。 22 | 23 | # 主要功能(20+页面) 24 | * 首页Tab 25 | * 首页商家列表 26 | * 选择收货地址列表 27 | * 选择城市 28 | * 商品搜索列表 29 | * 分类列表 30 | * 邀请好友领红包 31 | * 添加购物车页面 32 | * 食品档案 33 | * 订单Tab 34 | * 订单列表 35 | * 提交订单 36 | * 商品备注 37 | * 订单详情 38 | * 商品评论 39 | * 我的Tab 40 | * 我的页面 41 | * 美团红包页面 42 | * 无效红包页面 43 | * 代金券页面 44 | * 无效代金券列表 45 | * 收货地址列表 46 | * 新增收货地址 47 | * 帮助反馈 48 | * 协议说明 49 | * 待补充 50 | 51 | # 预览效果图 52 | ![mpvue](https://imgs-1257778377.cos.ap-shanghai.myqcloud.com/2019-09-07%2011.40.32.gif) 53 | 54 | # 安装调试 55 | 56 | ``` 57 | # install dependencies 58 | npm install 59 | 60 | # serve with hot reload at localhost:8080 61 | npm run dev 62 | 63 | # build for production with minification 64 | npm run build 65 | 66 | # build for production and view the bundle analyzer report 67 | npm run build --report 68 | ``` 69 | 70 | # API数据来源 71 | > mpvue-meituan 项目的数据来源目前均来自美团外卖小程序抓包数据,将抓包数据存储为本地JSON,然后工程访问本地JSON数据。由于美团外卖小程序属于美团正式线上产品,故不能直接访问其真实API,使用本地JSON一样能实现绝大部分需求,少数需要数据交互的需求自己mock数据即可。 72 | 73 | 74 | # 技术要点 75 | * 微信原生小程序开发能力 76 | * mpvue开发小程序能力 77 | * Vue开发能力 78 | * less,sass 等css编译器用法 79 | * 小程序开发基础框架结构搭建 80 | * 小程序网络层封装 81 | * Vuex全局状态管理框架的使用 82 | * 小程序,vue组件化开发技巧 83 | * 小程序中iconFont使用技巧 84 | * 使用canvas绘制小程序分享海报技巧 85 | * 待补充 86 | 87 | # 核心组件库 88 | * mpvue 89 | * vuex 90 | * lodash 91 | * mpvue-wxparse 92 | * minapp-api-promise 93 | * 待补充 94 | 95 | # 开发中遇到的坑 96 | > 待补充 97 | 98 | # 待完成功能 99 | - [ ] 选择城市列表 100 | - [ ] 分类筛选功能 101 | - [ ] 购物车页面完善优化 102 | - [ ] 发表评论功能 103 | - [ ] 提交订单页面完善优化 104 | - [ ] canvas绘制分享海报 105 | - [x] 网络层工具封装 106 | - [x] vuex状态管理使用 107 | - [x] 常用工具类封装 108 | - [x] 组件化使用 109 | - [x] sass环境的搭建及使用 110 | - [ ] 待补充 111 | 112 | # 目录结构 113 | 114 | ``` 115 | . 116 | ├── App.vue 117 | ├── action 118 | │   └── action.js 119 | ├── app.json 120 | ├── assets 121 | │   ├── global.scss 122 | │   └── iconfont.less 123 | ├── components 124 | │   ├── card.vue 125 | │   └── sep-line.vue 126 | ├── constants 127 | │   ├── commonType.js 128 | │   ├── errorCodeMap.js 129 | │   ├── hostConfig.js 130 | │   ├── pathConfig.js 131 | │   └── responseCode.js 132 | ├── main.js 133 | ├── middlewares 134 | │   └── index.js 135 | ├── network 136 | │   ├── cache 137 | │   │   └── cache.js 138 | │   └── request 139 | │   ├── HttpExtension.js 140 | │   └── HttpRequest.js 141 | ├── pages 142 | │   ├── addAddress 143 | │   │   ├── index.vue 144 | │   │   ├── main.js 145 | │   │   └── main.json 146 | │   ├── addressList 147 | │   │   ├── data.js 148 | │   │   ├── index.vue 149 | │   │   ├── main.js 150 | │   │   └── main.json 151 | │   ├── categoryList 152 | │   │   ├── data.js 153 | │   │   ├── index.vue 154 | │   │   ├── main.js 155 | │   │   └── main.json 156 | │   ├── citySearch 157 | │   │   ├── index.vue 158 | │   │   └── main.js 159 | │   ├── citys 160 | │   │   ├── index.vue 161 | │   │   └── main.js 162 | │   ├── commentList 163 | │   │   ├── index.vue 164 | │   │   ├── main.js 165 | │   │   └── main.json 166 | │   ├── couponList 167 | │   │   ├── data.js 168 | │   │   ├── index.vue 169 | │   │   ├── main.js 170 | │   │   └── main.json 171 | │   ├── dicedActivity 172 | │   │   ├── index.vue 173 | │   │   ├── main.js 174 | │   │   └── main.json 175 | │   ├── expiredCoupon 176 | │   │   ├── data.js 177 | │   │   ├── index.vue 178 | │   │   ├── main.js 179 | │   │   └── main.json 180 | │   ├── expiredRedPacket 181 | │   │   ├── data.js 182 | │   │   ├── index.vue 183 | │   │   ├── main.js 184 | │   │   └── main.json 185 | │   ├── feedback 186 | │   │   ├── index.vue 187 | │   │   ├── main.js 188 | │   │   └── main.json 189 | │   ├── home 190 | │   │   ├── data.js 191 | │   │   ├── index.vue 192 | │   │   ├── main.js 193 | │   │   └── main.json 194 | │   ├── index 195 | │   │   ├── index.vue 196 | │   │   └── main.js 197 | │   ├── me 198 | │   │   ├── index.vue 199 | │   │   ├── main.js 200 | │   │   └── main.json 201 | │   ├── orderDetail 202 | │   │   ├── index.vue 203 | │   │   ├── main.js 204 | │   │   └── main.json 205 | │   ├── orderList 206 | │   │   ├── data.js 207 | │   │   ├── index.vue 208 | │   │   └── main.js 209 | │   ├── pickProtocol 210 | │   │   ├── index.vue 211 | │   │   ├── main.js 212 | │   │   └── main.json 213 | │   ├── protocol 214 | │   │   ├── index.vue 215 | │   │   ├── main.js 216 | │   │   └── main.json 217 | │   ├── redPacket 218 | │   │   ├── data.js 219 | │   │   ├── index.vue 220 | │   │   ├── main.js 221 | │   │   └── main.json 222 | │   ├── remark 223 | │   │   ├── index.vue 224 | │   │   ├── main.js 225 | │   │   └── main.json 226 | │   ├── searchList 227 | │   │   ├── data.js 228 | │   │   ├── index.vue 229 | │   │   ├── main.js 230 | │   │   └── main.json 231 | │   ├── selectAddress 232 | │   │   ├── data.js 233 | │   │   ├── index.vue 234 | │   │   ├── main.js 235 | │   │   └── main.json 236 | │   ├── share 237 | │   │   ├── data.js 238 | │   │   ├── index.vue 239 | │   │   ├── main.js 240 | │   │   └── main.json 241 | │   ├── shoppingCart 242 | │   │   ├── data.js 243 | │   │   ├── index.vue 244 | │   │   ├── main.js 245 | │   │   └── main.json 246 | │   └── submitOrder 247 | │   ├── data.js 248 | │   ├── index.vue 249 | │   ├── main.js 250 | │   └── main.json 251 | ├── store 252 | │   ├── index.js 253 | │   ├── modules 254 | │   │   ├── shoppingCart.js 255 | │   │   └── submitOrder.js 256 | │   └── mutations-type.js 257 | └── utils 258 | ├── arrayExtension.js 259 | ├── bus.js 260 | ├── deepClone.js 261 | ├── deviceInfo.js 262 | ├── formatTime.js 263 | ├── index.js 264 | ├── mta_analysis.js 265 | ├── regex.js 266 | ├── stringExtension.js 267 | ├── style.js 268 | ├── toast.js 269 | └── wxapi.js 270 | 271 | 37 directories, 117 files 272 | ``` 273 | 274 | # 总结 275 | > mpvue-meituan 项目是作者大约使用了2周时间开源的一款小程序项目,项目中基本涵盖了企业开发中常用的技术要点,非常适合想学习小程序开发的小伙伴们参考学习。相信此项目能给小伙伴们带来不一样的收获。大家也可以加作者的mpvue小程序交流群交流学习(`QQ群号:694979037`)。 276 | > 277 | > 当然,如果老铁们认为作者的开源项目还不错,也请点个 **`star`** 支持一下 ❤️❤️❤️❤️ ,也衷心的欢迎小伙伴们提些宝贵的意见和建议。 278 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | process.env.NODE_ENV = 'production' 4 | 5 | var ora = require('ora') 6 | var rm = require('rimraf') 7 | var path = require('path') 8 | var chalk = require('chalk') 9 | var webpack = require('webpack') 10 | var config = require('../config') 11 | var webpackConfig = require('./webpack.prod.conf') 12 | 13 | var spinner = ora('building for production...') 14 | spinner.start() 15 | 16 | rm(path.join(config.build.assetsRoot, '*'), err => { 17 | if (err) throw err 18 | webpack(webpackConfig, function (err, stats) { 19 | spinner.stop() 20 | if (err) throw err 21 | process.stdout.write(stats.toString({ 22 | colors: true, 23 | modules: false, 24 | children: false, 25 | chunks: false, 26 | chunkModules: false 27 | }) + '\n\n') 28 | 29 | if (stats.hasErrors()) { 30 | console.log(chalk.red(' Build failed with errors.\n')) 31 | process.exit(1) 32 | } 33 | 34 | console.log(chalk.cyan(' Build complete.\n')) 35 | console.log(chalk.yellow( 36 | ' Tip: built files are meant to be served over an HTTP server.\n' + 37 | ' Opening index.html over file:// won\'t work.\n' 38 | )) 39 | }) 40 | }) 41 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | var chalk = require('chalk') 2 | var semver = require('semver') 3 | var packageConfig = require('../package.json') 4 | var shell = require('shelljs') 5 | function exec (cmd) { 6 | return require('child_process').execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | } 15 | ] 16 | 17 | if (shell.which('npm')) { 18 | versionRequirements.push({ 19 | name: 'npm', 20 | currentVersion: exec('npm --version'), 21 | versionRequirement: packageConfig.engines.npm 22 | }) 23 | } 24 | 25 | module.exports = function () { 26 | var warnings = [] 27 | for (var i = 0; i < versionRequirements.length; i++) { 28 | var mod = versionRequirements[i] 29 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 30 | warnings.push(mod.name + ': ' + 31 | chalk.red(mod.currentVersion) + ' should be ' + 32 | chalk.green(mod.versionRequirement) 33 | ) 34 | } 35 | } 36 | 37 | if (warnings.length) { 38 | console.log('') 39 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 40 | console.log() 41 | for (var i = 0; i < warnings.length; i++) { 42 | var warning = warnings[i] 43 | console.log(' ' + warning) 44 | } 45 | console.log() 46 | process.exit(1) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | 3 | var config = require('../config') 4 | if (!process.env.NODE_ENV) { 5 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 6 | } 7 | 8 | // var opn = require('opn') 9 | var path = require('path') 10 | var express = require('express') 11 | var webpack = require('webpack') 12 | var proxyMiddleware = require('http-proxy-middleware') 13 | var portfinder = require('portfinder') 14 | var webpackConfig = require('./webpack.dev.conf') 15 | 16 | // default port where dev server listens for incoming traffic 17 | var port = process.env.PORT || config.dev.port 18 | // automatically open browser, if not set will be false 19 | var autoOpenBrowser = !!config.dev.autoOpenBrowser 20 | // Define HTTP proxies to your custom API backend 21 | // https://github.com/chimurai/http-proxy-middleware 22 | var proxyTable = config.dev.proxyTable 23 | 24 | var app = express() 25 | var compiler = webpack(webpackConfig) 26 | 27 | // var devMiddleware = require('webpack-dev-middleware')(compiler, { 28 | // publicPath: webpackConfig.output.publicPath, 29 | // quiet: true 30 | // }) 31 | 32 | // var hotMiddleware = require('webpack-hot-middleware')(compiler, { 33 | // log: false, 34 | // heartbeat: 2000 35 | // }) 36 | // force page reload when html-webpack-plugin template changes 37 | // compiler.plugin('compilation', function (compilation) { 38 | // compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 39 | // hotMiddleware.publish({ action: 'reload' }) 40 | // cb() 41 | // }) 42 | // }) 43 | 44 | // proxy api requests 45 | Object.keys(proxyTable).forEach(function (context) { 46 | var options = proxyTable[context] 47 | if (typeof options === 'string') { 48 | options = { target: options } 49 | } 50 | app.use(proxyMiddleware(options.filter || context, options)) 51 | }) 52 | 53 | // handle fallback for HTML5 history API 54 | app.use(require('connect-history-api-fallback')()) 55 | 56 | // serve webpack bundle output 57 | // app.use(devMiddleware) 58 | 59 | // enable hot-reload and state-preserving 60 | // compilation error display 61 | // app.use(hotMiddleware) 62 | 63 | // serve pure static assets 64 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 65 | app.use(staticPath, express.static('./static')) 66 | 67 | // var uri = 'http://localhost:' + port 68 | 69 | var _resolve 70 | var readyPromise = new Promise(resolve => { 71 | _resolve = resolve 72 | }) 73 | 74 | // console.log('> Starting dev server...') 75 | // devMiddleware.waitUntilValid(() => { 76 | // console.log('> Listening at ' + uri + '\n') 77 | // // when env is testing, don't need open it 78 | // if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 79 | // opn(uri) 80 | // } 81 | // _resolve() 82 | // }) 83 | 84 | module.exports = new Promise((resolve, reject) => { 85 | portfinder.basePort = port 86 | portfinder.getPortPromise() 87 | .then(newPort => { 88 | if (port !== newPort) { 89 | console.log(`${port}端口被占用,开启新端口${newPort}`) 90 | } 91 | var server = app.listen(newPort, 'localhost') 92 | // for 小程序的文件保存机制 93 | require('webpack-dev-middleware-hard-disk')(compiler, { 94 | publicPath: webpackConfig.output.publicPath, 95 | quiet: true 96 | }) 97 | resolve({ 98 | ready: readyPromise, 99 | close: () => { 100 | server.close() 101 | } 102 | }) 103 | }).catch(error => { 104 | console.log('没有找到空闲端口,请打开任务管理器杀死进程端口再试', error) 105 | }) 106 | }) 107 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | 15 | var cssLoader = { 16 | loader: 'css-loader', 17 | options: { 18 | minimize: process.env.NODE_ENV === 'production', 19 | sourceMap: options.sourceMap 20 | } 21 | } 22 | 23 | var postcssLoader = { 24 | loader: 'postcss-loader', 25 | options: { 26 | sourceMap: true 27 | } 28 | } 29 | 30 | var px2rpxLoader = { 31 | loader: 'px2rpx-loader', 32 | options: { 33 | baseDpr: 1, 34 | rpxUnit: 0.5 35 | } 36 | } 37 | 38 | // generate loader string to be used with extract text plugin 39 | function generateLoaders (loader, loaderOptions) { 40 | var loaders = [cssLoader, px2rpxLoader, postcssLoader] 41 | if (loader) { 42 | loaders.push({ 43 | loader: loader + '-loader', 44 | options: Object.assign({}, loaderOptions, { 45 | sourceMap: options.sourceMap 46 | }) 47 | }) 48 | } 49 | 50 | // Extract CSS when that option is specified 51 | // (which is the case during production build) 52 | if (options.extract) { 53 | return ExtractTextPlugin.extract({ 54 | use: loaders, 55 | fallback: 'vue-style-loader' 56 | }) 57 | } else { 58 | return ['vue-style-loader'].concat(loaders) 59 | } 60 | } 61 | 62 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 63 | return { 64 | css: generateLoaders(), 65 | wxss: generateLoaders(), 66 | postcss: generateLoaders(), 67 | less: generateLoaders('less'), 68 | sass: generateLoaders('sass', { indentedSyntax: true }), 69 | scss: generateLoaders('sass').concat( 70 | { 71 | loader: 'sass-resources-loader', 72 | options: { 73 | resources: path.resolve(__dirname, '../src/assets/global.scss') 74 | } 75 | } 76 | ), 77 | stylus: generateLoaders('stylus'), 78 | styl: generateLoaders('stylus') 79 | } 80 | } 81 | 82 | // Generate loaders for standalone style files (outside of .vue) 83 | exports.styleLoaders = function (options) { 84 | var output = [] 85 | var loaders = exports.cssLoaders(options) 86 | for (var extension in loaders) { 87 | var loader = loaders[extension] 88 | output.push({ 89 | test: new RegExp('\\.' + extension + '$'), 90 | use: loader 91 | }) 92 | } 93 | return output 94 | } 95 | -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var config = require('../config') 3 | // var isProduction = process.env.NODE_ENV === 'production' 4 | // for mp 5 | var isProduction = true 6 | 7 | module.exports = { 8 | loaders: utils.cssLoaders({ 9 | sourceMap: isProduction 10 | ? config.build.productionSourceMap 11 | : config.dev.cssSourceMap, 12 | extract: isProduction 13 | }), 14 | transformToRequire: { 15 | video: 'src', 16 | source: 'src', 17 | img: 'src', 18 | image: 'xlink:href' 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var fs = require('fs') 3 | var utils = require('./utils') 4 | var config = require('../config') 5 | var vueLoaderConfig = require('./vue-loader.conf') 6 | var MpvuePlugin = require('webpack-mpvue-asset-plugin') 7 | var glob = require('glob') 8 | var CopyWebpackPlugin = require('copy-webpack-plugin') 9 | var relative = require('relative') 10 | 11 | function resolve (dir) { 12 | return path.join(__dirname, '..', dir) 13 | } 14 | 15 | function getEntry (rootSrc) { 16 | var map = {}; 17 | glob.sync(rootSrc + '/pages/**/main.js') 18 | .forEach(file => { 19 | var key = relative(rootSrc, file).replace('.js', ''); 20 | map[key] = file; 21 | }) 22 | return map; 23 | } 24 | 25 | const appEntry = { app: resolve('./src/main.js') } 26 | const pagesEntry = getEntry(resolve('./src'), 'pages/**/main.js') 27 | const entry = Object.assign({}, appEntry, pagesEntry) 28 | 29 | module.exports = { 30 | // 如果要自定义生成的 dist 目录里面的文件路径, 31 | // 可以将 entry 写成 {'toPath': 'fromPath'} 的形式, 32 | // toPath 为相对于 dist 的路径, 例:index/demo,则生成的文件地址为 dist/index/demo.js 33 | entry, 34 | target: require('mpvue-webpack-target'), 35 | output: { 36 | path: config.build.assetsRoot, 37 | filename: '[name].js', 38 | publicPath: process.env.NODE_ENV === 'production' 39 | ? config.build.assetsPublicPath 40 | : config.dev.assetsPublicPath 41 | }, 42 | resolve: { 43 | extensions: ['.js', '.vue', '.json'], 44 | alias: { 45 | 'vue': 'mpvue', 46 | '@': resolve('src') 47 | }, 48 | symlinks: false, 49 | aliasFields: ['mpvue', 'weapp', 'browser'], 50 | mainFields: ['browser', 'module', 'main'] 51 | }, 52 | module: { 53 | rules: [ 54 | { 55 | test: /\.vue$/, 56 | loader: 'mpvue-loader', 57 | options: vueLoaderConfig 58 | }, 59 | { 60 | test: /\.js$/, 61 | include: [resolve('src'), resolve('test')], 62 | use: [ 63 | 'babel-loader', 64 | { 65 | loader: 'mpvue-loader', 66 | options: { 67 | checkMPEntry: true 68 | } 69 | }, 70 | ] 71 | }, 72 | { 73 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 74 | loader: 'url-loader', 75 | options: { 76 | limit: 10000, 77 | name: utils.assetsPath('img/[name].[ext]') 78 | } 79 | }, 80 | { 81 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 82 | loader: 'url-loader', 83 | options: { 84 | limit: 10000, 85 | name: utils.assetsPath('media/[name].[ext]') 86 | } 87 | }, 88 | { 89 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 90 | loader: 'url-loader', 91 | options: { 92 | limit: 10000, 93 | name: utils.assetsPath('fonts/[name].[ext]') 94 | } 95 | } 96 | ] 97 | }, 98 | plugins: [ 99 | new MpvuePlugin(), 100 | new CopyWebpackPlugin([{ 101 | from: '**/*.json', 102 | to: '' 103 | }], { 104 | context: 'src/' 105 | }), 106 | new CopyWebpackPlugin([ 107 | { 108 | from: path.resolve(__dirname, '../static'), 109 | to: path.resolve(__dirname, '../dist/static'), 110 | ignore: ['.*'] 111 | } 112 | ]) 113 | ] 114 | } 115 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var utils = require('./utils') 2 | var webpack = require('webpack') 3 | var config = require('../config') 4 | var merge = require('webpack-merge') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | // var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 8 | 9 | // copy from ./webpack.prod.conf.js 10 | var path = require('path') 11 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 12 | var CopyWebpackPlugin = require('copy-webpack-plugin') 13 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 14 | 15 | // add hot-reload related code to entry chunks 16 | // Object.keys(baseWebpackConfig.entry).forEach(function (name) { 17 | // baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 18 | // }) 19 | 20 | module.exports = merge(baseWebpackConfig, { 21 | module: { 22 | rules: utils.styleLoaders({ 23 | sourceMap: config.dev.cssSourceMap, 24 | extract: true 25 | }) 26 | }, 27 | // cheap-module-eval-source-map is faster for development 28 | // devtool: '#cheap-module-eval-source-map', 29 | devtool: '#source-map', 30 | output: { 31 | path: config.build.assetsRoot, 32 | // filename: utils.assetsPath('[name].[chunkhash].js'), 33 | // chunkFilename: utils.assetsPath('[id].[chunkhash].js') 34 | filename: utils.assetsPath('[name].js'), 35 | chunkFilename: utils.assetsPath('[id].js') 36 | }, 37 | plugins: [ 38 | new webpack.DefinePlugin({ 39 | 'process.env': config.dev.env 40 | }), 41 | 42 | // copy from ./webpack.prod.conf.js 43 | // extract css into its own file 44 | new ExtractTextPlugin({ 45 | // filename: utils.assetsPath('[name].[contenthash].css') 46 | filename: utils.assetsPath('[name].wxss') 47 | }), 48 | // Compress extracted CSS. We are using this plugin so that possible 49 | // duplicated CSS from different components can be deduped. 50 | new OptimizeCSSPlugin({ 51 | cssProcessorOptions: { 52 | safe: true 53 | } 54 | }), 55 | new webpack.optimize.CommonsChunkPlugin({ 56 | name: 'common/vendor', 57 | minChunks: function (module, count) { 58 | // any required modules inside node_modules are extracted to vendor 59 | return ( 60 | module.resource && 61 | /\.js$/.test(module.resource) && 62 | module.resource.indexOf('node_modules') >= 0 63 | ) || count > 1 64 | } 65 | }), 66 | new webpack.optimize.CommonsChunkPlugin({ 67 | name: 'common/manifest', 68 | chunks: ['common/vendor'] 69 | }), 70 | 71 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 72 | // new webpack.HotModuleReplacementPlugin(), 73 | new webpack.NoEmitOnErrorsPlugin(), 74 | // https://github.com/ampedandwired/html-webpack-plugin 75 | // new HtmlWebpackPlugin({ 76 | // filename: 'index.html', 77 | // template: 'index.html', 78 | // inject: true 79 | // }), 80 | new FriendlyErrorsPlugin() 81 | ] 82 | }) 83 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var utils = require('./utils') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var UglifyJsPlugin = require('uglifyjs-webpack-plugin') 8 | var CopyWebpackPlugin = require('copy-webpack-plugin') 9 | // var HtmlWebpackPlugin = require('html-webpack-plugin') 10 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 12 | 13 | var env = config.build.env 14 | 15 | var webpackConfig = merge(baseWebpackConfig, { 16 | module: { 17 | rules: utils.styleLoaders({ 18 | sourceMap: config.build.productionSourceMap, 19 | extract: true 20 | }) 21 | }, 22 | devtool: config.build.productionSourceMap ? '#source-map' : false, 23 | output: { 24 | path: config.build.assetsRoot, 25 | // filename: utils.assetsPath('[name].[chunkhash].js'), 26 | // chunkFilename: utils.assetsPath('[id].[chunkhash].js') 27 | filename: utils.assetsPath('[name].js'), 28 | chunkFilename: utils.assetsPath('[id].js') 29 | }, 30 | plugins: [ 31 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 32 | new webpack.DefinePlugin({ 33 | 'process.env': env 34 | }), 35 | new UglifyJsPlugin({ 36 | sourceMap: true 37 | }), 38 | // extract css into its own file 39 | new ExtractTextPlugin({ 40 | // filename: utils.assetsPath('[name].[contenthash].css') 41 | filename: utils.assetsPath('[name].wxss') 42 | }), 43 | // Compress extracted CSS. We are using this plugin so that possible 44 | // duplicated CSS from different components can be deduped. 45 | new OptimizeCSSPlugin({ 46 | cssProcessorOptions: { 47 | safe: true 48 | } 49 | }), 50 | // generate dist index.html with correct asset hash for caching. 51 | // you can customize output by editing /index.html 52 | // see https://github.com/ampedandwired/html-webpack-plugin 53 | // new HtmlWebpackPlugin({ 54 | // filename: config.build.index, 55 | // template: 'index.html', 56 | // inject: true, 57 | // minify: { 58 | // removeComments: true, 59 | // collapseWhitespace: true, 60 | // removeAttributeQuotes: true 61 | // // more options: 62 | // // https://github.com/kangax/html-minifier#options-quick-reference 63 | // }, 64 | // // necessary to consistently work with multiple chunks via CommonsChunkPlugin 65 | // chunksSortMode: 'dependency' 66 | // }), 67 | // keep module.id stable when vender modules does not change 68 | new webpack.HashedModuleIdsPlugin(), 69 | // split vendor js into its own file 70 | new webpack.optimize.CommonsChunkPlugin({ 71 | name: 'common/vendor', 72 | minChunks: function (module, count) { 73 | // any required modules inside node_modules are extracted to vendor 74 | return ( 75 | module.resource && 76 | /\.js$/.test(module.resource) && 77 | module.resource.indexOf('node_modules') >= 0 78 | ) || count > 1 79 | } 80 | }), 81 | // extract webpack runtime and module manifest to its own file in order to 82 | // prevent vendor hash from being updated whenever app bundle is updated 83 | new webpack.optimize.CommonsChunkPlugin({ 84 | name: 'common/manifest', 85 | chunks: ['common/vendor'] 86 | }) 87 | ] 88 | }) 89 | 90 | // if (config.build.productionGzip) { 91 | // var CompressionWebpackPlugin = require('compression-webpack-plugin') 92 | 93 | // webpackConfig.plugins.push( 94 | // new CompressionWebpackPlugin({ 95 | // asset: '[path].gz[query]', 96 | // algorithm: 'gzip', 97 | // test: new RegExp( 98 | // '\\.(' + 99 | // config.build.productionGzipExtensions.join('|') + 100 | // ')$' 101 | // ), 102 | // threshold: 10240, 103 | // minRatio: 0.8 104 | // }) 105 | // ) 106 | // } 107 | 108 | if (config.build.bundleAnalyzerReport) { 109 | var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 110 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 111 | } 112 | 113 | module.exports = webpackConfig 114 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: '', 10 | assetsPublicPath: '/', 11 | productionSourceMap: false, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'], 18 | // Run the build command with an extra argument to 19 | // View the bundle analyzer report after build finishes: 20 | // `npm run build --report` 21 | // Set to `true` or `false` to always turn it on or off 22 | bundleAnalyzerReport: process.env.npm_config_report 23 | }, 24 | dev: { 25 | env: require('./dev.env'), 26 | port: 8080, 27 | // 在小程序开发者工具中不需要自动打开浏览器 28 | autoOpenBrowser: false, 29 | assetsSubDirectory: '', 30 | assetsPublicPath: '/', 31 | proxyTable: {}, 32 | // CSS Sourcemaps off by default because relative paths are "buggy" 33 | // with this option, according to the CSS-Loader README 34 | // (https://github.com/webpack/css-loader#sourcemaps) 35 | // In our experience, they generally work as expected, 36 | // just be aware of this issue when enabling this option. 37 | cssSourceMap: false 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | mpvue-meituan 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mpvue-meituan", 3 | "version": "1.0.0", 4 | "description": "mpvue 框架在美团外卖项目上实战", 5 | "author": "刘光强 <1126756952@qq.com>", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "start": "node build/dev-server.js", 10 | "build": "node build/build.js" 11 | }, 12 | "dependencies": { 13 | "lodash": "^4.17.10", 14 | "minapp-api-promise": "^1.0.2", 15 | "mpvue": "^1.0.11", 16 | "mpvue-wxparse": "^0.6.5", 17 | "vuex": "^3.0.1" 18 | }, 19 | "devDependencies": { 20 | "babel-core": "^6.22.1", 21 | "babel-loader": "^7.1.1", 22 | "babel-plugin-transform-runtime": "^6.22.0", 23 | "babel-preset-env": "^1.3.2", 24 | "babel-preset-stage-2": "^6.22.0", 25 | "babel-register": "^6.22.0", 26 | "chalk": "^2.4.0", 27 | "connect-history-api-fallback": "^1.3.0", 28 | "copy-webpack-plugin": "^4.5.1", 29 | "css-loader": "^0.28.11", 30 | "cssnano": "^3.10.0", 31 | "eventsource-polyfill": "^0.9.6", 32 | "express": "^4.16.3", 33 | "extract-text-webpack-plugin": "^3.0.2", 34 | "file-loader": "^1.1.11", 35 | "friendly-errors-webpack-plugin": "^1.7.0", 36 | "glob": "^7.1.2", 37 | "html-webpack-plugin": "^3.2.0", 38 | "http-proxy-middleware": "^0.18.0", 39 | "mpvue-loader": "^1.1.2", 40 | "mpvue-template-compiler": "^1.0.11", 41 | "mpvue-webpack-target": "^1.0.0", 42 | "node-sass": "^4.9.3", 43 | "optimize-css-assets-webpack-plugin": "^3.2.0", 44 | "ora": "^2.0.0", 45 | "portfinder": "^1.0.13", 46 | "postcss-loader": "^2.1.4", 47 | "postcss-mpvue-wxss": "^1.0.0", 48 | "prettier": "~1.12.1", 49 | "px2rpx-loader": "^0.1.10", 50 | "relative": "^3.0.2", 51 | "rimraf": "^2.6.0", 52 | "sass-loader": "^7.1.0", 53 | "sass-resources-loader": "^1.3.3", 54 | "semver": "^5.3.0", 55 | "shelljs": "^0.8.1", 56 | "style-loader": "^0.23.0", 57 | "uglifyjs-webpack-plugin": "^1.2.5", 58 | "url-loader": "^1.0.1", 59 | "vue-style-loader": "^4.1.0", 60 | "webpack": "^3.11.0", 61 | "webpack-bundle-analyzer": "^2.2.1", 62 | "webpack-dev-middleware-hard-disk": "^1.12.0", 63 | "webpack-merge": "^4.1.0", 64 | "webpack-mpvue-asset-plugin": "^0.1.1" 65 | }, 66 | "engines": { 67 | "node": ">= 4.0.0", 68 | "npm": ">= 3.0.0" 69 | }, 70 | "browserslist": [ 71 | "> 1%", 72 | "last 2 versions", 73 | "not ie <= 8" 74 | ] 75 | } 76 | -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件。", 3 | "setting": { 4 | "urlCheck": false, 5 | "es6": false, 6 | "postcss": true, 7 | "minified": true, 8 | "newFeature": true 9 | }, 10 | "miniprogramRoot": "dist/", 11 | "compileType": "miniprogram", 12 | "appid": "wx69720258b4555088", 13 | "projectname": "mpvue-meituan", 14 | "libVersion": "2.3.0", 15 | "condition": { 16 | "search": { 17 | "current": -1, 18 | "list": [] 19 | }, 20 | "conversation": { 21 | "current": -1, 22 | "list": [] 23 | }, 24 | "game": { 25 | "currentL": -1, 26 | "list": [] 27 | }, 28 | "miniprogram": { 29 | "current": -1, 30 | "list": [] 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 2 | 75 | 76 | -------------------------------------------------------------------------------- /src/action/action.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by guangqiang on 2017/10/3. 3 | */ 4 | 5 | import {getFetch, postFetch, putFetch, getFetchFromCache, postFetchForValidator} from '@/network/request/HttpExtension' 6 | import {PATH} from '@/constants/pathConfig' 7 | import {ApiSource} from '@/constants/commonType' 8 | 9 | const movieList = params => getFetch(PATH.PICTURE_LIST, params, false) 10 | const movieShowTimeList = params => getFetch(PATH.MOVIE_SHOWTIME, params, false, ApiSource.TIMEMOVIE, () => {}) 11 | const movieComeingNewList = params => getFetch(PATH.MOVIE_COMEING_NEW, params, ApiSource.TIMEMOVIE) 12 | const movieDetail = params => getFetch(PATH.MOVIE_DETAIL, params, ApiSource.TIMETICKET) 13 | 14 | const queryHomeHeadCategory = params => postFetch(`${PATH.HOME_HEAD_CATEGORY}?ui=${params.ui}®ion_id=${params.region_id}®ion_version=${params.region_version}`, params, false) 15 | const createActivity = params => postFetch(PATH.CREATE_ACTIVITY, params, true) 16 | const getActivityDetail = params => getFetch(`${PATH.GET_ACTIVITY_DETAIL}/${params.id}?longitude=${params.longitude}&latitude=${params.latitude}&append=${params.append}`, {}, false) 17 | const getActivityDetailGpsNull = params => getFetch(`${PATH.GET_ACTIVITY_DETAIL}/${params.id}?append=${params.append}`, {}, false) 18 | const bargainAction = params => postFetch(PATH.BARGAIN_EVENT, params, true) 19 | const bargainParticipatorList = params => getFetch(PATH.BARGAIN_PARTICIPATOR_LIST, params, false) 20 | const userLogin = params => postFetch(`${PATH.LOGIN}?trace=true`, params, false) 21 | const updateUserLogin = params => putFetch(PATH.UPDATE_USER_INFO, params, false) 22 | const refreshToken = params => postFetch(PATH.REFRESH_TOKEN, params, false) 23 | const queryActivityMaxLimit = params => getFetch(PATH.QUERY_ACTIVITY_MAXLIMIT, params, false) 24 | const conmuseRecordList = params => getFetch(PATH.CONSUME_RECORD_LIST, params, false) 25 | const getActivityList = params => getFetch(PATH.GETACTIVITY_LIST, params, false) 26 | const getConsumeDetailData = params => getFetch(`${PATH.PAYMENT_DETAIL}/${params.id}?append=${params.append}`, {}, false) 27 | const createOrderData = params => postFetch(PATH.CREATE_ORDER, params, false) 28 | const payOrderData = params => postFetch(`${PATH.PAY_ORDER}/${params.id}/pay`, params, false) 29 | const gotCouponFinish = params => postFetch(`${PATH.GOT_COUPON_FINISH}/${params.id}/metadata`, params, false) 30 | const getCouponCard = params => postFetch(PATH.GET_COUPON_CARD, params, false) 31 | const getCouponList = params => getFetch(PATH.GET_COUPON_LIST, params, false) 32 | const queryShopData = params => getFetch(`${PATH.QUERY_SHOP_DATA}/${params.id}?append=${params.append}`, {}, false) 33 | const getMyCouponList = params => getFetch(PATH.GET_MY_COUPON_LIST, params, false) 34 | const shareStatistic = params => postFetch(PATH.SHARE_STATISTIC, params, false) 35 | const cancelOrder = params => putFetch(`${PATH.CANCEL_ORDER}/${params.id}/cancel`, params, false) 36 | const miniAppLogin = params => postFetch(`${PATH.MINIAPP_LIGIN}?scene=bind`, params, false) 37 | 38 | const postFormId = () => {} 39 | 40 | export { 41 | movieList, 42 | movieDetail, 43 | getCityLocation, 44 | queryHomeHeadCategory 45 | } -------------------------------------------------------------------------------- /src/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/home/main", 4 | "pages/shoppingCart/main", 5 | "pages/submitOrder/main", 6 | "pages/me/main", 7 | "pages/expiredRedPacket/main", 8 | "pages/expiredCoupon/main", 9 | "pages/redPacket/main", 10 | "pages/couponList/main", 11 | "pages/categoryList/main", 12 | "pages/selectAddress/main", 13 | "pages/searchList/main", 14 | "pages/addAddress/main", 15 | "pages/orderList/main", 16 | "pages/remark/main", 17 | "pages/citySearch/main", 18 | "pages/citys/main", 19 | "pages/index/main", 20 | "pages/addressList/main", 21 | "pages/protocol/main", 22 | "pages/feedback/main", 23 | "pages/pickProtocol/main", 24 | "pages/orderDetail/main" 25 | ], 26 | "window": { 27 | "backgroundTextStyle": "light", 28 | "navigationBarBackgroundColor": "#fff", 29 | "navigationBarTitleText": "WeChat", 30 | "navigationBarTextStyle": "black" 31 | }, 32 | "tabBar": { 33 | "color": "#999", 34 | "selectedColor": "#000", 35 | "backgroundColor": "#fff", 36 | "borderStyle": "black", 37 | "list": [{ 38 | "pagePath": "pages/home/main", 39 | "text": "首页", 40 | "iconPath": "static/images/icon_tabbar_home@3x.png", 41 | "selectedIconPath": "static/images/icon_tabbar_home_selected@3x.png" 42 | }, 43 | { 44 | "pagePath": "pages/orderList/main", 45 | "text": "订单", 46 | "iconPath": "static/images/icon_tabbar_order@3x.png", 47 | "selectedIconPath": "static/images/icon_tabbar_order_selected@3x.png" 48 | }, 49 | { 50 | "pagePath": "pages/me/main", 51 | "text": "我的", 52 | "iconPath": "static/images/icon_tabbar_mine@3x.png", 53 | "selectedIconPath": "static/images/icon_tabbar_mine_selected@3x.png" 54 | } 55 | ] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/assets/global.scss: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-06-29 18:07:09 */ 2 | 3 | // 美团外卖小程序主题色系 4 | 5 | /** 主题色 **/ 6 | $theme-color: #F9D173; 7 | 8 | // 默认浅灰色背景颜色 9 | $page-bgcolor: #F4F4F4; 10 | 11 | // 黑色背景颜色 12 | $pageBlack-bgcolor: #2C2D30; 13 | 14 | // 默认黑色字体颜色 15 | $textBlack-color: #333; 16 | 17 | // 默认深灰色字体颜色 18 | $textDarkGray-color: #666; 19 | 20 | // 默认灰色字体颜色 21 | $textGray-color: #ccc; 22 | 23 | // 美团红 24 | $mtRed-color: #e74c3c; 25 | 26 | // 默认浅灰色 27 | $textLightGray-color: #ccc; 28 | 29 | // 默认分割线颜色 30 | $spLine-color: #e4e4e4; 31 | 32 | // 默认虚分割线颜色 33 | $dashedLine-color: #EAEAEA; 34 | 35 | // 默认placeholder颜色 36 | $placeholder-textcolor: #9B9B9B; 37 | 38 | // borderColor 39 | $border-color: #808080; 40 | 41 | // 导航title 颜色 42 | $nav-titlecolor: #262626; 43 | 44 | // 导航背景颜色 45 | $nav-bgcolor: #FEFEFE; 46 | 47 | /** width **/ 48 | // 边框线宽度 49 | $border-width: 2rpx; 50 | // 分割线高度 51 | $line-width: 2rpx; 52 | 53 | /** height **/ 54 | // 底部按钮高度 55 | $bottonBtn-height: 44; 56 | // 通用列表cell高度 57 | $cell-height: 44; 58 | 59 | /** font **/ 60 | // 默认文字字体 61 | $text-font: 14; 62 | // 默认按钮文字字体 63 | $btn-font: 15; 64 | // 按钮小号文字字体 65 | $btnFont-small: 13; 66 | // 导航title字体 67 | $navTitle-font: 17; 68 | // tabBar文字字体 69 | $tabbarTitle-font: 12; 70 | // 占位符的默认字体大小 71 | $placeholder-font: 13; 72 | 73 | /** opacity **/ 74 | // mask 透明度 75 | $modal-opacity: 0.3; -------------------------------------------------------------------------------- /src/components/card.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | 20 | -------------------------------------------------------------------------------- /src/components/sep-line.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 47 | 48 | -------------------------------------------------------------------------------- /src/constants/commonType.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by guangqiang on 2017/10/3. 3 | */ 4 | 5 | const monthList = [ 6 | 'Jan', 7 | 'Feb', 8 | 'Mar', 9 | 'Apr', 10 | 'May', 11 | 'Jun', 12 | 'Jul', 13 | 'Aug', 14 | 'Sep', 15 | 'Oct', 16 | 'Nov', 17 | 'Dec' 18 | ] 19 | 20 | const activityTabList = [ 21 | { 22 | title: "全部", 23 | type: "all" 24 | }, 25 | { 26 | title: "进行中", 27 | type: "doing" 28 | }, 29 | { 30 | title: "已结束", 31 | type: "end" 32 | } 33 | ] 34 | 35 | const orderStatus = { 36 | '01': '待支付', 37 | '11': '已取消', 38 | '12': '超时取消', 39 | '20': '已部分支付', 40 | '21': '支付成功' 41 | } 42 | 43 | const bargainTip = [ 44 | '扶我起来,我还能砍!', 45 | '唔给力吧!', 46 | '做好事,不用谢', 47 | '这一刀可还行伐', 48 | '感情深,砍得狠', 49 | '今天手感还不错', 50 | '看我慈悲刀法', 51 | '砍价应该体面~', 52 | '纸短情长啊不如砍价~', 53 | '给点力,砍到底' 54 | ] 55 | 56 | const bargainStatus = { 57 | DOING: 'DOING', // 正在砍 58 | SUCCESS: 'SUCCESS', // 砍价拼团成功 59 | FAIL: 'FAIL', // 拼团失败 60 | END: 'END', // 来迟了, 61 | OVER_LIMIT: 'OVER_LIMIT' // 本次活动领取超过上限 62 | } 63 | 64 | // 事件埋点统计类型 65 | const logEventType = { 66 | enterPage: 3001, 67 | exitPage: 3002, 68 | click: 3003, 69 | slide: 3004, 70 | gesture: 3005 71 | } 72 | 73 | // 同一工程多域名配置 74 | const ApiSource = { 75 | meituan: 'meituan', 76 | XIAMIMUSIC: 'XIAMIMUSIC', 77 | TIMEMOVIE: 'TIMEMOVIE' 78 | } 79 | 80 | export { 81 | monthList, 82 | logEventType, 83 | ApiSource, 84 | activityTabList, 85 | bargainTip, 86 | orderStatus, 87 | bargainStatus 88 | } -------------------------------------------------------------------------------- /src/constants/errorCodeMap.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-07-19 20:41:50 */ 2 | 3 | const errorCode = { 4 | '20220001': '活动已参与', 5 | '20210021': '您已创建了活动,不可重复创建哦', 6 | '20210000': '活动不存在', 7 | '20210010': '活动不处于开放状态', 8 | '20230015': '活动名额已用光,请再换个试试吧~', 9 | '20230016': '活动名额已用光,请再换个试试吧~', 10 | '20230017': '优惠券库存不足', 11 | '20210001': '活动已结束', 12 | '20210008': '活动已结束', 13 | '20210009': '活动暂未发布开放状态' 14 | } 15 | 16 | export {errorCode} -------------------------------------------------------------------------------- /src/constants/hostConfig.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by guangqiang on 2017/10/1. 3 | */ 4 | 5 | const host = { 6 | dev: { 7 | API_URL: 'https://meituan.cangdu.org', 8 | XIAMI_URL: 'https://api-m.mtime.cn', 9 | MSITE_URL: 'https://api.douban.com', 10 | VENILOG_URL: 'https://api.douban.com', 11 | appId: 'wx3d5c531f5e123456', 12 | envVersion: 'develop' 13 | }, 14 | test: { 15 | API_URL: 'https://meituan.cangdu.org', 16 | XIAMI_URL: 'http://10.10.21.108:9990', 17 | MSITE_URL: 'https://api.douban.com', 18 | VENILOG_URL: 'https://api.douban.com', 19 | appId: 'wx3d5c531f5e123456', 20 | envVersion: 'develop' 21 | }, 22 | qa: { 23 | API_URL: 'https://meituan.cangdu.org', 24 | XIAMI_URL: 'http://xiamirun.avosapps.com', 25 | MSITE_URL: 'https://api.douban.com', 26 | VENILOG_URL: 'https://api.douban.com' 27 | }, 28 | pre: { 29 | API_URL: 'https://meituan.cangdu.org', 30 | XIAMI_URL: 'https://api-m.mtime.cn', 31 | MSITE_URL: 'https://api.douban.com', 32 | VENILOG_URL: 'https://api.douban.com', 33 | appId: 'wx3d5c531f5e123456', 34 | envVersion: 'develop' 35 | }, 36 | prd: { 37 | API_URL: 'https://wx.waimai.meituan.com', 38 | XIAMI_URL: 'https://api-m.mtime.cn', 39 | MSITE_URL: 'https://api.douban.com', 40 | VENILOG_URL: 'https://api.douban.com', 41 | appId: 'wx3d5c531f5e123456', 42 | envVersion: 'trial' 43 | } 44 | } 45 | 46 | let ENV = 'prd' 47 | let currentHost = host[ENV] 48 | 49 | const SET_HOST = (env = 'dev') => { 50 | ENV = env 51 | currentHost = host[ENV] 52 | } 53 | 54 | const API_URL = currentHost.API_URL 55 | const XIAMI_URL = currentHost.XIAMI_URL 56 | const MSITE_URL = currentHost.MSITE_URL 57 | const VENILOG_URL = currentHost.VENILOG_URL 58 | export {ENV, API_URL, MSITE_URL, VENILOG_URL, XIAMI_URL, SET_HOST, currentHost} -------------------------------------------------------------------------------- /src/constants/pathConfig.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-06-29 10:26:46 */ 2 | 3 | const PATH = { 4 | HOME_HEAD_CATEGORY: '/weapp/v1/v8/home/head', 5 | PICTURE_DETAIL: '/hp/detail/', 6 | PICTURE_GRID_LIST: '/hp/bymonth/', 7 | MOVIE_LIST: '/movie/list/', 8 | 9 | CITY_LOCATION: '/v1/cities', 10 | CREATE_ACTIVITY: '/mc/v1/me/activities', 11 | GET_ACTIVITY_DETAIL: '/mc/v1/activities', 12 | BARGAIN_EVENT: '/mc/v1/me/participants', 13 | BARGAIN_PARTICIPATOR_LIST: '/mc/v1/participants', 14 | LOGIN: '/uc/v1/auth/login/wx-miniapp', 15 | UPDATE_USER_INFO: '/uc/v1/account/wx', 16 | REFRESH_TOKEN: '/uc/v1/auth/refresh-token', 17 | QUERY_ACTIVITY_MAXLIMIT: '/mc/v1/activities', 18 | CONSUME_RECORD_LIST: '/tc/v1/me/orders', 19 | GETACTIVITY_LIST: '/mc/v1/me/activities', 20 | PAYMENT_DETAIL: '/tc/v1/me/orders', 21 | CREATE_ORDER: '/tc/v1/me/orders', 22 | PAY_ORDER: '/tc/v1/me/orders', 23 | GOT_COUPON_FINISH: '/mc/v1/participants', 24 | GET_COUPON_CARD: '/mc/v1/coupons', 25 | GET_COUPON_LIST: '/mc/v1/coupons', 26 | QUERY_SHOP_DATA: '/sc/v1/shops', 27 | GET_MY_COUPON_LIST: '/mc/v1/me/coupons', 28 | SHARE_STATISTIC: '/cc/v1/me/footprints', 29 | CANCEL_ORDER: '/tc/v1/me/orders', 30 | POST_FORM_ID: '/xc/api/v1/miniapps', 31 | MINIAPP_LIGIN: '/uc/v1/auth/login/wx-miniapp' 32 | } 33 | 34 | export {PATH} -------------------------------------------------------------------------------- /src/constants/responseCode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by guangqiang on 2017/10/3. 3 | */ 4 | 5 | const responseCode = { 6 | RESPONSE_SUCCESS: '200', // 请求成功,返回数据 7 | TOKEN_INVALID: '-117', // token 失效 8 | USER_LOGOUT: '-110', // 用户未登录 9 | PARTICIPANT_NOT_GRANT_JOIN: '20220010', // 用户没有权限参与 10 | ACTIVITY_CREATER_NOT_GRANT: '20210025', // 活动创建者没有权限 11 | } 12 | 13 | export default responseCode -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-08-30 14:28:14 */ 2 | 3 | import Vue from 'vue' 4 | import App from './App' 5 | import store from './store' 6 | import * as util from './utils' 7 | 8 | Vue.config.productionTip = false 9 | App.mpType = 'app' 10 | Vue.prototype.util = util 11 | 12 | const app = new Vue({ 13 | store, 14 | ...App 15 | }) 16 | 17 | app.$mount() -------------------------------------------------------------------------------- /src/middlewares/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Umbrella001/mpvue-meituan/ea9c57fce44c762edaa10114316ac91b20f27773/src/middlewares/index.js -------------------------------------------------------------------------------- /src/network/cache/cache.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by guangqiang on 2017/10/3. 3 | */ 4 | 5 | import {getStorage, setStorage} from '@/utils/wxapi' 6 | 7 | /** 8 | * @param key:key为请求 url 9 | * @param fetchFunc:回调函数 10 | * @param isCache:是否需要缓存 11 | * @returns {value} 12 | */ 13 | const dataCache = (key, fetchFunc, isCache) => { 14 | // 不缓存, 15 | if (!isCache) { 16 | return fetchFunc() 17 | } 18 | // 需要缓存 19 | return getStorage(key).then(value => { 20 | if (value) { 21 | // 如果在缓存中找到数据,则返回缓存中的数据 22 | return value 23 | } else { 24 | // 如果在缓存中取不到数据,则从网络请求中获取数据,并将获取到的数据缓存下来 25 | return fetchFunc().then(value => { 26 | value ? setStorage(key, value) : null 27 | return value 28 | }) 29 | } 30 | }) 31 | } 32 | 33 | export {dataCache} -------------------------------------------------------------------------------- /src/network/request/HttpExtension.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by guangqiang on 2017/10/3. 3 | */ 4 | 5 | /** 网络请求工具类的拓展类,便于后期网络层修改维护 **/ 6 | 7 | import HttpUtils from './HttpRequest' 8 | import {API_URL, XIAMIMUSIC, XIAMI_URL} from '@/constants/hostConfig' 9 | import {ApiSource} from '@/constants/commonType' 10 | import {dataCache} from '../cache/cache' 11 | 12 | /** 13 | * GET \ POST 14 | * 从缓存中读取数据 15 | * @param isCache 是否缓存 16 | * @param requestType 网络请求类型 17 | * @param url 请求url 18 | * @param params 请求参数 19 | * @param isLoading 是否显示Loading 20 | * @param source API资源 21 | * @param callback 是否有回调函数 22 | * @returns {value \ promise} 返回的值如果从缓存中取到数据就直接换行数据,或则返回promise对象 23 | */ 24 | const fetchData = (isCache, requestType) => (url, params, isLoading, source, callback) => { 25 | switch (source) { 26 | case ApiSource.XIAMIMUSIC: 27 | url = `${XIAMI_URL}${url}` 28 | break 29 | case ApiSource.TIMEMOVIE: 30 | url = `${TIME_MOVIE_URL}${url}` 31 | break 32 | default: 33 | url = `${API_URL}${url}` 34 | break 35 | } 36 | const fetchFunc = () => { 37 | let promise = HttpUtils.fetch(url, params, requestType, isLoading) 38 | if (callback && typeof callback === 'function') { 39 | promise.then(response => { 40 | return callback(response) 41 | }) 42 | } 43 | return promise 44 | } 45 | return dataCache(url, fetchFunc, isCache) 46 | } 47 | 48 | /** 49 | * GET 请求 50 | * @param url 51 | * @param params 52 | * @param source 53 | * @param callback 54 | * @returns {{promise: Promise}} 55 | */ 56 | const getFetch = fetchData(false, 'GET') 57 | 58 | /** 59 | * POST 请求 60 | * @param url 61 | * @param params 62 | * @param callback 63 | * @returns {{promise: Promise}} 64 | */ 65 | const postFetch = fetchData(false, 'POST') 66 | 67 | /** 68 | * PUT 请求 69 | * @param url 70 | * @param params 71 | * @param callback 72 | * @returns {{promise: Promise}} 73 | */ 74 | const putFetch = fetchData(false, 'PUT') 75 | 76 | /** 77 | * DELETE 请求 78 | * @param url 79 | * @param params 80 | * @param callback 81 | * @returns {{promise: Promise}} 82 | */ 83 | const deleteFetch = fetchData(false, 'DELETE') 84 | 85 | /** 86 | * GET 请求,带缓存策略 87 | * @param url 88 | * @param params 89 | * @param callback 90 | * @returns {{promise: Promise}} 91 | */ 92 | const getFetchFromCache = fetchData(true, 'GET') 93 | 94 | /** 95 | * POST请求参数校验,通过middleware 来实现自动校验表单参数是否合法 96 | * @param url 97 | * @param params 98 | */ 99 | const postFetchForValidator = (url, params) => { 100 | let promise 101 | promise = () => { 102 | return fetchData(false, 'POST')(url, {}) 103 | } 104 | return { 105 | data: params, 106 | params, 107 | nextPayload: { 108 | promise: promise 109 | } 110 | } 111 | } 112 | 113 | export {getFetch, postFetch, putFetch, deleteFetch, getFetchFromCache, postFetchForValidator} -------------------------------------------------------------------------------- /src/network/request/HttpRequest.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by guangqiang on 2017/10/3. 3 | */ 4 | 5 | /** 封装的基于Fetch网络请求工具类 **/ 6 | 7 | import responseCode from '@/constants/responseCode' 8 | import {request, login} from '@/utils/wxapi' 9 | import {API_URL, XIAMIMUSIC} from '@/constants/hostConfig' 10 | import {PATH} from '@/constants/pathConfig' 11 | import {currentHost} from "@/constants/hostConfig" 12 | import {errorCode} from "@/constants/errorCodeMap" 13 | import {timestampToCommonDate} from "@/utils/formatTime" 14 | import {_array} from "@/utils/arrayExtension" 15 | 16 | /** 17 | * fetch 网络请求的header,可自定义header 内容 18 | * @type {{Accept: string, Content-Type: string, accessToken: *}} 19 | */ 20 | const header = { 21 | 'Content-Type': 'application/json' 22 | } 23 | 24 | /** 25 | * GET请求时,拼接请求URL 26 | * @param url 请求URL 27 | * @param params 请求参数 28 | * @returns {*} 29 | */ 30 | const handleUrl = url => params => { 31 | if (params) { 32 | let paramsArray = [] 33 | Object.keys(params).forEach(key => paramsArray.push(key + '=' + encodeURIComponent(params[key]))) 34 | if (url.search(/\?/) === -1) { 35 | typeof (params) === 'object' ? url += '?' + paramsArray.join('&') : url 36 | } else { 37 | url += '&' + paramsArray.join('&') 38 | } 39 | } 40 | return url 41 | } 42 | 43 | /** 44 | * fetch 网络请求超时处理 45 | * @param original_promise 原始的fetch 46 | * @param timeout 超时时间 30s 47 | * @returns {Promise.<*>} 48 | */ 49 | const timeoutFetch = (original_fetch, timeout = 30000) => { 50 | let timeoutBlock = () => {} 51 | let timeout_promise = new Promise((resolve, reject) => { 52 | timeoutBlock = () => { 53 | // 请求超时处理 54 | reject('timeout promise') 55 | } 56 | }) 57 | 58 | let abortable_promise = Promise.race([ 59 | original_fetch, 60 | timeout_promise 61 | ]) 62 | 63 | setTimeout(() => { 64 | timeoutBlock() 65 | }, timeout) 66 | 67 | return abortable_promise 68 | } 69 | 70 | async function handleLogin(callback) { 71 | return callback() 72 | var loginInfo = wx.getStorageSync('loginInfo') || {} 73 | var refreshToken = loginInfo.refreshToken 74 | var newData = new Date().getTime() 75 | if (loginInfo.accessToken) { 76 | if (loginInfo.expiration > newData) { 77 | console.log('未过期') 78 | return callback() 79 | } else { 80 | console.log('已过期') 81 | let params = { 82 | url: `${API_URL}${PATH.REFRESH_TOKEN}`, 83 | data: {refreshToken: refreshToken}, 84 | method: 'POST' 85 | } 86 | const refreshTokenInfo = await request(params) 87 | if (refreshTokenInfo.code != 0) { 88 | const wxLoginInfo = await login() 89 | let param = { 90 | url: `${API_URL}${PATH.LOGIN}?trace=true`, 91 | data: {appId: currentHost.appId, jsCode: wxLoginInfo.code}, 92 | method: 'POST' 93 | } 94 | const qbLoginInfo = await request(param) 95 | console.log('silentUserId:', qbLoginInfo.data.user.id) 96 | console.log('silentAccessToken:', qbLoginInfo.data.accessToken) 97 | wx.setStorageSync('loginInfo', qbLoginInfo.data) 98 | return callback() 99 | } else { 100 | wx.setStorageSync('loginInfo', Object.assign(loginInfo, refreshTokenInfo.data)) 101 | return callback() 102 | } 103 | } 104 | } else { 105 | console.log('未登录') 106 | const wxLoginInfo = await login() 107 | let params = { 108 | url: `${API_URL}${PATH.LOGIN}?trace=true`, 109 | data: {appId: currentHost.appId, jsCode: wxLoginInfo.code}, 110 | method: 'POST' 111 | } 112 | const qbLoginInfo = await request(params) 113 | console.log('silentUserId:', qbLoginInfo.data.user.id) 114 | console.log('silentAccessToken:', qbLoginInfo.data.accessToken) 115 | wx.setStorageSync('loginInfo', qbLoginInfo.data) 116 | return callback() 117 | } 118 | } 119 | 120 | const networkLog = (url, params, res, beforeRequest, isSuccess) => { 121 | const pages = getCurrentPages() 122 | const currentPage = pages[pages.length - 1] 123 | const route = currentPage.route 124 | const networkType = wx.getStorageSync('networkType') 125 | const afterRequest = new Date().getTime() 126 | const timeDif = afterRequest - beforeRequest 127 | var networkArr = wx.getStorageSync('networkArr') || [] 128 | if (networkArr.length >= 30) { 129 | wx.removeStorageSync('networkArr') 130 | networkArr = [] 131 | } 132 | var time = timestampToCommonDate(new Date().getTime()) 133 | networkArr = _array.unshift(networkArr, {url, params, res, time, route, timeDif, networkType, isSuccess}) 134 | wx.setStorageSync('networkArr', networkArr) 135 | } 136 | 137 | const HttpUtils = { 138 | /** 139 | * fetch网络请求 140 | * @param {string} [url=''] 网络请求URL 141 | * @param {*} [params={}] 网络请求参数 142 | * @param {string} [requestType='GET'] 请求类型 143 | * @param {boolean} [isLoading=true] 是否需要Loading 144 | */ 145 | fetch: (url = '', params = {}, requestType = 'GET', isLoading = false) => { 146 | const fetchCallback = () => { 147 | let promise = timeoutFetch(new Promise((resolve, reject) => { 148 | wx.showNavigationBarLoading() 149 | isLoading ? wx.showLoading({title: '加载中...', mask: true}) : null 150 | const beforeRequest = new Date().getTime() 151 | wx.request({ 152 | url: url, 153 | data: params, 154 | header: header, 155 | method: requestType, 156 | success: function (res) { 157 | let isSuccess = false 158 | let resCode = res.statusCode 159 | if (parseInt(resCode / 100) == 2) { 160 | isSuccess = true 161 | resolve(res.data) 162 | } else if (resCode == responseCode.TOKEN_INVALID) { 163 | } else if (resCode == responseCode.USER_LOGOUT) { 164 | } else { 165 | wx.showToast({ title: '服务器异常', icon: 'none', duration: 4000 }) 166 | } 167 | networkLog(url, params, res.data, beforeRequest, isSuccess) 168 | }, 169 | fail: function (e) { 170 | wx.showToast({ title: e.errMsg, icon: 'none', duration: 4000 }) 171 | networkLog(url, params, e, beforeRequest, false) 172 | reject(e) 173 | }, 174 | complete: function () { 175 | isLoading ? wx.hideLoading() : null 176 | wx.hideNavigationBarLoading() 177 | wx.stopPullDownRefresh() 178 | } 179 | }) 180 | })) 181 | return promise 182 | } 183 | return handleLogin(fetchCallback) 184 | } 185 | } 186 | 187 | export default HttpUtils -------------------------------------------------------------------------------- /src/pages/addAddress/index.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 47 | 48 | 188 | -------------------------------------------------------------------------------- /src/pages/addAddress/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-18 17:04:59 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/addAddress/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "新增收货地址" 3 | } -------------------------------------------------------------------------------- /src/pages/addressList/data.js: -------------------------------------------------------------------------------- 1 | const addressList = { 2 | "data": [{ 3 | "phone": "15214313256", 4 | "can_not_shipping_type": 0, 5 | "category_icon": "", 6 | "gd_addr_type": "", 7 | "is_default": 0, 8 | "address_range_tip": "", 9 | "editable": 1, 10 | "bind_type": 11, 11 | "id": 935908631, 12 | "category": 0, 13 | "house_number": "2楼,外卖科技", 14 | "can_shipping": 1, 15 | "address": "上海科技绿洲B区18号楼", 16 | "name": "刘光强", 17 | "gender": "先生", 18 | "longitude": 121385976, 19 | "latitude": 31164474, 20 | "address_type": 0 21 | }, { 22 | "phone": "15214313256", 23 | "can_not_shipping_type": 0, 24 | "category_icon": "http://p1.meituan.net/aichequan/459e21821938f624d4b340e6444831f71644.png", 25 | "gd_addr_type": "", 26 | "is_default": 0, 27 | "address_range_tip": "", 28 | "editable": 1, 29 | "bind_type": 15, 30 | "id": 1225134045, 31 | "category": 1, 32 | "house_number": "18号楼888号", 33 | "can_shipping": 1, 34 | "address": "九星苑", 35 | "name": "刘先生", 36 | "gender": "先生", 37 | "longitude": 121381110, 38 | "latitude": 31150280, 39 | "address_type": 0 40 | }, { 41 | "phone": "15214313256", 42 | "can_not_shipping_type": 0, 43 | "category_icon": "", 44 | "gd_addr_type": "", 45 | "is_default": 0, 46 | "address_range_tip": "", 47 | "editable": 1, 48 | "bind_type": 11, 49 | "id": 684933800, 50 | "category": 0, 51 | "house_number": "401", 52 | "can_shipping": 1, 53 | "address": "广中西路911弄51号", 54 | "name": "光强", 55 | "gender": "先生", 56 | "longitude": 121437016, 57 | "latitude": 31278644, 58 | "address_type": 0 59 | }, { 60 | "phone": "15214313256", 61 | "can_not_shipping_type": 0, 62 | "category_icon": "", 63 | "gd_addr_type": "", 64 | "is_default": 0, 65 | "address_range_tip": "", 66 | "editable": 1, 67 | "bind_type": 11, 68 | "id": 716687722, 69 | "category": 0, 70 | "house_number": "1111号,111栋", 71 | "can_shipping": 1, 72 | "address": "沪太路1067弄11号", 73 | "name": "光强", 74 | "gender": "先生", 75 | "longitude": 121427128, 76 | "latitude": 31277978, 77 | "address_type": 0 78 | }], 79 | "code": 0, 80 | "msg": "成功" 81 | } 82 | 83 | export {addressList} -------------------------------------------------------------------------------- /src/pages/addressList/index.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 41 | 42 | 109 | -------------------------------------------------------------------------------- /src/pages/addressList/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-18 16:43:20 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/addressList/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "我的收获地址" 3 | } -------------------------------------------------------------------------------- /src/pages/categoryList/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-18 19:54:52 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/categoryList/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "美食" 3 | } -------------------------------------------------------------------------------- /src/pages/citySearch/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 29 | 30 | 110 | -------------------------------------------------------------------------------- /src/pages/citySearch/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-14 18:14:27 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() 7 | -------------------------------------------------------------------------------- /src/pages/citys/index.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 49 | 50 | 164 | -------------------------------------------------------------------------------- /src/pages/citys/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-08-30 18:13:59 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() 7 | -------------------------------------------------------------------------------- /src/pages/commentList/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/pages/commentList/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-10-07 17:51:40 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/commentList/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "评论" 3 | } -------------------------------------------------------------------------------- /src/pages/couponList/data.js: -------------------------------------------------------------------------------- 1 | const couponList = { 2 | "data": { 3 | "page_index": 0, 4 | "poi_coupon_info_list": [{ 5 | "valid": false, 6 | "poicoupon_view_id": "syAPBsPPPvyOk&source=wKid=OkPPOkPBt", 7 | "status": 1, 8 | "valid_day": 8, 9 | "code": "", 10 | "type": 1, 11 | "poi_id": 959825, 12 | "mutex_type": 1, 13 | "poi_url": "http://p1.meituan.net/waimaipoi/30759016da283ca9a103d83624cf26f340960.jpg", 14 | "info": "", 15 | "id": -11, 16 | "disable_descriptions": [], 17 | "title": "烧烤吧(龙虾)", 18 | "use_rule": "不可与满减、折扣商品、第二份半价活动优惠同时享受。在线支付专享。", 19 | "scheme": "", 20 | "valid_time_desc": "有效期至2018.10.01", 21 | "use_condition": "", 22 | "money": 35.0, 23 | "category_type": 0, 24 | "price_limit": "满65可用", 25 | "deadline": 1538409599 26 | }, { 27 | "valid": false, 28 | "poicoupon_view_id": "syAPBsPPPvywK&source=wKid=OkPPOkPBt", 29 | "status": 1, 30 | "valid_day": 8, 31 | "code": "", 32 | "type": 1, 33 | "poi_id": 5319356, 34 | "mutex_type": 1, 35 | "poi_url": "http://p0.meituan.net/waimaipoi/62f2afcb9bdf34e38fe183017995a307303008.jpg", 36 | "info": "", 37 | "id": -11, 38 | "disable_descriptions": [], 39 | "title": "串意十足烧烤店(古方路店)", 40 | "use_rule": "不可与满减、折扣商品、第二份半价活动优惠同时享受。在线支付专享。", 41 | "scheme": "", 42 | "valid_time_desc": "有效期至2018.10.01", 43 | "use_condition": "", 44 | "money": 31.0, 45 | "category_type": 0, 46 | "price_limit": "满48可用", 47 | "deadline": 1538409599 48 | }, { 49 | "valid": false, 50 | "poicoupon_view_id": "stsvayAsPvyts&source=wKid=OkPBBvvyt", 51 | "status": 1, 52 | "valid_day": 3, 53 | "code": "", 54 | "type": 1, 55 | "poi_id": 1602339, 56 | "mutex_type": 1, 57 | "poi_url": "http://p1.meituan.net/waimaipoi/172eb82855c13261baf78a056db93adc304216.jpg", 58 | "info": "", 59 | "id": -11, 60 | "disable_descriptions": [], 61 | "title": "席师傅特色麻辣香锅", 62 | "use_rule": "不可与满减、折扣商品、第二份半价活动优惠同时享受。在线支付专享。", 63 | "scheme": "", 64 | "valid_time_desc": "有效期至2018.09.26", 65 | "use_condition": "", 66 | "money": 28.0, 67 | "category_type": 0, 68 | "price_limit": "满45可用", 69 | "deadline": 1537977599 70 | }, { 71 | "valid": false, 72 | "poicoupon_view_id": "swKPPyAPPtsva&source=wKid=OkPBBvvyt", 73 | "status": 1, 74 | "valid_day": 3, 75 | "code": "", 76 | "type": 1, 77 | "poi_id": 5204575, 78 | "mutex_type": 1, 79 | "poi_url": "http://p1.meituan.net/business/4895902007cf8cad1e04d27d3f77d89f54971.jpg", 80 | "info": "", 81 | "id": -11, 82 | "disable_descriptions": [], 83 | "title": "九阿婆黄金猪排饭(漕河泾店)", 84 | "use_rule": "不可与满减、折扣商品、第二份半价活动优惠同时享受。在线支付专享。", 85 | "scheme": "", 86 | "valid_time_desc": "有效期至2018.09.26", 87 | "use_condition": "", 88 | "money": 26.0, 89 | "category_type": 0, 90 | "price_limit": "满30可用", 91 | "deadline": 1537977599 92 | }, { 93 | "valid": false, 94 | "poicoupon_view_id": "yBvvaOkyABvsP&source=wKid=OkPBBvwKv", 95 | "status": 1, 96 | "valid_day": 26, 97 | "code": "", 98 | "type": 1, 99 | "poi_id": 5631136, 100 | "mutex_type": 2, 101 | "poi_url": "http://p0.meituan.net/waimaipoi/c4ea604406e519bd53156313bf267c99100224.jpg", 102 | "info": "", 103 | "id": -11, 104 | "disable_descriptions": [], 105 | "title": "夜曲成人用品", 106 | "use_rule": "可与其他活动优惠同时享受。在线支付专享。", 107 | "scheme": "", 108 | "valid_time_desc": "有效期至2018.10.19", 109 | "use_condition": "", 110 | "money": 15.0, 111 | "category_type": 0, 112 | "price_limit": "满100可用", 113 | "deadline": 1539964799 114 | }, { 115 | "valid": false, 116 | "poicoupon_view_id": "PvyvaBvtsyAwK&source=wKid=OkPBvasPP", 117 | "status": 1, 118 | "valid_day": 7, 119 | "code": "", 120 | "type": 1, 121 | "poi_id": 4756335, 122 | "mutex_type": 2, 123 | "poi_url": "http://p1.meituan.net/waimaipoi/8f5a14a02bc26f9d7ea9fb6395ae108c4017.jpg", 124 | "info": "", 125 | "id": -11, 126 | "disable_descriptions": [], 127 | "title": "乐凯撒比萨(爱琴海购物公园店)", 128 | "use_rule": "可与其他活动优惠同时享受。在线支付专享。", 129 | "scheme": "", 130 | "valid_time_desc": "有效期至2018.09.30", 131 | "use_condition": "", 132 | "money": 9.0, 133 | "category_type": 0, 134 | "price_limit": "满90可用", 135 | "deadline": 1538323199 136 | }, { 137 | "valid": false, 138 | "poicoupon_view_id": "PPBvyyAtsOkwK&source=wKid=OkPBvatss", 139 | "status": 1, 140 | "valid_day": 3, 141 | "code": "", 142 | "type": 1, 143 | "poi_id": 4208203, 144 | "mutex_type": 2, 145 | "poi_url": "http://p0.meituan.net/waimaipoi/eec7c57c9497d61b02a886f0b8229ec3239616.jpg", 146 | "info": "", 147 | "id": -11, 148 | "disable_descriptions": [], 149 | "title": "重庆鸡公煲(漕宝店)", 150 | "use_rule": "可与其他活动优惠同时享受。在线支付专享。", 151 | "scheme": "", 152 | "valid_time_desc": "有效期至2018.09.26", 153 | "use_condition": "", 154 | "money": 5.0, 155 | "category_type": 0, 156 | "price_limit": "满56可用", 157 | "deadline": 1537977599 158 | }, { 159 | "valid": false, 160 | "poicoupon_view_id": "kOkBvBvvyOkwK&source=wKid=OkPBwKsPO", 161 | "status": 1, 162 | "valid_day": 23, 163 | "code": "", 164 | "type": 1, 165 | "poi_id": 2145959, 166 | "mutex_type": 2, 167 | "poi_url": "http://p1.meituan.net/waimaipoi/28cbe8190b93878db45cf126c5711eea40960.jpg", 168 | "info": "", 169 | "id": -11, 170 | "disable_descriptions": [], 171 | "title": "华城果业", 172 | "use_rule": "可与其他活动优惠同时享受。在线支付专享。", 173 | "scheme": "", 174 | "valid_time_desc": "有效期至2018.10.16", 175 | "use_condition": "", 176 | "money": 3.0, 177 | "category_type": 0, 178 | "price_limit": "满48可用", 179 | "deadline": 1539705599 180 | }, { 181 | "valid": false, 182 | "poicoupon_view_id": "vPBPBwKPPBvOk&source=wKid=OkPBOkPPB", 183 | "status": 1, 184 | "valid_day": 24, 185 | "code": "", 186 | "type": 1, 187 | "poi_id": 5439052, 188 | "mutex_type": 2, 189 | "poi_url": "http://p1.meituan.net/waimaipoi/339aeb47a0bff9d6ae6910309deb9aa811035.jpg", 190 | "info": "", 191 | "id": -11, 192 | "disable_descriptions": [], 193 | "title": "三米粥铺(东兰店)", 194 | "use_rule": "可与其他活动优惠同时享受。在线支付专享。", 195 | "scheme": "", 196 | "valid_time_desc": "有效期至2018.10.17", 197 | "use_condition": "", 198 | "money": 3.0, 199 | "category_type": 0, 200 | "price_limit": "满39可用", 201 | "deadline": 1539791999 202 | }], 203 | "show_coupon_token": 0, 204 | "has_more": 0, 205 | "coupon_token_url": "", 206 | "coupon_token_text": "去领券" 207 | }, 208 | "code": 0, 209 | "msg": "成功" 210 | } 211 | 212 | export {couponList} -------------------------------------------------------------------------------- /src/pages/couponList/index.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 67 | 68 | 185 | -------------------------------------------------------------------------------- /src/pages/couponList/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-18 15:39:31 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/couponList/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "商家代金券" 3 | } -------------------------------------------------------------------------------- /src/pages/dicedActivity/index.vue: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Umbrella001/mpvue-meituan/ea9c57fce44c762edaa10114316ac91b20f27773/src/pages/dicedActivity/index.vue -------------------------------------------------------------------------------- /src/pages/dicedActivity/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-19 23:23:49 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/dicedActivity/main.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /src/pages/expiredCoupon/data.js: -------------------------------------------------------------------------------- 1 | const dataList = { 2 | "data": { 3 | "page_index": 0, 4 | "poi_coupon_info_list": [{ 5 | "valid": false, 6 | "poicoupon_view_id": "vPPvyPBPBBvPP&source=wKid=OkPByAvaB", 7 | "status": 3, 8 | "valid_day": 0, 9 | "code": "", 10 | "type": 1, 11 | "poi_id": 5606842, 12 | "mutex_type": 1, 13 | "poi_url": "http://p1.meituan.net/waimaipoi/e3cda15ee74c4cc5ca6c0f75b427ca40321522.jpg", 14 | "info": "", 15 | "id": -11, 16 | "disable_descriptions": [], 17 | "title": "麻辣无双(东兰路店)", 18 | "use_rule": "不可与满减、折扣商品、第二份半价活动优惠同时享受。在线支付专享。", 19 | "scheme": "", 20 | "valid_time_desc": "有效期至2018.09.22", 21 | "use_condition": "", 22 | "money": 32.0, 23 | "category_type": 0, 24 | "price_limit": "满45可用", 25 | "deadline": 1537631999 26 | }, { 27 | "valid": false, 28 | "poicoupon_view_id": "vvayAtsBvsPyA&source=wKid=OkPByAvaB", 29 | "status": 3, 30 | "valid_day": 0, 31 | "code": "", 32 | "type": 1, 33 | "poi_id": 1602339, 34 | "mutex_type": 1, 35 | "poi_url": "http://p1.meituan.net/waimaipoi/172eb82855c13261baf78a056db93adc304216.jpg", 36 | "info": "", 37 | "id": -11, 38 | "disable_descriptions": [], 39 | "title": "席师傅特色麻辣香锅", 40 | "use_rule": "不可与满减、折扣商品、第二份半价活动优惠同时享受。在线支付专享。", 41 | "scheme": "", 42 | "valid_time_desc": "有效期至2018.09.22", 43 | "use_condition": "", 44 | "money": 28.0, 45 | "category_type": 0, 46 | "price_limit": "满45可用", 47 | "deadline": 1537631999 48 | }, { 49 | "valid": false, 50 | "poicoupon_view_id": "PsPvyOksPtsOk&source=wKid=OkPBBvvas", 51 | "status": 3, 52 | "valid_day": 0, 53 | "code": "", 54 | "type": 1, 55 | "poi_id": 4633504, 56 | "mutex_type": 1, 57 | "poi_url": "http://p0.meituan.net/waimaipoi/2fd1ecc03b71fcdcdc388981734e379a30167.jpg", 58 | "info": "", 59 | "id": -11, 60 | "disable_descriptions": [], 61 | "title": "粥宫壹号(漕宝路店)", 62 | "use_rule": "不可与满减、折扣商品、第二份半价活动优惠同时享受。在线支付专享。", 63 | "scheme": "", 64 | "valid_time_desc": "有效期至2018.09.22", 65 | "use_condition": "", 66 | "money": 18.0, 67 | "category_type": 0, 68 | "price_limit": "满25可用", 69 | "deadline": 1537631999 70 | }], 71 | "show_coupon_token": 0, 72 | "has_more": 0, 73 | "coupon_token_url": "", 74 | "coupon_token_text": "去领券" 75 | }, 76 | "code": 0, 77 | "msg": "成功" 78 | } 79 | 80 | export {dataList} -------------------------------------------------------------------------------- /src/pages/expiredCoupon/index.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 53 | 54 | 154 | -------------------------------------------------------------------------------- /src/pages/expiredCoupon/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-18 16:31:10 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/expiredCoupon/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "商家代金券" 3 | } -------------------------------------------------------------------------------- /src/pages/expiredRedPacket/data.js: -------------------------------------------------------------------------------- 1 | const dataList = { 2 | "data": { 3 | "show_steal_entry": 0, 4 | "page_size": 20, 5 | "vp_entrance": { 6 | "text": "", 7 | "bg_url": "", 8 | "sub_text": "", 9 | "link": "", 10 | "buy_status": 0, 11 | "icon_url": "", 12 | "show": false 13 | }, 14 | "page_index": 0, 15 | "coupon_total_num": 10, 16 | "has_more": 0, 17 | "coupon_list": [{ 18 | "coupon_sign": "", 19 | "status": 3, 20 | "shipping_type": 0, 21 | "coupon_id": -11, 22 | "coupon_key": "", 23 | "coupon_type": 1, 24 | "steal_status": 0, 25 | "poi_exchanged_coupon": 0, 26 | "poi_id": 0, 27 | "amount": 6.0, 28 | "id": -11, 29 | "disable_descriptions": [], 30 | "title": "狂欢月专属红包", 31 | "use_limits": "限仅限外卖狂欢月部分指定商户可用,微信小程序,非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 32 | "valid_time_desc": "有效期至2018.09.24", 33 | "coupon_view_id": "yOkPPvavyPBsP&source=tsid=OkPPwKtsv", 34 | "is_premium_type": false, 35 | "category_type": 0, 36 | "price_limit": "满30可用", 37 | "logo_url": "" 38 | }, { 39 | "coupon_sign": "", 40 | "status": 3, 41 | "shipping_type": 0, 42 | "coupon_id": -11, 43 | "coupon_key": "", 44 | "coupon_type": 1, 45 | "steal_status": 0, 46 | "poi_exchanged_coupon": 0, 47 | "poi_id": 0, 48 | "amount": 4.0, 49 | "id": -11, 50 | "disable_descriptions": [], 51 | "title": "通用红包", 52 | "use_limits": "限非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 53 | "valid_time_desc": "有效期至2018.09.23", 54 | "coupon_view_id": "KwKtsBvsPOkwK&source=tsid=OkPBsPtsw", 55 | "is_premium_type": false, 56 | "category_type": 0, 57 | "price_limit": "满20可用", 58 | "logo_url": "" 59 | }, { 60 | "coupon_sign": "", 61 | "status": 3, 62 | "shipping_type": 0, 63 | "coupon_id": -11, 64 | "coupon_key": "", 65 | "coupon_type": 1, 66 | "steal_status": 0, 67 | "poi_exchanged_coupon": 0, 68 | "poi_id": 0, 69 | "amount": 4.0, 70 | "id": -11, 71 | "disable_descriptions": [], 72 | "title": "狂欢月专属红包", 73 | "use_limits": "限仅限外卖狂欢月部分指定商户可用,微信小程序,非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 74 | "valid_time_desc": "有效期至2018.09.22", 75 | "coupon_view_id": "PvyvyvyyAPPOk&source=tsid=OkPBvyvaP", 76 | "is_premium_type": false, 77 | "category_type": 0, 78 | "price_limit": "满20可用", 79 | "logo_url": "" 80 | }, { 81 | "coupon_sign": "", 82 | "status": 3, 83 | "shipping_type": 0, 84 | "coupon_id": -11, 85 | "coupon_key": "", 86 | "coupon_type": 1, 87 | "steal_status": 0, 88 | "poi_exchanged_coupon": 0, 89 | "poi_id": 0, 90 | "amount": 4.0, 91 | "id": -11, 92 | "disable_descriptions": [], 93 | "title": "狂欢月专属红包", 94 | "use_limits": "限仅限外卖狂欢月部分指定商户可用,微信小程序,非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 95 | "valid_time_desc": "有效期至2018.09.21", 96 | "coupon_view_id": "ssPyAtsPBPPBv&source=tsid=OkPBvavat", 97 | "is_premium_type": false, 98 | "category_type": 0, 99 | "price_limit": "满20可用", 100 | "logo_url": "" 101 | }, { 102 | "coupon_sign": "", 103 | "status": 3, 104 | "shipping_type": 0, 105 | "coupon_id": -11, 106 | "coupon_key": "", 107 | "coupon_type": 1, 108 | "steal_status": 0, 109 | "poi_exchanged_coupon": 0, 110 | "poi_id": 0, 111 | "amount": 4.0, 112 | "id": -11, 113 | "disable_descriptions": [], 114 | "title": "通用红包", 115 | "use_limits": "限非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 116 | "valid_time_desc": "有效期至2018.09.20", 117 | "coupon_view_id": "KPPPByAwKBvvy&source=tsid=OkPBPPyAw", 118 | "is_premium_type": false, 119 | "category_type": 0, 120 | "price_limit": "满20可用", 121 | "logo_url": "" 122 | }, { 123 | "coupon_sign": "", 124 | "status": 3, 125 | "shipping_type": 0, 126 | "coupon_id": -11, 127 | "coupon_key": "", 128 | "coupon_type": 1, 129 | "steal_status": 0, 130 | "poi_exchanged_coupon": 0, 131 | "poi_id": 0, 132 | "amount": 4.0, 133 | "id": -11, 134 | "disable_descriptions": [], 135 | "title": "狂欢月专属红包", 136 | "use_limits": "限仅限外卖狂欢月部分指定商户可用,微信小程序,非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 137 | "valid_time_desc": "有效期至2018.09.20", 138 | "coupon_view_id": "yPBwKOkPByAts&source=tsid=OkPBPPsPv", 139 | "is_premium_type": false, 140 | "category_type": 0, 141 | "price_limit": "满20可用", 142 | "logo_url": "" 143 | }, { 144 | "coupon_sign": "", 145 | "status": 3, 146 | "shipping_type": 0, 147 | "coupon_id": -11, 148 | "coupon_key": "", 149 | "coupon_type": 1, 150 | "steal_status": 0, 151 | "poi_exchanged_coupon": 0, 152 | "poi_id": 0, 153 | "amount": 1.0, 154 | "id": -11, 155 | "disable_descriptions": [], 156 | "title": "夜宵红包", 157 | "use_limits": "限非到店自取订单,21:00-23:59、00:00-05:00,夜宵频道使用。限登录和收餐手机号为15214313256使用。", 158 | "valid_time_desc": "有效期至2018.09.20", 159 | "coupon_view_id": "syAwKBvyAtsyA&source=tsid=OkPBBvvyt", 160 | "is_premium_type": false, 161 | "category_type": 0, 162 | "price_limit": "满40可用", 163 | "logo_url": "" 164 | }, { 165 | "coupon_sign": "", 166 | "status": 3, 167 | "shipping_type": 0, 168 | "coupon_id": -11, 169 | "coupon_key": "", 170 | "coupon_type": 1, 171 | "steal_status": 0, 172 | "poi_exchanged_coupon": 0, 173 | "poi_id": 0, 174 | "amount": 4.0, 175 | "id": -11, 176 | "disable_descriptions": [], 177 | "title": "狂欢月专属红包", 178 | "use_limits": "限仅限外卖狂欢月部分指定商户可用,微信小程序,非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 179 | "valid_time_desc": "有效期至2018.09.19", 180 | "coupon_view_id": "APPOkPByAsPBv&source=tsid=OkPBPBvay", 181 | "is_premium_type": false, 182 | "category_type": 0, 183 | "price_limit": "满20可用", 184 | "logo_url": "" 185 | }, { 186 | "coupon_sign": "", 187 | "status": 3, 188 | "shipping_type": 0, 189 | "coupon_id": -11, 190 | "coupon_key": "", 191 | "coupon_type": 1, 192 | "steal_status": 0, 193 | "poi_exchanged_coupon": 0, 194 | "poi_id": 0, 195 | "amount": 3.0, 196 | "id": -11, 197 | "disable_descriptions": [], 198 | "title": "狂欢月专属红包", 199 | "use_limits": "限仅限外卖狂欢月部分指定商户可用,微信小程序,非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 200 | "valid_time_desc": "有效期至2018.09.18", 201 | "coupon_view_id": "BwKyAPByAyAyA&source=tsid=OkPBOkPBP", 202 | "is_premium_type": false, 203 | "category_type": 0, 204 | "price_limit": "满20可用", 205 | "logo_url": "" 206 | }, { 207 | "coupon_sign": "", 208 | "status": 3, 209 | "shipping_type": 0, 210 | "coupon_id": -11, 211 | "coupon_key": "", 212 | "coupon_type": 1, 213 | "steal_status": 0, 214 | "poi_exchanged_coupon": 0, 215 | "poi_id": 0, 216 | "amount": 3.0, 217 | "id": -11, 218 | "disable_descriptions": [], 219 | "title": "狂欢月专属红包", 220 | "use_limits": "限仅限外卖狂欢月部分指定商户可用,微信小程序,非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 221 | "valid_time_desc": "有效期至2018.09.17", 222 | "coupon_view_id": "ysPvyyAwKvayA&source=tsid=OkPBOkOkv", 223 | "is_premium_type": false, 224 | "category_type": 0, 225 | "price_limit": "满20可用", 226 | "logo_url": "" 227 | }] 228 | }, 229 | "code": 0, 230 | "msg": "成功" 231 | } 232 | 233 | export {dataList} -------------------------------------------------------------------------------- /src/pages/expiredRedPacket/index.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 49 | 50 | 139 | -------------------------------------------------------------------------------- /src/pages/expiredRedPacket/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-18 14:29:11 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/expiredRedPacket/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "美团红包" 3 | } -------------------------------------------------------------------------------- /src/pages/feedback/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | 17 | -------------------------------------------------------------------------------- /src/pages/feedback/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-25 17:10:23 */ 2 | 3 | import Vue from 'vue' 4 | import App from './index' 5 | 6 | const app = new Vue(App) 7 | app.$mount() -------------------------------------------------------------------------------- /src/pages/feedback/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "美团外卖" 3 | } -------------------------------------------------------------------------------- /src/pages/home/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-14 20:16:03 */ 2 | import Vue from 'vue' 3 | import App from '.' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/home/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "仿美团外卖" 3 | } -------------------------------------------------------------------------------- /src/pages/index/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 75 | 76 | 114 | -------------------------------------------------------------------------------- /src/pages/index/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './index' 3 | 4 | const app = new Vue(App) 5 | app.$mount() 6 | -------------------------------------------------------------------------------- /src/pages/me/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 90 | 91 | 177 | -------------------------------------------------------------------------------- /src/pages/me/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-18 10:13:17 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/me/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarBackgroundColor": "#FFD26B", 3 | "navigationBarTextStyle": "black", 4 | "navigationBarTitleText": "我的", 5 | "backgroundColor": "#eeeeee", 6 | "backgroundTextStyle": "light" 7 | } -------------------------------------------------------------------------------- /src/pages/orderDetail/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /src/pages/orderDetail/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-19 20:13:22 */ 2 | 3 | import Vue from 'vue' 4 | import App from './index' 5 | 6 | const app = new Vue(App) 7 | app.$mount() -------------------------------------------------------------------------------- /src/pages/orderDetail/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "订单详情" 3 | } -------------------------------------------------------------------------------- /src/pages/orderList/index.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 53 | 54 | 155 | -------------------------------------------------------------------------------- /src/pages/orderList/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-17 23:39:29 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/orderList/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "订单" 3 | } -------------------------------------------------------------------------------- /src/pages/pickProtocol/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | 17 | -------------------------------------------------------------------------------- /src/pages/pickProtocol/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-26 23:28:01 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/pickProtocol/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "到店自取用户协议" 3 | } -------------------------------------------------------------------------------- /src/pages/protocol/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | 17 | -------------------------------------------------------------------------------- /src/pages/protocol/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-25 17:10:23 */ 2 | 3 | import Vue from 'vue' 4 | import App from './index' 5 | 6 | const app = new Vue(App) 7 | app.$mount() -------------------------------------------------------------------------------- /src/pages/protocol/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "协议及说明" 3 | } -------------------------------------------------------------------------------- /src/pages/redPacket/data.js: -------------------------------------------------------------------------------- 1 | const redPacket = { 2 | "data": { 3 | "show_steal_entry": 0, 4 | "page_size": 20, 5 | "vp_entrance": { 6 | "text": "", 7 | "bg_url": "", 8 | "sub_text": "", 9 | "link": "", 10 | "buy_status": 0, 11 | "icon_url": "", 12 | "show": false 13 | }, 14 | "page_index": 0, 15 | "coupon_total_num": 4, 16 | "has_more": 0, 17 | "coupon_list": [{ 18 | "coupon_sign": "", 19 | "status": 1, 20 | "shipping_type": 0, 21 | "coupon_id": -11, 22 | "coupon_key": "", 23 | "coupon_type": 1, 24 | "steal_status": 0, 25 | "poi_exchanged_coupon": 0, 26 | "poi_id": 0, 27 | "amount": 6.0, 28 | "id": -11, 29 | "disable_descriptions": [], 30 | "title": "通用红包", 31 | "use_limits": "限非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 32 | "valid_time_desc": "有效期至2018.09.25", 33 | "coupon_view_id": "syAPBsPPPvyPP&source=tsid=OkPPOkPBt", 34 | "is_premium_type": false, 35 | "category_type": 0, 36 | "price_limit": "满34可用", 37 | "logo_url": "" 38 | }, { 39 | "coupon_sign": "", 40 | "status": 1, 41 | "shipping_type": 0, 42 | "coupon_id": -11, 43 | "coupon_key": "", 44 | "coupon_type": 1, 45 | "steal_status": 0, 46 | "poi_exchanged_coupon": 0, 47 | "poi_id": 0, 48 | "amount": 6.0, 49 | "id": -11, 50 | "disable_descriptions": [], 51 | "title": "狂欢月专属红包", 52 | "use_limits": "限仅限外卖狂欢月部分指定商户可用,微信小程序,非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 53 | "valid_time_desc": "有效期至2018.09.25", 54 | "coupon_view_id": "PtsPBPPtsBvBv&source=tsid=OkPPwKvyP", 55 | "is_premium_type": false, 56 | "category_type": 0, 57 | "price_limit": "满30可用", 58 | "logo_url": "" 59 | }, { 60 | "coupon_sign": "", 61 | "status": 1, 62 | "shipping_type": 0, 63 | "coupon_id": -11, 64 | "coupon_key": "", 65 | "coupon_type": 1, 66 | "steal_status": 0, 67 | "poi_exchanged_coupon": 0, 68 | "poi_id": 0, 69 | "amount": 6.0, 70 | "id": -11, 71 | "disable_descriptions": [], 72 | "title": "狂欢月专属红包", 73 | "use_limits": "限仅限外卖狂欢月部分指定商户可用,微信小程序,非到店自取订单使用。限登录和收餐手机号为15214313256使用。", 74 | "valid_time_desc": "有效期至2018.09.24", 75 | "coupon_view_id": "yOkPPvavyPBsP&source=tsid=OkPPwKtsv", 76 | "is_premium_type": false, 77 | "category_type": 0, 78 | "price_limit": "满30可用", 79 | "logo_url": "" 80 | }, { 81 | "coupon_sign": "", 82 | "status": 1, 83 | "shipping_type": 0, 84 | "coupon_id": -11, 85 | "coupon_key": "", 86 | "coupon_type": 1, 87 | "steal_status": 0, 88 | "poi_exchanged_coupon": 0, 89 | "poi_id": 0, 90 | "amount": 6.0, 91 | "id": -11, 92 | "disable_descriptions": [], 93 | "title": "到店自取专享红包", 94 | "use_limits": "限到店自取订单使用。限登录和收餐手机号为15214313256使用。", 95 | "valid_time_desc": "有效期至2018.09.27", 96 | "coupon_view_id": "PwKvavaPPyABv&source=tsid=OkPBsPsPP", 97 | "is_premium_type": false, 98 | "category_type": 0, 99 | "price_limit": "满30可用", 100 | "logo_url": "" 101 | }] 102 | }, 103 | "code": 0, 104 | "msg": "成功" 105 | } 106 | 107 | export {redPacket} -------------------------------------------------------------------------------- /src/pages/redPacket/index.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 56 | 57 | 151 | -------------------------------------------------------------------------------- /src/pages/redPacket/main.js: -------------------------------------------------------------------------------- 1 | /** Created by guangqiang on 2018-09-18 11:05:33 */ 2 | import Vue from 'vue' 3 | import App from './index' 4 | 5 | const app = new Vue(App) 6 | app.$mount() -------------------------------------------------------------------------------- /src/pages/redPacket/main.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "美团红包" 3 | } -------------------------------------------------------------------------------- /src/pages/remark/index.vue: -------------------------------------------------------------------------------- 1 |