Rorschach 3 years ago
commit
418b48face
19 changed files with 10965 additions and 0 deletions
  1. 24 0
      .gitignore
  2. 17 0
      README.md
  3. 10183 0
      package-lock.json
  4. 48 0
      package.json
  5. 4 0
      postcss.config.js
  6. 12 0
      src/about.html
  7. 1 0
      src/about.js
  8. 6 0
      src/helper/const.js
  9. 41 0
      src/helper/response.js
  10. 17 0
      src/helper/utils.js
  11. BIN
      src/img/buy.png
  12. BIN
      src/img/choose.png
  13. BIN
      src/img/grey.png
  14. BIN
      src/img/wx_icon.png
  15. BIN
      src/img/zfb_icon.png
  16. 72 0
      src/index.html
  17. 157 0
      src/index.js
  18. 239 0
      src/index.less
  19. 144 0
      webpack.config.js

+ 24 - 0
.gitignore

@@ -0,0 +1,24 @@
+.DS_Store
+node_modules
+/dist
+/build
+
+/sign/release
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw*

+ 17 - 0
README.md

@@ -0,0 +1,17 @@
+### 义方小学堂h5活动购买页
+
+```
+npm install
+```
+
+### 打包命令
+``` 
+
+npm run build 
+```
+
+### 本地调试
+```
+
+npm run server 
+ ```

File diff suppressed because it is too large
+ 10183 - 0
package-lock.json


+ 48 - 0
package.json

@@ -0,0 +1,48 @@
+{
+  "name": "efunbox-xxt-buy-web",
+  "version": "1.0.0",
+  "description": "",
+  "main": "webpack.config.js",
+  "dependencies": {
+    "expose-loader": "^0.7.5",
+    "jquery": "^3.4.1",
+    "jquery.cookie": "^1.4.1"
+  },
+  "browserslist": [
+    "defaults",
+    "not ie <= 8",
+    "last 2 versions",
+    "> 1%",
+    "iOS >= 7",
+    "Android >= 4.0"
+  ],
+  "devDependencies": {
+    "@babel/core": "^7.8.7",
+    "@babel/preset-env": "^7.8.7",
+    "autoprefixer": "^9.7.4",
+    "babel-loader": "^8.0.6",
+    "css-loader": "^3.4.2",
+    "file-loader": "^5.1.0",
+    "html-loader": "^0.5.5",
+    "html-webpack-plugin": "^3.2.0",
+    "less": "^3.11.1",
+    "less-loader": "^5.0.0",
+    "mini-css-extract-plugin": "^0.9.0",
+    "optimize-css-assets-webpack-plugin": "^5.0.3",
+    "postcss-loader": "^3.0.0",
+    "style-loader": "^1.1.3",
+    "terser-webpack-plugin": "^2.3.5",
+    "uglifyjs-webpack-plugin": "^2.2.0",
+    "url-loader": "^3.0.0",
+    "webpack": "^4.42.0",
+    "webpack-cli": "^3.3.11",
+    "webpack-dev-server": "^3.10.3"
+  },
+  "scripts": {
+    "build": "webpack",
+    "dev": "webpack-dev-server",
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "ISC"
+}

+ 4 - 0
postcss.config.js

@@ -0,0 +1,4 @@
+// 自动加前缀
+module.exports = {
+    plugins:[require('autoprefixer')]
+}

+ 12 - 0
src/about.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Document</title>
+</head>
+<body>
+    <div class="asd">asdfasdf啊时代步伐说不定就哈佛</div>
+    
+</body>
+</html>

+ 1 - 0
src/about.js

@@ -0,0 +1 @@
+console.log(11,22,33)

+ 6 - 0
src/helper/const.js

@@ -0,0 +1,6 @@
+export default class url {
+    static composeApiPath(apiName) {
+      const requestBaseUrl = 'https://xxtbfd-api.ai160.com/'
+      return `${requestBaseUrl}${apiName}`
+    }
+  }

+ 41 - 0
src/helper/response.js

@@ -0,0 +1,41 @@
+(function(designWidth, maxWidth) {
+    var doc = document,
+        win = window,
+        docEl = doc.documentElement,
+        remStyle = document.createElement("style"),
+        tid;
+
+    function refreshRem() {
+        var width = docEl.getBoundingClientRect().width;
+        maxWidth = maxWidth || 540;
+        width > maxWidth && (width = maxWidth);
+        var rem = width * 100 / designWidth;
+        remStyle.innerHTML = "html{font-size:" + rem + "px;}"
+    }
+    if (docEl.firstElementChild) {
+        docEl.firstElementChild.appendChild(remStyle)
+    } else {
+        var wrap = doc.createElement("div");
+        wrap.appendChild(remStyle);
+        doc.write(wrap.innerHTML);
+        wrap = null
+    }
+    refreshRem();
+    win.addEventListener("resize", function() {
+        clearTimeout(tid);
+        tid = setTimeout(refreshRem, 300)
+    }, false);
+    win.addEventListener("pageshow", function(e) {
+        if (e.persisted) {
+            clearTimeout(tid);
+            tid = setTimeout(refreshRem, 300)
+        }
+    }, false);
+    if (doc.readyState === "complete") {
+        doc.body.style.fontSize = "16px"
+    } else {
+        doc.addEventListener("DOMContentLoaded", function(e) {
+            doc.body.style.fontSize = "16px"
+        }, false)
+    }
+})(750, 750);

+ 17 - 0
src/helper/utils.js

@@ -0,0 +1,17 @@
+export default class Utils {
+    static GetQueryString(name) {
+        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
+        var r = window.location.search.substr(1).match(reg);
+        if (r != null) return unescape(r[2]);
+        return null;
+    }
+}
+
+// a = {
+//     "body": "义方快乐学堂12个月VIP会员",
+//     "out_trade_no": "497b828ec0cc448fb7ce03650d3930d9",
+//     "product_code": "QUICK_WAP_WAY",
+//     "subject": "义方快乐学堂12个月VIP会员",
+//     "timeout_express": "30m",
+//     "total_amount": "299"
+// }

BIN
src/img/buy.png


BIN
src/img/choose.png


BIN
src/img/grey.png


BIN
src/img/wx_icon.png


BIN
src/img/zfb_icon.png


+ 72 - 0
src/index.html

@@ -0,0 +1,72 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>VIP购买</title>
+</head>
+
+<body>
+    <div class="container">
+        <div class="product-box">
+            <div class="product-title">套餐选择</div>
+
+            <!-- <div class="product-list">
+                <div class="item focus" onclick="choose">
+                    <span class="time">12个月</span>
+                    <span class="price">¥199元</span>
+                    <span class="origin-price">原价: ¥499元</span>
+                </div>
+                <div class="item" onclick="choose">
+                    <span class="time">12个月</span>
+                    <span class="price">¥199元</span>
+                    <span class="origin-price">原价: ¥499元</span>
+                </div>
+                <div class="item" onclick="choose">
+                    <span class="time">12个月</span>
+                    <span class="price">¥199元</span>
+                    <span class="origin-price">原价: ¥499元</span>
+                </div>
+            </div> -->
+        </div>
+        <div class="pay-way">
+            <div class="pay-title">选择支付方式</div>
+            <div class="pay-item wx-pay">
+                <div class="left-box">
+                    <img src='./img/wx_icon.png' class="wx-img">
+                    <span class="pay-name">微信支付</span>
+                </div>
+                <span class="wx-choose pay-choose"></span>
+            </div>
+            <div class="pay-item zfb-pay">
+                <div class="left-box">
+                    <img src='./img/zfb_icon.png' class="zfb-img">
+                    <span class="pay-name">支付宝支付</span>
+                </div>
+                <span class="zfb-choose pay-choose"></span>
+            </div>
+        </div>
+        <div class="footer">
+            <div class="left">
+               支付
+                <span class="pay-price">199</span>
+                
+            </div>
+            <div class="pay-btn">支付</div>
+        </div>
+    </div>
+    <div class="buy-dialog">
+        <div class="box">
+            <!-- <img src="img/buy.png"> -->
+            <div class="title">是否已完成支付</div>
+            <div class="bottom">
+                <div class="yes">已支付</div>
+                <div class="no">未支付</div>
+            </div>
+        </div>
+    </div>
+</body>
+
+</html>
+

+ 157 - 0
src/index.js

@@ -0,0 +1,157 @@
+require('./index.less');
+import 'jquery.cookie'
+import './helper/response';
+import Api from './helper/const';
+import Utils from './helper/utils';
+
+const channel = Utils.GetQueryString('channel');
+const uid = Utils.GetQueryString('uid');
+let payWay = 'wx';
+let productId = '';
+
+const getStatus = (orderId) => {
+    // 查询是否成功
+    $.ajax({
+        url: Api.composeApiPath(`order/${orderId}`),
+        dataType: "json",
+        async: true,
+        headers: {
+            uid: uid
+        },
+        type: "GET",
+        success: function (res) {
+            $.removeCookie('orderId');
+            $.removeCookie('isPayBack');
+            if ($.cookie('isWx')) {
+                $.removeCookie('isWx');
+                $('.buy-dialog').css('display', 'none')
+            }
+            if (res.data.status === 2) {
+                console.log('支付成功')
+                system.postMessage('success')
+            } else {
+                console.log('支付失败')
+                system.postMessage('close')
+            }
+        }
+    });
+}
+// 默认微信支付
+$('.wx-choose').addClass('choose');
+$.ajax({
+    url: Api.composeApiPath('order/product'),
+    dataType: "json",
+    async: true,
+    data: {
+        "channel": channel
+    },
+    headers: {
+        uid: uid
+    },
+    type: "GET",
+    success: function (res) {
+        renderProductList(res.data)
+    }
+});
+
+// 渲染页面
+const renderProductList = (list) => {
+    const box = $("<div class='product-list'></div>")
+    list.forEach((item, index) => {
+        if (index === 0) {
+            productId = item.id;
+            $('.pay-price').html(`¥${item.price / 100}元`)
+
+        }
+        box.append(
+            $(`<div data-price="${item.price / 100}" data-id="${item.id}" class="item ${index === 0 ? 'focus' : ''}">
+            <span class="time">${item.payType === 'YEAR' ? '12个月':item.payType === 'MONTH'?'1个月':'连续包月'}</span>
+            <span class="price">¥${item.price / 100}元</span>
+            <span class="origin-price">原价: ¥${item.originalPrice / 100}元</span>
+        </div>`).on('click', chooseProduct)
+        )
+    })
+    $('.product-box').append(box);
+}
+// 修改支付方式
+const changePayWay = (flag) => {
+    // if (typeof system !== 'undefined') {
+    //     system.postMessage(window.location.search)
+    // }
+    if (flag === 'wx' && payWay !== 'wx') {
+        payWay = 'wx';
+        $('.zfb-choose').removeClass('choose');
+        $('.wx-choose').addClass('choose');
+    }
+    if (flag === 'zfb' && payWay !== 'zfb') {
+        payWay = 'zfb';
+        $('.wx-choose').removeClass('choose');
+        $('.zfb-choose').addClass('choose');
+    }
+}
+// 生成订单
+const createOrder = (method, id) => {
+    let str = method === 'zfb' ? '/aliPay/prePay' : '/wxPay/prePay';
+    $.ajax({
+        url: Api.composeApiPath(str),
+        dataType: "json",
+        async: true,
+        data: JSON.stringify({
+            "channel": channel,
+            "productId": id
+        }),
+        type: "POST",
+        headers: {
+            uid: uid
+        },
+        contentType: "application/json",
+        success: res => {
+            $.cookie('orderId', res.data.orderId);
+            $.cookie('isPayBack', 1);
+            if (method === 'zfb') {
+                $('body').append(
+                    $(`<div>${res.data.payInfo}</div>`)
+                )
+            } else if (method === 'wx') {
+                $.cookie('isWx', 1);
+                window.location.href = res.data.payInfo
+            }
+        }
+    });
+}
+
+const chooseProduct = (e) => {
+    e.stopPropagation();
+    $('.item').removeClass('focus');
+    $(e.currentTarget).addClass('focus');
+    productId = e.currentTarget.dataset.id.toString();
+    $('.pay-price').html(`¥${e.currentTarget.dataset.price}元`)
+
+}
+
+// 绑定事件
+$(document).ready(() => {
+    if ($.cookie('isPayBack') === '1' && $.cookie('isWx') === '1') {
+        $('.buy-dialog').css('display', 'flex')
+    }
+    if (Utils.GetQueryString('payBack') === '1') {
+        getStatus($.cookie('orderId'))
+    }
+    $('.wx-pay').on('click', () => {
+        changePayWay('wx');
+    });
+    $('.zfb-pay').on('click', () => {
+        changePayWay('zfb');
+    });
+    $('.pay-btn').on('click', () => {
+        if (payWay && productId) {
+            createOrder(payWay, productId)
+        }
+    });
+    $('.yes').on('click', () => {
+        getStatus($.cookie('orderId'))
+    });
+    $('.no').on('click', () => {
+        getStatus($.cookie('orderId'))
+    });
+});

+ 239 - 0
src/index.less

@@ -0,0 +1,239 @@
+html,
+body {
+    margin: 0;
+    border: none;
+    padding: 0;
+}
+
+.asd {
+    font-size: 100px;
+}
+
+.container {
+    width: 100%;
+    height: 100%;
+    background: #eee;
+
+    .product-box {
+        width: 100%;
+        background: #fff;
+        margin-bottom: .4rem;
+
+        .product-title {
+            width: 100%;
+            height: 1.4rem;
+            line-height: 1.4rem;
+            color: #a8674d;
+            font-size: .4rem;
+            text-align: center;
+        }
+
+        .product-list {
+            width: 100%;
+            padding-bottom: .5rem;
+
+            .item {
+                width: 6.48rem;
+                height: 1.06rem;
+                border-radius: .53rem;
+                background: #fff;
+                border: .02rem solid rgb(168, 103, 77);
+                color: #a8674d;
+                box-sizing: border-box;
+                display: flex;
+                flex-direction: row;
+                align-items: center;
+                justify-content: space-around;
+                margin: 0 auto .4rem;
+
+                &.focus {
+                    background: #f5880d;
+
+                    border: none;
+                    color: #fff;
+                }
+
+                .time {
+                    font-size: .36rem;
+                }
+
+                .price {
+                    font-size: .4rem;
+                }
+
+                .origin-price {
+                    font-size: .28rem;
+                }
+            }
+        }
+    }
+
+    .pay-way {
+        width: 100%;
+        background: #fff;
+
+        .pay-title {
+            width: 6.82rem;
+            height: 1.05rem;
+            border-bottom: .02rem solid #e4e4e4;
+            text-align: center;
+            margin: 0 auto;
+            line-height: 1.05rem;
+            color: #191919;
+            font-size: .32rem;
+
+        }
+
+        .pay-item {
+            width: 6.82rem;
+            height: 1rem;
+            border-bottom: .02rem solid #e4e4e4;
+            margin: 0 auto;
+            display: flex;
+            align-items: center;
+            justify-content: space-between;
+
+            .left-box {
+                display: flex;
+                align-items: center;
+
+                .wx-img {
+                    width: 0.58rem;
+                    height: 0.5rem;
+
+                }
+
+                .zfb-img {
+                    width: 0.56rem;
+                    height: 0.56rem;
+
+                }
+
+                .pay-name {
+                    color: #191919;
+                    margin-left: .34rem;
+                    font-size: .28rem;
+                }
+            }
+
+            .pay-choose {
+                float: right;
+                width: 0.48rem;
+                height: 0.48rem;
+                background: url('./img/grey.png') no-repeat;
+                background-size: 100%;
+
+                &.choose {
+                    background: url('./img/choose.png') no-repeat;
+                    background-size: 100%;
+                }
+            }
+
+        }
+    }
+
+    .footer {
+        width: 100%;
+        height: 1.2rem;
+        position: fixed;
+        left: 0;
+        bottom: 0;
+        display: flex;
+        flex-direction: row;
+        align-items: center;
+        box-shadow: 0px -2px 8px 0px rgba(0, 0, 0, 0.18);
+
+        .left {
+            width: 59%;
+            height: 100%;
+            font-size: .32rem;
+            color: #a8674d;
+            text-indent: .5rem;
+            display: flex;
+            align-items: center;
+
+            span {
+                font-size: .4rem;
+                text-indent: 0;
+            }
+        }
+
+        .pay-btn {
+            width: 41%;
+            height: 100%;
+            background: #f5880d;
+            text-align: center;
+            line-height: 100%;
+            font-size: .4rem;
+            color: #fff;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+    }
+
+
+
+}
+
+.buy-dialog {
+    width: 100%;
+    height: 100%;
+    background: rgba(0, 0, 0, .8);
+    display: none;
+    justify-content: center;
+    align-items: center;
+    position: absolute;
+    top: 0;
+
+    .box {
+        width: 5.5rem;
+        height: 3.54rem;
+        background: rgba(255, 255, 255, 1);
+        border-radius: .2rem;
+
+        .title {
+            width: 100%;
+            height: 0.56rem;
+            color: #434343;
+            font-size: .4rem;
+            text-align: center;
+            margin-top: .63rem;
+        }
+
+        .bottom {
+            width: 100%;
+            display: flex;
+            align-items: center;
+            justify-content: space-around;
+            margin-top: .98rem;
+
+            .yes {
+                width: 2.51rem;
+                height: .84rem;
+                background: rgba(245, 136, 13, 1);
+                border-radius: .47rem;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                color: #fff;
+                font-size: .36rem;
+            }
+
+            .no {
+                width: 2.51rem;
+                height: .84rem;
+                background: rgba(61, 173, 254, 1);
+                border-radius: .47rem;
+                display: flex;
+                align-items: center;
+                text-align: center;
+                color: #fff;
+                font-size: .36rem;
+                justify-content: center;
+
+            }
+
+        }
+    }
+}

+ 144 - 0
webpack.config.js

@@ -0,0 +1,144 @@
+const path = require('path');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 抽离css,不插入到head标签里
+const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // 压缩css
+const TerserJSPlugin = require('terser-webpack-plugin')
+const webpack = require('webpack');
+
+const htmlPlugin = new HtmlWebpackPlugin({
+    template: './src/index.html',
+    filename: 'index.html',
+    hash: true,
+    minify: {
+        removeAttributeQuotes: true,
+        collapseWhitespace: true
+    }
+});
+
+const aboutPlugin = new HtmlWebpackPlugin({
+    template: './src/about.html',
+    filename: 'about.html',
+    hash: true,
+    minify: {
+        removeAttributeQuotes: true,
+        collapseWhitespace: true
+    }
+});
+/* const htmlPlugin = ['index', 'about'].map(chunkName => {
+   return new HtmlWebpackPlugin({
+        template: `./src/${chunkName}.html`,
+        filename: `${chunkName}.html`,
+        hash: true,
+        chunks: [`./src/${chunkName}`],
+        minify: {
+            removeAttributeQuotes: true,
+            collapseWhitespace: true
+        }
+    });
+}) */
+
+
+
+const miniPlugin = new MiniCssExtractPlugin({
+    filename: 'main.css'
+});
+// 每个模块中注入jq
+const webpackProvidePlugin = new webpack.ProvidePlugin({
+    $: 'jquery',
+})
+
+module.exports = {
+    optimization: {
+        minimize: true, // 开启压缩,默认false
+        minimizer: [
+            new TerserJSPlugin({
+                terserOptions: {
+                    output: {
+                        comments: false // 删除js文件中的注释
+                    }
+                },
+                extractComments: false, // 不将注释提取到单独的文件
+                sourceMap: true // 源码映射
+            }),
+            new OptimizeCSSAssetsPlugin()
+        ]
+    },
+    devServer: {
+        // port: 3000,
+        // progress: true,
+        contentBase: path.resolve(__dirname, './build'),
+        open: true,
+        host: '127.0.0.1'
+    },
+    mode: 'development', // development production
+    entry: {
+        index: './src/index.js',
+        about: './src/about.js'
+    },
+    output: {
+        filename: '[name].bundle.js',
+        path: path.resolve(__dirname, 'dist'),
+    },
+
+    plugins: [
+        miniPlugin,
+        htmlPlugin,
+        aboutPlugin,
+        webpackProvidePlugin
+    ],
+    module: {
+        rules: [{
+                test: /\.(html)$/, // html文件中img标签src没有被打包的问题
+                use: {
+                    loader: 'html-loader',
+                    options: {
+                        attrs: ['img:src', 'img:data-src', 'audio:src'],
+                        minimize: true
+                    }
+                }
+            },
+            {
+                test: /\.(png|jpg)$/,
+                use: [{
+                    loader: 'url-loader',
+                    options: {
+                        limit: 1,
+                        esModule: false,
+                        outputPath: 'img/'
+                    }
+
+                }]
+            },
+            {
+                test: /\.js$/,
+                use: {
+                    loader: 'babel-loader',
+                    options: {
+                        presets: [
+                            '@babel/preset-env'
+                        ]
+                    }
+                },
+                include: path.resolve(__dirname, 'src'),
+                exclude: /node_modules/
+            },
+            {
+                test: /\.css$/,
+                use: [
+                    MiniCssExtractPlugin.loader,
+                    'css-loader',
+                    'postcss-loader'
+                ]
+            },
+            {
+                test: /\.less$/,
+                use: [
+                    MiniCssExtractPlugin.loader,
+                    'css-loader',
+                    'less-loader',
+                    'postcss-loader',
+                ]
+            }
+        ]
+    }
+}