ソースを参照

Merge branch 'rel-master'

feat
JinxChen 1年前
コミット
afa3b61b80
48個のファイルの変更3166行の追加2232行の削除
  1. +2
    -2
      .env.development
  2. +1
    -1
      .env.production
  3. +2
    -2
      .env.test
  4. +31
    -31
      .eslintrc.js
  5. +0
    -32
      .postcssrc.js
  6. +165
    -64
      README.md
  7. +0
    -36
      antpay_frontend_web_run.sh
  8. +2
    -2
      babel.config.js
  9. +37
    -0
      h5_frontend_web_run.sh
  10. +783
    -37
      package-lock.json
  11. +9
    -4
      package.json
  12. +3
    -3
      public/index.html
  13. +11
    -12
      setup_development.sh
  14. +9
    -10
      setup_production.sh
  15. +9
    -9
      setup_test.sh
  16. +6
    -4
      src/App.vue
  17. +0
    -52
      src/api/alipay.js
  18. +79
    -0
      src/api/core.js
  19. +57
    -0
      src/api/pay.js
  20. +49
    -0
      src/api/wx.js
  21. +125
    -0
      src/assets/css/public.scss
  22. +323
    -0
      src/assets/css/reset.scss
  23. バイナリ
      src/assets/img/dealers_form_banner.jpg
  24. バイナリ
      src/assets/img/ssjl.jpg
  25. +0
    -144
      src/components/AgreementDialog.vue
  26. +0
    -76
      src/components/Checkbox.vue
  27. +0
    -13
      src/config/customize.js
  28. +2
    -2
      src/config/models.js
  29. +70
    -0
      src/http/java_api.js
  30. +1
    -1
      src/http/request.js
  31. +58
    -0
      src/http/webapi.js
  32. +88
    -47
      src/main.js
  33. +6
    -12
      src/router/index.js
  34. +64
    -37
      src/store/index.js
  35. +5
    -4
      src/store/prefix.js
  36. +40
    -1
      src/utils/index.js
  37. +0
    -268
      src/views/AliPayForm.vue
  38. +0
    -535
      src/views/AliPayIndex.vue
  39. +0
    -36
      src/views/AliPayRedirect.vue
  40. +0
    -173
      src/views/AliPayResult.vue
  41. +0
    -46
      src/views/ComponentsTest.vue
  42. +0
    -501
      src/views/chunyu/AliPayForm.vue
  43. +28
    -0
      src/views/index.vue
  44. +117
    -0
      src/views/package-home/index.vue
  45. +563
    -0
      src/views/package-list/index.vue
  46. +0
    -32
      src/views/page-not-found/index.vue
  47. +386
    -0
      src/views/pay-result/index.vue
  48. +35
    -3
      vue.config.js

+ 2
- 2
.env.development ファイルの表示

@@ -1,4 +1,4 @@
NODE_ENV= development
# base api
VUE_APP_BASE_API = 'https://id.ssjlai.com/telpopay'
#VUE_APP_BASE_API = 'https://ai.ssjlai.com/telpopay'
VUE_APP_BASE_API = 'https://id.ssjlai.com/'
#VUE_APP_BASE_API = 'https://ai.ssjlai.com/'

+ 1
- 1
.env.production ファイルの表示

@@ -1,3 +1,3 @@
NODE_ENV= production
# base api
VUE_APP_BASE_API = 'https://ai.ssjlai.com/telpopay'
VUE_APP_BASE_API = 'https://ai.ssjlai.com/'

+ 2
- 2
.env.test ファイルの表示

@@ -1,4 +1,4 @@
NODE_ENV= test
# base api
VUE_APP_BASE_API = 'https://id.ssjlai.com/telpopay'
#VUE_APP_BASE_API = 'https://ai.ssjlai.com/telpopay'
VUE_APP_BASE_API = 'https://id.ssjlai.com/'
#VUE_APP_BASE_API = 'https://ai.ssjlai.com/'

+ 31
- 31
.eslintrc.js ファイルの表示

@@ -1,33 +1,33 @@
/*
* @Date: 2022-01-19 10:08:26
* @LastEditors: JinxChen
* @LastEditTime: 2022-01-19 10:29:11
* @FilePath: \alipay-scan-code-front-end\.eslintrc.js
* @description:
*/
module.exports = {
root: true,
env: {
node: true,
},
extends: ["plugin:vue/essential", "eslint:recommended", "@vue/prettier"],
parserOptions: {
parser: "babel-eslint",
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "off" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "off" : "off",
"prettier/prettier": "off", //关闭 prettier 验证
},
overrides: [
{
files: [
"**/__tests__/*.{j,t}s?(x)",
"**/tests/unit/**/*.spec.{j,t}s?(x)",
],
env: {
jest: true,
},
root: true,
env: {
node: true,
},
extends: ["plugin:vue/essential", "eslint:recommended", "@vue/prettier"],
parserOptions: {
parser: "babel-eslint",
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
//关闭prettier
"prettier/prettier": "off",
// 关闭eslint语法检测
"no-unused-vars":0,
},
],
};
globals: {
"AMap": "true",
"AMapUI": "true",
},
overrides: [
{
files: [
"**/__tests__/*.{j,t}s?(x)",
"**/tests/unit/**/*.spec.{j,t}s?(x)",
],
env: {
jest: true,
},
},
],
};

+ 0
- 32
.postcssrc.js ファイルの表示

@@ -1,32 +0,0 @@
/*
* @Date: 2022-01-19 10:10:50
* @LastEditors: JinxChen
* @LastEditTime: 2022-01-21 15:57:33
* @FilePath: \alipay-scan-code-front-end\.postcssrc.js
* @description:
*/
const path = require("path");

module.exports = ({ webpack }) => {
const designWidth = webpack.resourcePath.includes(path.join("node_modules", "vant")) ? 375 : 375;
return {
plugins: {
autoprefixer: {},
"postcss-px-to-viewport": {
unitToConvert: "px",
viewportWidth: designWidth,
unitPrecision: 6,
propList: ["*"],
viewportUnit: "vw",
fontViewportUnit: "vw",
selectorBlackList: [],
minPixelValue: 1,
mediaQuery: true,
exclude: [],
landscape: false,
landscapeUnit: 'vw', // 横屏时使用的单位
landscapeWidth: 1125 // 横屏时使用的视口宽度
}
}
};
};

+ 165
- 64
README.md ファイルの表示

@@ -1,89 +1,190 @@
<!--
* @Date: 2022-01-19 10:08:58
* @Date: 2022-08-17 16:19:13
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 15:52:30
* @FilePath: \AntpayFrontEnd\README.md
* @description: 项目说明文档
* @LastEditTime: 2023-02-24 18:49:37
* @FilePath: \TelpoH5FrontendWeb\README.md
* @description: 项目说明
-->
# alipay-scan-code-front-end
## 项目说明
## 这是一个通过支付宝二维码进入的h5
## 项目依赖安装
# telpo-h5-template

## Project setup
```
npm install
```

### 项目运行
### Compiles and hot-reloads for development
```
npm run dev
```

### 项目打包
### Compiles and minifies for production
```
npm run build
```

### 项目本地调试
### Run your tests
```
npm run test
```

### Lints and fixes files
```
运行成功后 本地调试首次进入会进入到 http://localhost:8080/#/404 404页面
因为当前url还没有参数, 此时需要手动在url后面添加需要的参数,
例子: http://localhost:8080/#/index?goodsNo=889&userId=1
其中 goodsNo是商品的no, userId是用户的id, 这两个参数后面接口都会用到
以上在线上环境不需要配置,因为二维码会自动把这两个参数添加上去
npm run lint
```

### 项目代码编写规范(暂时想到这些,后面根据项目情况补充说明)
- css类名: 小写驼峰 中间用 - 隔开
- js函数方法: 开头小写后面开头大写驼峰
- .vue 文件命名: 统一大写驼峰
- 常量命名: 全部大写 以_拼接, 具体例子见: /src/config/models下的文件


### 项目分支管理
- master: 不可在此分支做任何修改, 只能合并develop分支, git merge --no-ff develop ; 且部署上线时对应production环境,不可混肴
- develop: 平时开发使用此分支, 需另开分支并说明是做什么的, 比如fix bug, git checkout -b fix-xxxx, 开发完成自测无问题后合并到develop分支,
- test: 如不必要不在此分支做任何修改, 合并develpo分支, git merge --no-ff develop ; 部署上线时对应test环境,不可混肴

### git 提交规范
- feature 新增一个功能
- bugfix 修复一个
- Bugdocs 文档变更
- style 代码格式(不影响功能,例如空格、分号等格式修正)
- refactor 代码重构
- perf 改善性能
- test 测试
- build 变更项目构建或外部依赖(例如 scopes: webpack、gulp、npm 等)
- ci 更改持续集成软件的配置文件和 package 中的 scripts 命令,例如 scopes: Travis, Circle 等
- chore 变更构建流程或辅助工具
- revert 代码回退

### 版本控制以及版本迭代说明

### v1.0.0
`2022.02.23`
build
- 初版发布
- 完成 项目搭建
- 完成 项目迁移 从documentFrontEndWeb 到 AntpayFrontEnd
- 增加 docker部署脚本
- 增加 环境设置脚本
- 增加 nginx.conf文件
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

# 本项目为天波H5项目
## 版本号管理
- 版本格式:主版本号.次版本号.修订号
1.主版本号:当你做了不兼容的 API 修改( 一般项目发生重大功能改变)
2.次版本号:当你做了向下兼容的功能性新增,
3.修订号:当你做了向下兼容的问题修正。
例如:
- V #1.0.0

##git提交为以下类别
- 1.fix 修复 xxx问题
- 2.feat 增加 xxx功能
- 3.docs 文档变更
- 4.style 代码格式(不影响代码运行的变动)
- 5.perf 性能优化
- 提交格式,比如:
-start---------------
- 版本号 v#1.0.0
- 2022.08.06
fix
- 修改文件名称
- fix 修复了 xxx问题
...

- 后续可根据项目需要更新或者改进
-end------------------------

## v1.0.0
`2022.8.8`
feat
- 增加 项目基本配置

## v1.0.1
`2022.8.18`
feat
- card-form
- 增加 一个表单录入页

## v1.0.2
`2022.8.19`
style
- card-form
- 修改 页面样式

## v1.0.3
`2022.8.19`
feat
- card-form
- 增加 接口

## v1.0.4
`2022.8.20`
feat
- card-form
- 增加 保存失败错误提示

## v1.0.5
`2022.8.20`
fix
- 修复 路由history模式原因引起的页面空白的问题
- card-form
- 修复 保存iccId参数多出来一个的问题

## v1.0.6
`2022.8.23`
feat
- card-form
- 增加 亲情号码六个字段

## v1.0.7
`2022.8.24`
feat
- card-form
- 增加 备注字段

## v1.0.8
`2022.8.25`
feat
- card-form
- 增加 学校名称字段
- 修改 学校名称字段最大长度为30

## v1.0.9
`2022.8.30`
feat
- card-form
- 修复 保存字段错误的问题

## v1.0.10
`2022.8.31`
feat
- card-form
- 增加 年级/班级下拉选择

### v1.0.1
`2022.02.25`

## v1.0.11
`2022.9.9`
feat
- card-form
- 修改 保存接口传参

## v1.0.12
`2022.10.11`
feat
- card-form
- 修改 班级参数

-------------分割线,以下是2023年的readme----------

## v1.0.13
`2023.2.24`
feat
- package-list
- 增加 一个话费套餐购买页面



## v1.0.14
`2023.2.24`
feat
- package-home
- 增加 一个微信授权获取code的首页


## v1.0.15
`2023.2.24`
fix
- package-home
- 修复 微信网页授权重定向错误的问题

## v1.0.16
`2023.2.24`
fix
- package-home
- 修复 微信网页获取openId失败的问题

## v1.0.17
`2023.2.24`
feature
- 增加 非支付宝浏览环境下扫码切换支付宝弹窗提示
- 增加 android和ios设备支付宝下载链接
- 增加 android设备复制粘贴下载链接功能
- pay-result
- 增加 一个微信支付结果查询页面


### v1.0.2
`2022.03.04`
## v1.0.18
`2023.2.24`
feature
- 增加 春雨个性化定制 '@/views/chunyu/AliPayForm'
- 增加 Checkbox 组件, '@/components/checkbox'
- 增加 AgreementDialog 组件, '@/components/AgreementDialog'
- 修复 路由切换页面不刷新的问题



## v1.0.19
`2023.2.25`
fix
- 修复 路由切换页面不刷新的问题

+ 0
- 36
antpay_frontend_web_run.sh ファイルの表示

@@ -1,36 +0,0 @@
#!/bin/bash
###
# @Date: 2021-11-15 09:37:49
# @LastEditors: JinxChen
# @LastEditTime: 2022-03-04 10:47:47
# @FilePath: \AntpayFrontEnd\antpay_frontend_web_run.sh
# @description: docker部署脚本, 根据项目具体情况来 修改 docker run -p 8804:80
###
environment=$1
version=$2
echo "环境变量为${environment},版本为$version!"
if [[ ${environment} = 'production' ]]; then
echo "开始远程构建容器"
docker stop antpay_frontend_web || true;
docker rm antpay_frontend_web || true;
docker rmi -f $(docker images | grep registry.cn-shanghai.aliyuncs.com/gps_card/antpay_frontend_web | awk '{print $3}')
#docker login --username=telpo_linwl@1111649216405698 --password=telpo#1234 registry.cn-shanghai.aliyuncs.com;
docker login --username=rzl_wangjx@1111649216405698 --password=telpo.123 registry.cn-shanghai.aliyuncs.com
docker pull registry.cn-shanghai.aliyuncs.com/gps_card/antpay_frontend_web:$version
docker run -p 8804:80 -d --restart=always --name antpay_frontend_web registry.cn-shanghai.aliyuncs.com/gps_card/antpay_frontend_web:$version;
#删除产生的None镜像
docker rmi -f $(docker images | grep none | awk '{print $3}')
docker ps -a

elif [[ ${environment} == 'test' ]]; then
echo "开始在测试环境远程构建容器"
docker stop antpay_frontend_web || true
docker rm antpay_frontend_web || true
docker rmi -f $(docker images | grep 139.224.254.18:5000/antpay_frontend_web | awk '{print $3}')
docker pull 139.224.254.18:5000/antpay_frontend_web:$version
docker run -p 8804:80 -d --restart=always --name antpay_frontend_web 139.224.254.18:5000/antpay_frontend_web:$version;
#删除产生的None镜像
docker rmi -f $(docker images | grep none | awk '{print $3}')
docker ps -a

fi

+ 2
- 2
babel.config.js ファイルの表示

@@ -1,8 +1,8 @@
/*
* @Date: 2022-01-19 10:08:26
* @LastEditors: JinxChen
* @LastEditTime: 2022-01-19 10:56:39
* @FilePath: \alipay-scan-code-front-end\babel.config.js
* @LastEditTime: 2023-02-25 15:43:27
* @FilePath: \TelpoH5FrontendWeb\babel.config.js
* @description:
*/
module.exports = {


+ 37
- 0
h5_frontend_web_run.sh ファイルの表示

@@ -0,0 +1,37 @@
#!/bin/bash
###
# @Date: 2022-08-18 09:19:07
# @LastEditors: JinxChen
# @LastEditTime: 2022-08-18 10:06:40
# @FilePath: \TelpoH5FrontendWeb\h5_frontend_web_run.sh
# @description: 部署脚本
###

environment=$1
version=$2
echo "环境变量为${environment},版本为$version!"
if [[ ${environment} = 'production' ]];
then
echo "开始远程构建容器"
docker stop h5_frontend_web || true;
docker rm h5_frontend_web || true;
docker rmi -f $(docker images | grep registry.cn-shanghai.aliyuncs.com/tolpo_platform/h5_frontend_web | awk '{print $3}')
#docker login --username=telpo_linwl@1111649216405698 --password=telpo#1234 registry.cn-shanghai.aliyuncs.com;
#docker login --username=telpo_fengjj@1111649216405698 --password=PWDaliyun123 registry.cn-shanghai.aliyuncs.com
docker login --username=rzl_wangjx@1111649216405698 --password=telpo.123 registry.cn-shanghai.aliyuncs.com
docker pull registry.cn-shanghai.aliyuncs.com/tolpo_platform/h5_frontend_web:$version
docker run -p 8075:80 -d --restart=always --name h5_frontend_web registry.cn-shanghai.aliyuncs.com/tolpo_platform/h5_frontend_web:$version;
#删除产生的None镜像
docker rmi -f $(docker images | grep none | awk '{print $3}')
docker ps -a
else
echo "开始在测试环境远程构建容器"
docker stop h5_frontend_web || true
docker rm h5_frontend_web || true
docker rmi -f $(docker images | grep 139.224.254.18:5000/h5_frontend_web | awk '{print $3}')
docker pull 139.224.254.18:5000/h5_frontend_web:$version
docker run -p 8075:80 -d --restart=always --name h5_frontend_web 139.224.254.18:5000/h5_frontend_web:$version;
#删除产生的None镜像
docker rmi -f $(docker images | grep none | awk '{print $3}')
docker ps -a
fi

+ 783
- 37
package-lock.json
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 9
- 4
package.json ファイルの表示

@@ -1,5 +1,5 @@
{
"name": "alipay-scan-code-front-end",
"name": "h5frontend",
"version": "0.1.0",
"private": true,
"scripts": {
@@ -12,14 +12,18 @@
"test:unit": "vue-cli-service test:unit"
},
"dependencies": {
"amfe-flexible": "^2.2.1",
"@vant/area-data": "^1.2.2",
"axios": "^0.26.0",
"core-js": "^3.6.5",
"html2canvas": "^1.4.1",
"nprogress": "^0.2.0",
"rxjs": "^7.8.0",
"vant": "^2.12.39",
"vue": "^2.6.11",
"vue-router": "^3.2.0",
"vuex": "^3.4.0"
"vuex": "^3.4.0",
"weixin-js-sdk": "^1.6.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^4.5.0",
@@ -34,11 +38,12 @@
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-vue": "^6.2.2",
"lint-staged": "^9.5.0",
"postcss-px-to-viewport": "^1.1.1",
"prettier": "^2.2.1",
"sass": "^1.26.5",
"sass-loader": "^8.0.2",
"vue-template-compiler": "^2.6.11"
"vue-template-compiler": "^2.6.11",
"postcss-pxtorem": "^5.1.1",
"compression-webpack-plugin": "^5.0.0"
},
"gitHooks": {
"pre-commit": "lint-staged"


+ 3
- 3
public/index.html ファイルの表示

@@ -1,8 +1,8 @@
<!--
* @Date: 2022-01-19 10:08:26
* @LastEditors: JinxChen
* @LastEditTime: 2022-02-16 10:52:18
* @FilePath: \alipay-scan-code-front-end\public\index.html
* @LastEditTime: 2023-02-25 15:03:02
* @FilePath: \TelpoH5FrontendWeb\public\index.html
* @description:
-->
<!DOCTYPE html>
@@ -12,7 +12,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title>电子学生证订购服务</title>
<title></title>
</head>
<body>
<noscript>


+ 11
- 12
setup_development.sh ファイルの表示

@@ -1,27 +1,26 @@
#!/bin/bash
###
# @Author: your name
# @Date: 2020-07-02 10:34:00
# @LastEditTime: 2022-02-25 15:01:41
# @Date: 2022-08-18 09:19:07
# @LastEditors: JinxChen
# @Description: In User Settings Edit
# @FilePath: \AntpayFrontEnd\setup_development.sh
# @LastEditTime: 2022-08-18 10:06:17
# @FilePath: \TelpoH5FrontendWeb\setup_development.sh
# @description:
###
#!/bin/bash
npm -v
npm config set registry https://registry.npm.taobao.org
npm install
npm run build-dev
image_version=`date +%Y%m%d%H%M`;
docker stop antpay_frontend_web || true;
docker rm antpay_frontend_web || true;
docker stop h5_frontend_web || true;
docker rm h5_frontend_web || true;
# 删除镜像
docker rmi -f $(docker images | grep telpo/antpay_frontend_web | awk '{print $3}')
docker rmi -f $(docker images | grep telpo/h5_frontend_web | awk '{print $3}')
# 构建telpo/mrp:$image_version镜像
docker build --no-cache . -t telpo/antpay_frontend_web:$image_version;
docker build --no-cache . -t telpo/h5_frontend_web:$image_version;
#删除产生的None镜像
docker rmi -f $(docker images | grep none | awk '{print $3}')
# 查看镜像列表
docker images;
docker run -p 8804:80 -d --restart=always --name antpay_frontend_web telpo/antpay_frontend_web:$image_version;
docker run -p 8075:80 -d --restart=always --name h5_frontend_web telpo/h5_frontend_web:$image_version;
# 查看日志
docker logs antpay_frontend_web;
docker logs h5_frontend_web;

+ 9
- 10
setup_production.sh ファイルの表示

@@ -1,28 +1,27 @@
#!/bin/bash
###
# @Author: your name
# @Date: 2020-07-02 10:34:59
# @LastEditTime: 2022-02-25 15:01:53
# @Date: 2022-08-18 09:19:07
# @LastEditors: JinxChen
# @Description: In User Settings Edit
# @FilePath: \AntpayFrontEnd\setup_production.sh
# @LastEditTime: 2022-08-18 09:29:15
# @FilePath: \TelpoH5FrontendWeb\setup_production.sh
# @description:
###
#!/bin/bash
npm -v
npm config set registry https://registry.npm.taobao.org
npm install
npm run build
image_version=$version;
# 删除镜像
docker rmi -f $(docker images | grep registry.cn-shanghai.aliyuncs.com/tolpo_platform/antpay_frontend_web | awk '{print $3}')
docker rmi -f $(docker images | grep registry.cn-shanghai.aliyuncs.com/tolpo_platform/h5_frontend_web | awk '{print $3}')
# 构建telpo/mrp:$image_version镜像
docker build --no-cache . -t telpo/antpay_frontend_web:$image_version;
docker build --no-cache . -t telpo/h5_frontend_web:$image_version;
#TODO:推送镜像到阿里仓库
echo '=================开始推送镜像======================='
#docker login --username=telpo_linwl@1111649216405698 --password=telpo#1234 registry.cn-shanghai.aliyuncs.com
#docker login --username=telpo_fengjj@1111649216405698 --password=PWDaliyun123 registry.cn-shanghai.aliyuncs.com
docker login --username=rzl_wangjx@1111649216405698 --password=telpo.123 registry.cn-shanghai.aliyuncs.com
docker tag telpo/antpay_frontend_web:$image_version registry.cn-shanghai.aliyuncs.com/tolpo_platform/antpay_frontend_web:$image_version
docker push registry.cn-shanghai.aliyuncs.com/tolpo_platform/antpay_frontend_web:$image_version
docker tag telpo/h5_frontend_web:$image_version registry.cn-shanghai.aliyuncs.com/tolpo_platform/h5_frontend_web:$image_version
docker push registry.cn-shanghai.aliyuncs.com/tolpo_platform/h5_frontend_web:$image_version
echo '=================推送镜像完成======================='
#删除产生的None镜像
docker rmi -f $(docker images | grep none | awk '{print $3}')


+ 9
- 9
setup_test.sh ファイルの表示

@@ -1,10 +1,10 @@

###
# @Author: your name
# @Date: 2020-07-02 10:34:59
# @LastEditTime: 2022-02-25 15:02:07
# @Date: 2022-08-18 09:19:07
# @LastEditors: JinxChen
# @Description: In User Settings Edit
# @FilePath: \AntpayFrontEnd\setup_test.sh
# @LastEditTime: 2022-08-18 09:29:35
# @FilePath: \TelpoH5FrontendWeb\setup_test.sh
# @description:
###
#!/bin/bash
npm -v
@@ -14,14 +14,14 @@ npm run build-test
image_version=$version;
# 删除镜像
docker rmi -f $(
docker images | grep 139.224.254.18:5000/antpay_frontend_web | awk '{print $3}'
docker images | grep 139.224.254.18:5000/h5_frontend_web | awk '{print $3}'
)
# 构建telpo/mrp:$image_version镜像
docker build --no-cache . -t telpo/antpay_frontend_web:$image_version;
docker build --no-cache . -t telpo/h5_frontend_web:$image_version;
#TODO:推送镜像到私有仓库
echo '=================开始推送镜像======================='
docker tag telpo/antpay_frontend_web:$image_version 139.224.254.18:5000/antpay_frontend_web:$image_version
docker push 139.224.254.18:5000/antpay_frontend_web:$image_version
docker tag telpo/h5_frontend_web:$image_version 139.224.254.18:5000/h5_frontend_web:$image_version
docker push 139.224.254.18:5000/h5_frontend_web:$image_version
echo '=================推送镜像完成======================='
#删除产生的None镜像
docker rmi -f $(docker images | grep none | awk '{print $3}')


+ 6
- 4
src/App.vue ファイルの表示

@@ -1,7 +1,7 @@
<!--
* @Date: 2022-01-19 10:08:26
* @LastEditors: JinxChen
* @LastEditTime: 2022-02-25 16:45:37
* @LastEditTime: 2022-05-10 18:25:55
* @FilePath: \AntpayFrontEnd\src\App.vue
* @description:
-->
@@ -25,7 +25,8 @@ export default {
}
},
mounted() {
console.log("当前版本号::", VERSION_MODEL, "当前环境::", process.env.NODE_ENV);
console.log("当前版本号::", VERSION_MODEL, "当前环境::", process.env.NODE_ENV, this.$title);

},
methods: {
reload() {
@@ -33,7 +34,7 @@ export default {
this.$nextTick(() => {
this.isRouterAlive = true;
});
}
},
}
}
</script>
@@ -43,6 +44,7 @@ export default {
text-align: center;
color: #2c3e50;
height: 100vh;
width: 100vw;
width: 100%;
background-color: #f7f8fa;
}
</style>

+ 0
- 52
src/api/alipay.js ファイルの表示

@@ -1,52 +0,0 @@
/*
* @Date: 2022-02-14 15:18:50
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 10:50:22
* @FilePath: \AntpayFrontEnd\src\api\alipay.js
* @description: axios封装
*/
import request from '../http/request';

export const APIAlipay = {
getGoodsDetails, //首页获取商品数据
getAlipayForm, // 调起支付宝收银台
getAlipayResult, //获取支付结果
};
export default APIAlipay;

// post请求
function getGoodsDetails(goodsNo) {
return request({
url: '/api/get/goods',
method: 'get',
params: {
goodsNo
},
});
}

function getAlipayForm(params) {
return request({
url: '/webpage/alipay',
method: 'post',
data: params,
});
}

function getAlipayResult(params) {
return request({
url: '/api/order/detail/callback',
method: 'post',
data: params,
});
}

// get请求 示例
/* function getPolygonFence(serialNo) {
return request({
url: '/api/Geofence/GetPolygonFence',
method: 'get',
headers: { AuthKey: 'key1' },
params: { serialNo },
})
} */

+ 79
- 0
src/api/core.js ファイルの表示

@@ -0,0 +1,79 @@
/*
* @Date: 2021-12-18 15:49:01
* @LastEditors: JinxChen
* @LastEditTime: 2023-02-24 10:03:15
* @FilePath: \TelpoH5FrontendWeb\src\api\core.js
* @description:
* b端的接口, 每次调用前先获取token
*/
import axios from 'axios';
import prefix from '@/store/prefix'
const baseUrl = process.env.VUE_APP_BASE_API + 'gateway';
const service = axios.create({
baseURL: baseUrl,
});
service.interceptors.request.use(
request => {
if (localStorage.getItem(prefix + 'gatewayToken')) {
request.headers.AccessToken = localStorage.getItem(prefix + 'gatewayToken');
}
return request;
},
);
export const APICore = {
areaAlarmDetail, //获取告警详情
getAuth, //获取b端接口token
changeAlarmStatus, //修改非法区域告警推送状态
QueryLiveBasePackage, //获取基本套餐
payLiveBaseDevice, //微信统一下单
GpsDeviceFence, //围栏 redis
}
/* const headerAuth = this.$store.getters.gatewayToken; */
// 获取告警详情
function areaAlarmDetail(data) {
return service({
url: `${baseUrl}/core/api/v1/Fence/AreaAlarmDetail`,
method: 'get',
params: data,
})
}
// 获取告警授权token
function getAuth(params) {
return service({
url: `${baseUrl}/core/api/v1/Ability/study_ai/terminal/auth`,
method: 'post',
data: params
})
}
function changeAlarmStatus(params) {
return service({
url: `${baseUrl}/core/api/v1/Fence/AddAreaUserFilter`,
method: 'post',
data: params
})
}
function GpsDeviceFence(params) {
return service({
url: `${baseUrl}/core/api/v1/Redis/GpsDeviceFence`,
method: 'post',
data: params
})
}
// 获取基本套餐信息
function QueryLiveBasePackage(params) {
return service({
url: `${baseUrl}/core/api/v1/Device/QueryLiveBasePackage`,
method: 'post',
data: params
});
}
// 统一下单
// 获取基本套餐信息
function payLiveBaseDevice(params) {
return service({
url: `${baseUrl}/core/api/v1/Device/PayLiveBaseDevice`,
method: 'post',
data: params
});
}
export default APICore;

+ 57
- 0
src/api/pay.js ファイルの表示

@@ -0,0 +1,57 @@
import javaRequest from '@/http/java_api';

export const APIPay = {
getToken, //获取token
getOpenId, // 获取openId
getPolAlipayForm, //获取聚合码支付宝form
getPolWx, //获取聚合码微信
getWxPayResult, //获取微信支付结果
getAlipayResult,
};
export default APIPay;

function getToken(manufacturerNo) {
return javaRequest({
url: '/authorization/get/token',
method: 'get',
params: {manufacturerNo},
});
}
function getOpenId(code) {
return javaRequest({
url: '/polymerization/get/openid',
method: 'get',
params: {code},
});
}

function getPolAlipayForm(params) {
return javaRequest({
url: '/polymerization/alipay',
method: 'post',
data: params,
});
}

function getPolWx(params) {
return javaRequest({
url: '/polymerization/wxpay',
method: 'post',
data: params,
});
}

function getWxPayResult(params) {
return javaRequest({
url: '/api/wx/order/callback',
method: 'post',
data: params,
});
}
function getAlipayResult(params) {
return javaRequest({
url: '/api/order/detail/callback',
method: 'post',
data: params,
});
}

+ 49
- 0
src/api/wx.js ファイルの表示

@@ -0,0 +1,49 @@
/*
* @Date: 2021-06-30 14:29:56
* @LastEditors: JinxChen
* @LastEditTime: 2023-02-25 10:44:01
* @FilePath: \TelpoH5FrontendWeb\src\api\wx.js
* @description: 功能
*/
import request from '@/http/webapi';


const APIWx = {
createJSSDK,
checkIsNewCustomer, //获取微信用户是否首次关注,即是否是新用户
ocr, //ocr识别
Effective, //激活接口
}
export default APIWx;
function createJSSDK({ userId, sUrl, appId }) {
return request({
url: '/api/WX/CreateJsSdk',
method: 'get',
params: { userId, sUrl, appId },
})
}
function checkIsNewCustomer(params) {
return request({
url: '/api/User/getOpenId',
method: 'post',
headers: { AuthKey: 'key1' },
data: params,
})
}

function ocr(params) {
return request({
url: '/api/WX/ocr',
method: 'post',
headers: { AuthKey: 'key1' },
data: params,
})
}
// 中亿SIM自动激活接口
function Effective(params) {
return request({
url: '/api/Command/Effective',
method: 'post',
data: params,
});
}

+ 125
- 0
src/assets/css/public.scss ファイルの表示

@@ -0,0 +1,125 @@
$designWidth: 750;
$blue: #2599ff;
$next: #8bc6fa;
$red: #ff8c8c;
$background: #f2f4f5;
$border_color: #d1d1d1;
/* 绑定时选择人物关系图片head.png */
$spriteWidthHead: 180;
$spriteHeightHead: 330;
$iconWidthHead: 80;
$iconHeightHead: 80;
/* 雪碧图 */
$spriteWidth: 400;
$spriteHeight: 400;
/* tabbar */
$tabbarH: 60px;
/* navbar */
$navbarH: 46px;

/* @function px2rem($px) {
@return $px*320/$designWidth/20+rem;
} */

@-webkit-keyframes rotation {
from {
-webkit-transform: rotate(0deg);
}

to {
-webkit-transform: rotate(360deg);
}
}

@mixin colorAndFont($color, $fontSize) {
color: $color;
font-size: ($fontSize)px;
}

@mixin center {
display: flex;
justify-content: center;
align-items: center;
}

@mixin boxShadow($color...) {
@if $color {
box-shadow: 0 0 10px $color;
} @else {
box-shadow: 0 0 10px rgba(185, 185, 185, .9);
}
}

@mixin avatarShadow {
box-shadow: 0 0 1px 1px rgba(185, 185, 185, 0.4);
}

@mixin avatarActiveShadow {
box-shadow: 0 0 5px 1px rgba(185, 185, 185, 0.4);
}

@mixin avatarOnlineShadow {
box-shadow: 0 0 1px 1px rgba(95, 204, 14, 0.4);
}

@mixin avatarActiveOnlineShadow {
box-shadow: 0 0 5px 1px rgba(95, 204, 14, 0.4);
}

@mixin border {
position: absolute;
box-sizing: border-box;
content: ' ';
pointer-events: none;
top: -50%;
right: -50%;
bottom: -50%;
left: -50% !important;
border-bottom: 1px solid $border_color;
-webkit-transform: scale(.5);
transform: scale(.5);
}

// 雪碧图位置的处理
@mixin bgPosition(
$spriteWidth,
$spriteHeight,
$iconWidth,
$iconHeight,
$iconX,
$iconY
) {
background-position: (
($iconX / ($spriteWidth - $iconWidth)) * 100% ($iconY / ($spriteHeight - $iconHeight)) * 100%
);
}

// 雪碧图
@mixin icon_position($iconWidth, $iconHeight, $iconX, $iconY) {
@include bgPosition(
$spriteWidth,
$spriteHeight,
$iconWidth,
$iconHeight,
$iconX,
$iconY
);
}

// 雪碧图路径
@mixin icon($spriteUrl, $iconW, $iconH, $containerW, $containerH) {
background: transparent url($spriteUrl) no-repeat;
background-size: (400 * $iconW / $containerW)px (400 * $iconH / $containerH)px;
}

// 绑定时选择人物关系图片head.png
@mixin head_position($iconX, $iconY) {
@include bgPosition(
$spriteWidthHead,
$spriteHeightHead,
$iconWidthHead,
$iconHeightHead,
$iconX,
$iconY
);
}

+ 323
- 0
src/assets/css/reset.scss ファイルの表示

@@ -0,0 +1,323 @@
* {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
-webkit-tap-highlight-color: transparent;
}

html {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}

body,
html {
-webkit-user-select: none;
user-select: none;
width: 100vw;
height: 100vh;
}

address,
applet,
article,
aside,
audio,
blockquote,
body,
canvas,
caption,
dd,
details,
div,
dl,
dt,
embed,
figcaption,
figure,
footer,
h1,
h2,
h3,
h4,
h5,
h6,
header,
html,
iframe,
li,
mark,
menu,
nav,
object,
ol,
output,
p,
pre,
progress,
ruby,
section,
summary,
table,
tbody,
td,
tfoot,
th,
thead,
time,
tr,
ul,
video {
margin: 0;
padding: 0;
border: 0;
vertical-align: baseline;
}

a {
color: #444444;
background-color: transparent;
text-decoration: none;
-webkit-touch-callout: none;
outline: none;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}

a.active,
a.link,
a.hover {
color: #444444;
}

li {
list-style: none;
}

article,
aside,
details,
figcaption,
figure,
footer,
header,
main,
menu,
nav,
section,
summary {
display: block;
}

audio,
canvas,
progress,
video {
display: inline-block;
}

audio:not([controls]) {
display: none;
height: 0;
}

[hidden],
template {
display: none;
}

a:active,
a:hover {
outline: 0;
}

b,
strong {
font-weight: 700;
}

small {
font-size: 80%;
}

sub,
sup {
position: relative;
vertical-align: baseline;
font-size: 75%;
line-height: 0;
}

sup {
top: -0.5em;
}

sub {
bottom: -0.25em;
}

img {
border: 0;
-webkit-touch-callout: none;
}

svg:not(:root) {
overflow: hidden;
}

hr {
box-sizing: content-box;
height: 0;
}

pre {
overflow: auto;
}

code,
kbd,
pre,
samp {
font-size: 1em;
font-family: monospace;
}

a,
button,
input,
optgroup,
select,
textarea {
-webkit-tap-highlight-color: transparent;
}

button,
input,
optgroup,
select,
textarea {
margin: 0;
outline: 0;
color: inherit;
font: inherit;
line-height: normal;
-webkit-appearance: none;
}

button {
overflow: visible;
}

button,
select {
text-transform: none;
}

button,
html input[type='button'],
input[type='reset'],
input[type='submit'] {
cursor: pointer;
-webkit-appearance: button;
}

button[disabled],
html input[disabled] {
cursor: default;
}

button::-moz-focus-inner,
input::-moz-focus-inner {
padding: 0;
border: 0;
}

input {
line-height: normal;
}

input[type='checkbox'],
input[type='radio'] {
box-sizing: border-box;
padding: 0;
}

input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
height: auto;
}

input[type='search'] {
box-sizing: content-box;
-webkit-appearance: textfield;
}

input[type='search']::-webkit-search-cancel-button,
input[type='search']::-webkit-search-decoration {
-webkit-appearance: none;
}

fieldset {
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
border: 1px solid silver;
}

legend {
padding: 0;
border: 0;
}

textarea {
overflow: auto;
}

optgroup {
font-weight: 700;
}

table {
border-collapse: collapse;
border-spacing: 0;
}

td,
th {
padding: 0;
}

.fl,
.leftArea {
float: left;
}

.fr,
.rightArea {
float: right;
}

.clearFix:after {
clear: both;
display: block;
visibility: hidden;
height: 0;
content: '.';
}

input {
border: none;
}

button,
input,
select,
textarea {
outline: 0;
}

textarea {
overflow: hidden;
border: none;
resize: none;
}

img[src=''], img:not([src]) {
opacity: 0;
}

バイナリ
src/assets/img/dealers_form_banner.jpg ファイルの表示

変更前 変更後
幅: 750  |  高さ: 750  |  サイズ: 171KB

バイナリ
src/assets/img/ssjl.jpg ファイルの表示

変更前 変更後
幅: 300  |  高さ: 300  |  サイズ: 15KB

+ 0
- 144
src/components/AgreementDialog.vue ファイルの表示

@@ -1,144 +0,0 @@
<!--
* @Date: 2022-02-26 16:40:02
* @LastEditors: JinxChen
* @LastEditTime: 2022-02-28 17:00:19
* @FilePath: \AntpayFrontEnd\src\components\AgreementDialog.vue
* @description: 协议弹窗组件
-->
<template>
<div>
<van-dialog
class="agreement-container"
v-model="show"
:title="title"
confirm-button-color="#1989fa"
:show-confirm-button="false"
>
<div class="agreement-content">
<h5>一.开通需知及承诺</h5>
<p v-show="isNewCustom">1.感谢用户使用支付宝花呗分期功能。</p>
<p v-show="isNewCustom">
2.用户自愿开通4G电子学生证资费套餐服务({{count}}
<!-- 24 -->
期)每月自动通过支付宝花呗分期支付资费(话费+流量)套餐费{{(price/count).toFixed(2)}}元/月。
</p>
<p v-show="isNewCustom">3.用户需连续使用该资费套餐24期,可据此领取4G电子学生证1台、电话卡1张。</p>
<p style="white-space: pre-wrap">
<span v-show="isNewCustom">4.</span>
{{description}}
</p>
<p v-show="isOldCustom">5.协议期内,电子学生证非人为损坏或进水按“三包”政策进行免费维修或更换。如丢失或人为损坏,按优惠价重新购买。</p>
<p v-show="isOldCustom">6.北京随手精灵科技有限公司接受电子学生证运营销售商委托采用支付宝花呗分期付代收业务货款。</p>
<h5>二.用户承诺</h5>
<p>1.用户已充分了解支付宝花呗付款条款(含支付宝花呗相关规则),充分阅读及理解本协议。</p>
<p>2.用户已经签署业务订购回执,自愿购买并同意签署本协议。</p>
<h5>三.法律适用与管辖</h5>
<p>本协议之效力、解释、变更、执行与争议解决均适用中华人民共和国法律。因本协议产生的争议,均应依照中华人民共和国法律予以处理。</p>
<p v-show="!isButtonShow">{{countDown}}秒后显示按钮</p>
<div class="agreement-button" v-show="isButtonShow">
<van-button type="warning" @click="onDisAgree" round>不同意</van-button>
<van-button type="info" @click="onAgree" round>同意</van-button>
</div>
</div>
</van-dialog>
</div>
</template>

<script>
export default {
name:'agreement-dialog',
props: {
show: {
default: true,
type: Boolean
},
title: {
default: '',
type: String
},
isNewCustom: {
default: true,
type: Boolean
},
isOldCustom: {
default: false,
type: Boolean
},
count: {
default: null,
type: Number
},
price: {
default: null,
type: Number
},
description: {
default: '',
type: String
},
countDown: {
default: 3,
type: Number
},
isButtonShow: {
default: false,
type: Boolean
},
},
data(){
return {
}
},
methods: {
// 不同意
onDisAgree() {
this.$bus.$emit('getCheckStatus', false);
this.$bus.$emit('closeButton', false);
this.resetCountDown();
},
// 同意
onAgree() {
this.$bus.$emit('getCheckStatus', true);
this.$bus.$emit('closeButton', false);
this.resetCountDown();
},
// 重置倒计时和关闭弹窗
resetCountDown() {
this.countDown = 3;
},
}

}
</script>

<style scoped lang="scss">
.agreement-container {
.agreement-content {
height: 500px;
padding: 5px 10px;
border-top: 0.5px soild;
border-bottom: 0.5px soild;
text-align: left;
overflow: scroll;
h5 {
padding: 5px;
}
p {
padding: 5px;
font-size: 14px;
line-height: 20px;
}
.agreement-button {
padding: 10px;
display: flex;
justify-content: space-around;
align-items: center;
.van-button {
height: 30px;
width: 120px;
border-radius: 10px;
}
}
}
}
</style>

+ 0
- 76
src/components/Checkbox.vue ファイルの表示

@@ -1,76 +0,0 @@
<!--
* @Date: 2022-02-26 09:26:04
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 11:40:00
* @FilePath: \AntpayFrontEnd\src\components\Checkbox.vue
* @description: 单选框组件
-->
<template>
<div class="checkbox-container">
<van-checkbox v-model="checked" shape="square" @change="onCheckChange">
<strong >已阅读协议并确认</strong>
</van-checkbox>
</div>
</template>

<script>
export default {
name:'checkbox',
mounted() {
this.getDialogData();
},
data(){
return {
checked: false,
}
},
methods: {
// 获取从dialog组件传过来的参数
getDialogData() {
this.$bus.$on('getCheckStatus', (data) => {
this.checked = data;
})
},
// 单选框值发生变化时
onCheckChange(value) {
this.checked = value;
this.$emit('SendCheckStatus', value);
},
}
}
</script>

<style scoped lang="scss">
.checkbox-container {
margin: 5px 0;
.agreement-container {
.agreement-content {
height: 500px;
padding: 5px 10px;
border-top: 0.5px soild;
border-bottom: 0.5px soild;
text-align: left;
overflow: scroll;
h5 {
padding: 5px;
}
p {
padding: 5px;
font-size: 14px;
line-height: 20px;
}
.agreement-button {
padding: 10px;
display: flex;
justify-content: space-around;
align-items: center;
.van-button {
height: 30px;
width: 120px;
border-radius: 10px;
}
}
}
}
}
</style>

+ 0
- 13
src/config/customize.js ファイルの表示

@@ -1,13 +0,0 @@
/*
* @Date: 2022-02-26 15:09:25
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 10:58:12
* @FilePath: \AntpayFrontEnd\src\config\customize.js
* @description: 个性化定制, 根据不同的商家定制个性化的界面
* 注意: 后期可以根据接口来实现
*/
import store from '../store/index';

export const CUSTOMIZE_SERVICE = {
isChunyu:() => store.getters.goodsNo === 889,
};

+ 2
- 2
src/config/models.js ファイルの表示

@@ -1,11 +1,11 @@
/*
* @Date: 2021-11-20 10:26:39
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 11:38:20
* @LastEditTime: 2022-07-21 16:41:11
* @FilePath: \AntpayFrontEnd\src\config\models.js
* @description:
*/
export const VERSION_MODEL = '1.0.2'; //版本号
export const VERSION_MODEL = '1.0.19F'; //版本号
export const IMAGE_URL = {
production: 'http://zfb.ssjlai.com/web/',
test: 'http://zfb.ssjlai.com/web/',


+ 70
- 0
src/http/java_api.js ファイルの表示

@@ -0,0 +1,70 @@
/*
* @Author: linwl
* @Date: 2020-04-13 14:47:59
* @LastEditTime: 2023-02-24 14:54:19
* @LastEditors: JinxChen
* @Description: axios请求配置
* @FilePath: \TelpoH5FrontendWeb\src\http\requestPolymer.js
*/
import axios from 'axios';
import prefix from '@/store/prefix';
const httpProxyPrefix = process.env.VUE_APP_BASE_API + 'telpopay/';

// create an axios instance axios.create创建一个实例
const service = axios.create({
// baseURL: process.env.VUE_APP_BASE_API,
baseURL: httpProxyPrefix,
// timeout: 5000 // request timeout
});

const errorHandler = (error) => {
// const status = get(error, 'response.status');
const status = error.response.status;
console.log(status);
switch (status) {
case 400: error.message = '请求错误'; break;
case 401: error.message = '未授权,请登录'; break;
case 403: error.message = '拒绝访问'; break;
case 404: error.message = '请求地址出错'; break;
case 408: error.message = '请求超时'; break;
case 500: error.message = '服务器内部错误'; break;
case 501: error.message = '服务未实现'; break;
case 502: error.message = '网关错误'; break;
case 503: error.message = '服务器不可用'; break;
case 504: error.message = '网关超时'; break;
case 505: error.message = 'HTTP版本不受支持'; break;
default: break;
}
return Promise.reject(error);
};

// 请求拦截器,增加 token interceptors拦截
service.interceptors.request.use(
request => {
/* if (localStorage.getItem('token')) {

} */
if (localStorage.getItem(prefix + 'token')) {
request.headers.token = localStorage.getItem(prefix + 'token');
}
console.log(localStorage.getItem(prefix + 'token'));
return request;
},
errorHandler
);

// response interceptor
service.interceptors.response.use(
response => {
// const res = response.data
/* if (response.data.message !== null && response.data.message.indexOf('无效的Access Token') >= 0) { // 登录过期,未建立统一错误码,用 message 暂代
// 登录过期
NotifyService.notify({ type: 'warning', message: `请重新登录,${response.data.message}` });
setTimeout(() => router.push('/login'), 1500);
} */
return response;
},
errorHandler
);

export default service;

+ 1
- 1
src/http/request.js ファイルの表示

@@ -6,7 +6,7 @@
* @description: 封装axios
*/

import axios from 'axios'
import axios from 'axios';
const httpRequestUrl = process.env.VUE_APP_BASE_API;

// create an axios instance axios.create创建一个实例


+ 58
- 0
src/http/webapi.js ファイルの表示

@@ -0,0 +1,58 @@
/*
* @Author: linwl
* @Date: 2020-04-13 14:47:59
* @LastEditTime: 2023-02-24 10:47:44
* @LastEditors: JinxChen
* @Description: axios请求配置
* @FilePath: \TelpoH5FrontendWeb\src\http\webapi.js
*/
import axios from 'axios';
const httpProxyPrefix = process.env.VUE_APP_BASE_API + 'webapi';

// create an axios instance axios.create创建一个实例
const service = axios.create({
baseURL: httpProxyPrefix,
});

const errorHandler = (error) => {
// const status = get(error, 'response.status');
const status = error.response.status;
console.log(status);
switch (status) {
case 400: error.message = '请求错误'; break;
case 401: error.message = '未授权,请登录'; break;
case 403: error.message = '拒绝访问'; break;
case 404: error.message = '请求地址出错'; break;
case 408: error.message = '请求超时'; break;
case 500: error.message = '服务器内部错误'; break;
case 501: error.message = '服务未实现'; break;
case 502: error.message = '网关错误'; break;
case 503: error.message = '服务器不可用'; break;
case 504: error.message = '网关超时'; break;
case 505: error.message = 'HTTP版本不受支持'; break;
default: break;
}
return Promise.reject(error);
};

// 请求拦截器,增加 token interceptors拦截
service.interceptors.request.use(
request => {
/* if (localStorage.getItem('webapiToken')) {

} */
request.headers.AuthToken = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJVc2VySW5mbyI6eyJVc2VySWQiOiJjZTQzOWU1Yy03NWVjLTRhMTEtYWJmMC02YTdhM2IzY2UwMGQiLCJMb2dpbk5hbWUiOiIxODI3NzQyNjcxMiIsIkxvZ2luVHlwZSI6MX0sIkV4cCI6MTY4NDg5NTk5ODg4NS4wfQ.VK_fNU0QrCJwsc_Dxa_lPP1dvnxo73TfKzV_bJquqxU';
return request;
},
errorHandler
);

// response interceptor
service.interceptors.response.use(
response => {
return response;
},
errorHandler
);

export default service;

+ 88
- 47
src/main.js ファイルの表示

@@ -1,74 +1,115 @@
/*
* @Date: 2022-01-19 10:08:26
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 15:00:32
* @FilePath: \AntpayFrontEnd\src\main.js
* @LastEditTime: 2023-02-25 15:44:55
* @FilePath: \TelpoH5FrontendWeb\src\main.js
* @description:
*/
import Vue from "vue";
import 'amfe-flexible/index.js';
import App from "./App.vue";
import router from "./router";
import store from "./store";
import './assets/reset.scss'; //配置全局清除样式
import '@/assets/css/reset.scss';
// ui库按需引入
import 'vant/lib/index.css';
import {
Button,
Tab,
Tabs,
Image as VanImage,
Calendar,
Cell,
CellGroup,
RadioGroup,
Radio,
DropdownMenu,
DropdownItem,
Checkbox,
CheckboxGroup,
Col,
Row,
DatetimePicker,
Dialog,
Card,
Form,
Field,
Sku,
Divider,
Empty,
Notify,
Field,
Form,
Icon,
Image,
Lazyload,
List,
Loading,
Toast,
Popup,
Area,
Cascader,
NavBar,
NoticeBar,
Notify,
Overlay,
Picker,
Popup,
PullRefresh,
Radio,
RadioGroup,
Row,
Slider,
Swipe,
SwipeCell,
SwipeItem,
Switch,
Tab,
Tabbar,
TabbarItem,
Tabs,
Toast,
} from 'vant'; //按需加载vant组件

Vue
.use(Button)
.use(Tab)
.use(VanImage)
.use(Cell)
.use(CellGroup)
.use(RadioGroup)
.use(Radio)
.use(DropdownMenu)
.use(DropdownItem)
.use(Checkbox)
.use(CheckboxGroup)
.use(Col)
.use(Row)
.use(Dialog)
.use(Card)
.use(Form)
.use(Field)
.use(Sku)
.use(Empty)
.use(Notify)
.use(Loading)
.use(Toast)
.use(Area)
.use(Popup)
.use(Picker)
.use(Cascader)
.use(Tabs);
.use(Button)
.use(Calendar)
.use(Checkbox)
.use(CheckboxGroup)
.use(Cell)
.use(CellGroup)
.use(Col)
.use(DatetimePicker)
.use(Dialog)
.use(Divider)
.use(Empty)
.use(Icon)
.use(Image)
.use(Form)
.use(Field)
.use(Lazyload)
.use(List)
.use(Loading)
.use(NavBar)
.use(NoticeBar)
.use(Notify)
.use(Overlay)
.use(Picker)
.use(Popup)
.use(PullRefresh)
.use(Radio)
.use(RadioGroup)
.use(Row)
.use(Slider)
.use(Swipe)
.use(SwipeCell)
.use(SwipeItem)
.use(Switch)
.use(Tab)
.use(Tabbar)
.use(TabbarItem)
.use(Tabs)
.use(Toast)

Vue.config.productionTip = false;
Vue.config.devtools = true;
// 全局配置 loading
Toast.setDefaultOptions('success', {
duration: 1500,
forbidClick: true,
});
Toast.setDefaultOptions('loading', {
duration: 0,
forbidClick: true,
});
Dialog.setDefaultOptions({
confirmButtonColor: "#3296fa",
cancelButtonColor: "#999",
showCancelButton: false
});
Vue.config.productionTip = false;
Vue.prototype.$bus = new Vue();
new Vue({


+ 6
- 12
src/router/index.js ファイルの表示

@@ -1,8 +1,8 @@
/*
* @Date: 2022-01-19 10:08:26
* @LastEditors: JinxChen
* @LastEditTime: 2022-02-28 09:47:42
* @FilePath: \AntpayFrontEnd\src\router\index.js
* @LastEditTime: 2023-02-25 15:56:31
* @FilePath: \TelpoH5FrontendWeb\src\router\index.js
* @description:
*/
import Vue from "vue";
@@ -11,18 +11,12 @@ import Nprogress from "nprogress";
import "nprogress/nprogress.css";

Vue.use(VueRouter);

const routes = [
{ path: '/', redirect: 'index' },
{ path: '/index', name: 'index', component: resolve => require(['@/views/AliPayIndex'], resolve) },
{ path: '/form', name: 'form', component: resolve => require(['@/views/AliPayForm'], resolve) },
{ path: '/redirect', name: 'redirect', component: resolve => require(['@/views/AliPayRedirect'], resolve) },
{ path: '/result', name: 'result', component: resolve => require(['@/views/AliPayResult'], resolve) },
{ path: '/404', name: 'page-not-found', component: resolve => require(['@/views/page-not-found/index'], resolve) },
// 春雨
{ path: '/chunyuForm', name: 'chunyuForm', component: resolve => require(['@/views/chunyu/AliPayForm'], resolve) },
// 组件测试页面
{ path: '/compTest', name: 'compTest', component: resolve => require(['@/views/ComponentsTest'], resolve) },
{ path: '/index', name: 'index', component: resolve => require(['@/views/index'], resolve) },
{ path: '/packageHome', name: 'packageHome', component: resolve => require(['@/views/package-home'], resolve) },
{ path: '/packageList', name: 'packageList', component: resolve => require(['@/views/package-list'], resolve) },
{ path: '/payResult', name: 'payResult', component: resolve => require(['@/views/pay-result'], resolve) },

];



+ 64
- 37
src/store/index.js ファイルの表示

@@ -1,59 +1,86 @@
/*
* @Date: 2022-01-19 10:08:26
* @Date: 2022-08-17 16:18:02
* @LastEditors: JinxChen
* @LastEditTime: 2022-02-14 15:29:30
* @FilePath: \alipay-scan-code-front-end\src\store\index.js
* @description: 配置store
* @LastEditTime: 2023-02-25 15:23:43
* @FilePath: \TelpoH5FrontendWeb\src\store\index.js
* @description:
*/
import Vue from 'vue';
import Vuex from 'vuex';
/* import prefix from '@/store/prefix'; */
import { isNotNull } from "../utils/index"

import prefix from '@/store/prefix';
import { isNotNull } from '@/utils';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
goodsNo: '',
userId: '',
price: '',
count: '',
},
imei: '', //例子
gatewayToken: '', //gateway接口token
token: '',
wxAuthCode: '',
openId: '',
appId: '',
isFromWx: null
},
mutations: {
goodsNo(state, goodsNo) {
state.goodsNo = goodsNo;
window.localStorage[ 'goodsNo' ] = goodsNo;
imei(state, imei) {
state.imei = imei;
window.localStorage[ prefix + 'imei' ] = imei;
},
gatewayToken(state, gatewayToken) {
state.gatewayToken = gatewayToken;
window.localStorage[prefix + 'gatewayToken'] = gatewayToken;
},
token(state, token) {
state.token = token;
window.localStorage[prefix + 'token'] = token;
},
userId(state, userId) {
state.userId = userId;
window.localStorage[ 'userId' ] = userId;
wxAuthCode(state, wxAuthCode) {
state.wxAuthCode = wxAuthCode;
window.localStorage[prefix + 'wxAuthCode'] = wxAuthCode;
},
price(state, price) {
state.price = price;
window.localStorage[ 'price' ] = price;
openId(state, openId) {
state.openId = openId;
window.localStorage[prefix + 'openId'] = openId;
},
count(state, count) {
state.count = count;
window.localStorage[ 'count' ] = count;
appId(state, appId) {
state.appId = appId;
window.localStorage[prefix + 'appId'] = appId;
},
isFromWx(state, isFromWx) {
state.isFromWx = isFromWx;
window.localStorage[prefix + 'isFromWx'] = isFromWx;
},
},
getters: {
goodsNo: state => {
if (isNotNull(state.goodsNo)) return state.goodsNo;
else return window.localStorage[ 'goodsNo' ] == null ? '' : window.localStorage[ 'goodsNo' ];
imei: state => {
if (isNotNull(state.imei)) return state.imei;
else return window.localStorage[ prefix + 'imei' ] == null ? '' : window.localStorage[ prefix + 'imei' ];
},
gatewayToken: state => {
if (state.gatewayToken != '') return state.gatewayToken;
return window.localStorage[prefix + 'gatewayToken'] == null ? '' : window.localStorage[prefix + 'gatewayToken'];
},
token: state => {
if (state.token != '') return state.token;
return window.localStorage[prefix + 'token'] == null ? '' : window.localStorage[prefix + 'token'];
},
userId: state => {
if (isNotNull(state.userId)) return state.userId;
else return window.localStorage[ 'userId' ] == null ? '' : window.localStorage[ 'userId' ];
wxAuthCode: state => {
if (state.wxAuthCode != '') return state.wxAuthCode;
return window.localStorage[prefix + 'wxAuthCode'] == null ? '' : window.localStorage[prefix + 'wxAuthCode'];
},
price: state => {
if (isNotNull(state.price)) return state.price;
else return window.localStorage[ 'price' ] == null ? '' : window.localStorage[ 'price' ];
openId: state => {
if (state.openId != '') return state.openId;
return window.localStorage[prefix + 'openId'] == null ? '' : window.localStorage[prefix + 'openId'];
},
count: state => {
if (isNotNull(state.count)) return state.count;
else return window.localStorage[ 'count' ] == null ? '' : window.localStorage[ 'count' ];
appId: state => {
if (state.appId != '') return state.appId;
return window.localStorage[prefix + 'appId'] == null ? '' : window.localStorage[prefix + 'appId'];
},
isFromWx: state => {
if (state.isFromWx != '') return state.isFromWx;
return window.localStorage[prefix + 'isFromWx'] == null ? '' : window.localStorage[prefix + 'isFromWx'];
},
},

actions: {},
modules: {}
})
});

+ 5
- 4
src/store/prefix.js ファイルの表示

@@ -1,9 +1,10 @@
/*
* @Date: 2022-01-19 16:37:44
* @Date: 2022-08-17 17:30:25
* @LastEditors: JinxChen
* @LastEditTime: 2022-02-23 17:36:21
* @FilePath: \AlipayFrontEnd\src\store\prefix.js
* @LastEditTime: 2023-02-25 15:23:55
* @FilePath: \TelpoH5FrontendWeb\src\store\prefix.js
* @description:
*/
const prefix = 'alipay_front_end_web_';
// 多个前端项目在一个域名底下,故缓存需要明确根据项目分类
const prefix = 'telpo_h5_';
export default prefix;

+ 40
- 1
src/utils/index.js ファイルの表示

@@ -1,7 +1,7 @@
/*
* @Date: 2022-01-19 16:39:51
* @LastEditors: JinxChen
* @LastEditTime: 2022-02-25 16:55:56
* @LastEditTime: 2022-04-13 16:22:59
* @FilePath: \AntpayFrontEnd\src\utils\index.js
* @description: 工具类
*/
@@ -50,3 +50,42 @@ export function isAndroid(userAgent) {
return false;
}
}


// 初始化分期数数组, 1. 如果 分数数组面 包含有 '1' 并且还有其它'12' '24'两个分期, 则把 '1'删掉
// 2. 否则直接返回该数组
export function intCount(array) {
let index = array.some(item => item === '1');
if( index) {
// 大于-1表示存在
let newArray = array.splice(1, 2);
return newArray;
// 存在就删除
} else {
return array;
}
}


// 通过接口返回的数组判读是否显示花呗或者支付宝,, 1. 1 12 24 都存在则支付宝花呗全都显示
// 2. 只有 1 则 只显示支付宝
// 3. 没有 1 则显示花呗
export function isShowAlipay(array) {
let index = array.indexOf('1');
if(index > -1 && array.length === 1 ) {
return true;
} else if (index > -1 && array.length > 2) {
return true;
} else {
return false;
}
}

export function isShowAntpay(array) {
let index = array.indexOf('1');
if(index < 0 && array.length >= 1) {
return true;
} else {
return false;
}
}

+ 0
- 268
src/views/AliPayForm.vue ファイルの表示

@@ -1,268 +0,0 @@
<!--
* @Date: 2022-01-19 16:53:16
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 11:08:17
* @FilePath: \AntpayFrontEnd\src\views\AliPayForm.vue
* @description: 春雨个性化表单
-->
<template>
<div class="form-container">
<!-- 头部 -->
<div class="form-header">
<div class="img-left">
<van-image :src="goodsData.imgPath" height="120"></van-image>
</div>
<div class="content-right">
<p>
<strong>套餐名字:</strong>
</p>
<p>{{goodsData.mainTitle}}</p>
<p>
<strong>月套餐费:</strong>
</p>
<p>
<span>¥{{ (goodsData.price/goodsData.count).toFixed(2) }}</span> x
<span>{{goodsData.count}}期</span>
<span v-show="goodsData.isAmountShow">=¥{{goodsData.price}}</span>
</p>
</div>
</div>
<!-- 中部表单 -->
<div class="form-body">
<van-form @submit="onSubmit" @failed="onFailed">
<div class="form-box">
<van-field
v-model="form.phoneNumber"
name="phoneNumber"
label="电话"
type="tel"
placeholder="必填"
maxlength="11"
required
clearable
:rules="[{ required: true, message: '请填写电话' }]"
/>
<van-field
v-model="form.schoolName"
name="schoolName"
label="学校"
placeholder="必填"
maxlength="30"
required
clearable
:rules="[{ required: true, message: '请填写学校' }]"
/>
<van-field
v-model="form.className"
name="className"
label="班级"
placeholder="必填"
maxlength="10"
required
clearable
:rules="[{ required: true, message: '请填写班级' }]"
/>
<van-field
v-model="form.userName"
name="userName"
label="学生"
placeholder="必填"
maxlength="10"
required
clearable
:rules="[{ required: true, message: '请填写学生' }]"
/>
</div>
<!-- '请知悉' 提示, -->
<div class="know-tips">
<h5>请知悉!</h5>
<p>点击以下按钮,启动支付宝页面"立即支付"</p>
<p>成功后,将分期每月从你的余额扣{{ (goodsData.price/goodsData.count).toFixed(2) }}元</p>
</div>
<div class="form-footer">
<van-button
native-type="onSubmit"
>{{submitText}}</van-button>
</div>
</van-form>
</div>
</div>
</template>

<script>
import { APIAlipay } from "../api/alipay";
import { IMAGE_URL } from '../config/models';
export default {
name:'alipay-form',
data(){
return {
goodsData: {
imgPath: '',
price: null,
count: null,
isAmountShow: '',
mainTitle: '',
title: '4G电子学生证资费套餐开通服务协议',
}, //接收从首页传过来的数据
form: {
phoneNumber: '',
schoolName: '',
className: '',
userName: '',
deviceImei: ''
}, //输入的表单数据
alipayForm: '', //接收支付宝接口返回的表单
submitText: '办理支付宝分期业务', //submit标题
}
},
mounted() {
this.getGoodsDetails();

},
methods: {
// 根据商品编号获取商品详情
getGoodsDetails() {
APIAlipay.getGoodsDetails(this.$store.getters.goodsNo)
.then(res => {
if(res.data.code === 20000) {
let good = res.data.data.goods;
console.log("good", good);
// 图片路径
this.goodsData.imgPath = IMAGE_URL[ process.env.NODE_ENV ] + good.goodsImg;
// 价格
this.goodsData.price = good.price;
// 是否是老用户
this.isOld = good.descriptionText === '' ? true : false;
// 商品名称
this.goodsData.mainTitle = good.mainTitle;
// 分期数
let count = good.periodizationJson.substring(1, good.periodizationJson.length - 1).split(',');
// 是否显示金额总数, todo 后期需从接口获取
this.goodsData.isAmountShow = JSON.parse(this.$route.query.isAmountShow);
this.goodsData.count = Math.max(...count);
this.goodsData.goodDefCount = Math.max(...count).toString();
}
})
},
// 办理支付宝分期业务表单校验通过后
onSubmit() {
let reg = /^1[3456789]\d{9}$/; //手机号码正则验证
if(!reg.test(this.form.phoneNumber)) {
this.$notify({
message: '请输入正确的手机号码',
type: 'warning',
duration: 1500
})
} else {
let reqBody = {
username: this.form.userName,
deviceImei: this.form.deviceImei === '' ? '123' : this.form.deviceImei,
schoolName: this.form.schoolName,
className: this.form.className,
phoneNumber: this.form.phoneNumber,
periodizationNum: Number(this.goodsData.count),
goodsNo: this.$store.getters.goodsNo,
alipayStateType: Number(this.goodsData.payType),
userId: this.$store.getters.userId,
}
APIAlipay.getAlipayForm(reqBody)
.then(res => {
this.alipayForm = res.data;
this.$store.commit('price', Number(this.goodsData.price));
this.$store.commit('count', Number(this.goodsData.count));
// 跳转到一个中转页 form,再通过这个中转页来调起支付宝的收银台
this.$router.push({path: 'redirect', query: {alipayForm: this.alipayForm}});
})
.catch(error => {
console.log(error);
})
}
},
// 表单不通过时
onFailed() {
console.log("表单输入不完整!");
},
}
}
</script>

<style scoped lang="scss">
.form-container {
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
overflow: hidden;
/* padding: 5px;
border-radius: 20px; */
background-color: #f7f8fa;
.form-header {
height: 25vh;
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px,
rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
background-color: rgba(235, 233, 229, 0.726);
.img-left {
width: 120px;
}
.content-right {
flex: 1;
p {
font-size: 14px;
text-align: left;
padding: 5px 10px;
strong {
text-align: left;
}
}
}
}
.form-body {
flex: 1;
position: relative;
overflow: scroll;
/* padding: 10px; */
box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px,
rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
.know-tips {
height: 120px;
width: 100%;
padding: 10px;
h5 {
font-size: 16px;
text-align: left;
padding: 5px;
color: red;
}
p {
font-size: 14px;
padding: 5px;
text-align: left;
}
}
}
.form-footer {
height: 15vh;
width: 100%;
position: absolute;
padding: 10px;
bottom: 10px;
left: 0;
display: flex;
justify-content: center;
flex-direction: column;
.van-button {
height: 40px;
background-color: #1989fa;
color: white;
border-radius: 5px;
&.notSubmit {
background-color: rgba(150, 150, 146, 0.904);
}
}
}
}
</style>

+ 0
- 535
src/views/AliPayIndex.vue ファイルの表示

@@ -1,535 +0,0 @@
<!--
* @Date: 2022-01-19 16:52:21
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 11:19:26
* @FilePath: \AntpayFrontEnd\src\views\AliPayIndex.vue
* @description:
-->
<template>
<div class="index-container">
<!-- 头部banner -->
<div class="index-banner">
<img class="img-contanier" :src="goodsData.imgPath"/>
</div>
<!-- 中间内容 -->
<div class="index-body">
<p class="set-meal-title">月套餐费: <span class="set-meal-price">¥{{ (goodsData.price/goodsData.count).toFixed(2) }}</span> x <span>{{goodsData.count}}期</span> <span v-show='isAmountShow'> = ¥{{goodsData.price}}</span></p>
<p class="index-tips">{{switchPayType}}:</p>
<!-- 花呗or支付宝 -->
<van-radio-group class="radio-group" v-model="radio" @change="onRadioChange">
<van-cell-group>
<!-- 支付宝 -->
<van-cell title="" clickable @click="radio = '1'" v-show="isAlipayShow">
<template #icon>
<img :src="alipayIconPath" alt="" class="pay-icon">
</template>
<template #right-icon>
<span class="radio-group-span">支付宝</span>
<van-radio name="1" />
</template>
</van-cell>
<!-- 花呗 -->
<van-cell title="" clickable @click="radio = '2'">
<template #icon>
<img :src="antpayIconpath" alt="" class="pay-icon">
</template>
<template #right-icon>
<span class="radio-group-span">花呗<label>(推荐)</label></span>
<van-radio name="2" />
</template>
</van-cell>
<!-- 花呗分期 -->
<div class="antpay-container" v-show="isAntpay">
<van-row>
<van-col span="6" class="antpay-row-col-6"><p>花呗分期:</p></van-col>
<van-col span="18" class="antpay-row-col-18">
<van-radio-group v-model="antPayRadio" @change="onChange">
<van-button type="default" size="mini" v-for="(item) in countList" :key="item.value">
<van-radio :name="item.value">
<p>分{{item.value}}期</p>
<p>每期{{ (goodsData.price/item.value).toFixed(2) }}元</p>
</van-radio>
</van-button>
</van-radio-group>
</van-col>
</van-row>
</div>
</van-cell-group>
</van-radio-group>
<!-- 我要开通花呗 -->
<p class="open-antpay" @click="onOpenAntpay">我要开通花呗</p>
<!-- 协议 -->
<p class="agreement" @click="onOpenAgreement">{{agreement.title}}</p>
<!-- 协议内容 -->
<van-dialog
class="agreement-container"
v-model="agreement.show"
:title="agreement.title"
confirm-button-color="#1989fa"
:show-confirm-button="false"
>
<div class="agreement-content">
<h5>一.开通需知及承诺</h5>
<p v-show="isNewCustom">1.感谢用户使用支付宝花呗分期功能。</p>
<p v-show="isNewCustom">2.用户自愿开通4G电子学生证资费套餐服务({{goodsData.count}}<!-- 24 -->期)每月自动通过支付宝花呗分期支付资费(话费+流量)套餐费{{(goodsData.price/goodsData.count).toFixed(2)}}元/月。</p>
<p v-show="isNewCustom">3.用户需连续使用该资费套餐24期,可据此领取4G电子学生证1台、电话卡1张。</p>
<p style="white-space: pre-wrap"><span v-show="isNewCustom">4.</span>{{goodsData.description}}</p>
<p v-show="isOldCustom">5.协议期内,电子学生证非人为损坏或进水按“三包”政策进行免费维修或更换。如丢失或人为损坏,按优惠价重新购买。</p>
<p v-show="isOldCustom">6.北京随手精灵科技有限公司接受电子学生证运营销售商委托采用支付宝花呗分期付代收业务货款。</p>
<h5>二.用户承诺</h5>
<p>1.用户已充分了解支付宝花呗付款条款(含支付宝花呗相关规则),充分阅读及理解本协议。</p>
<p>2.用户已经签署业务订购回执,自愿购买并同意签署本协议。</p>
<h5>三.法律适用与管辖</h5>
<p>本协议之效力、解释、变更、执行与争议解决均适用中华人民共和国法律。因本协议产生的争议,均应依照中华人民共和国法律予以处理。</p>
<p v-show="!agreement.isButtonShow">{{agreement.countDown}}秒后显示按钮</p>
<div class="agreement-button" v-show="agreement.isButtonShow">
<van-button type="warning" @click="onDisAgree" round>不同意</van-button>
<van-button type="info" @click="onAgree" round>同意</van-button>
</div>
</div>
</van-dialog>
</div>
<!-- 底部 -->
<div class="index-footer-out">
<div class="index-footer">
<div class="checkbox-container" v-show="!isChunyu">
<van-checkbox v-model="checked" shape="square" @change="onCheckChange"><strong>已阅读协议并确认</strong></van-checkbox>
</div>
<div class="footer-button">
<van-button :class="['van-button', {notSubmit: !checked && !isChunyu}]" block @click="onSubmit">{{submitText}}</van-button>
</div>
</div>
</div>
<!-- 非支付宝浏览器提示弹窗 -->
<van-dialog v-model="isAlipayBrowser" title="提示您切换支付宝扫码!"
:show-cancel-button="false"
:show-confirm-button="false"
confirm-button-color="#1989fa"
className="alipay-dialog"
:close-on-click-overlay="true">
<p>1.如果已安装支付宝,请打开支付宝扫码。</p>
<p>2.如果未安装支付宝,请到应用商店下载。
<span v-show="!isAndroid" @click="onDownAlipay" class="down">点击前往应用商店下载</span>
<span v-show="isAndroid">或复制 {{alipayDownUrl.android}}
[<span @click="onCopy" class="copy-span">点击复制
</span>],粘贴到浏览器打开下载页面。</span></p>
<p class="close-text">点击屏幕任意地方关闭弹窗</p>
</van-dialog>
</div>
</template>

<script>
import { isNotNull, isAlipayBrowser, isAndroid } from "../utils/index";
import { APIAlipay } from "../api/alipay";
import { IMAGE_URL, USER_AGENT, ALIPAY_DOWN_URL} from '../config/models';
/* import { CUSTOMIZE_SERVICE } from '../config/customize'; */
export default {
name:'alipay-index',
data(){
return {
// 商品数据
goodsData: {
imgPath: null /* || require('../assets/banner_03.jpg') */, //首页图片路径
price: null, //价格
count: null, //分期数
defCount: null, //默认分期数
amount: 480, //总数
isOld: null, //是否是老用户
description: null, //商品描述
defDescription: '电子学生证套餐两年内(24个月)内含每月200分钟通话和1.5G流量,超出通话或流量部分,由用户自行交费。', //默认协议内容
payType: null, //支付类型, 2是花呗, 1 是支付宝
name: null, //商品名称
},
radio: '2', //单选框的值,默认是 '2', 2是花呗, 1支付宝
antPayRadio: '', //花呗分期,默认24期
antpayIconpath: require('../assets/antpay.png'), //花呗支付图片
alipayIconPath: require('../assets/alipay.png'), //支付宝图片
checked: false, //是否已经勾选协议
isAlipayShow: false, //是否显示支付宝选项
goodsNo: '', //商品id
countList: null, //分期数数组
isAmountShow: true, //是否显示总数, 默认显示,部分客户不需要显示则false
isAntpay: true, //单选是否是花呗, 默认是花呗,否则是支付宝
agreement: {
title: '4G电子学生证资费套餐开通服务协议', //协议标题
show: false, //是否显示协议内容,默认不显示
isButtonShow: false, //是否显示按钮
timer: '', //定义一个倒计时
countDown: 3, //同意/不同意按钮显示倒计时
},
isNewCustom: true, //是否是新用户
isOldCustom: false, //是否是新用户
checkCount: 0, //首次点击同意协议单选框
isAlipayBrowser: !isAlipayBrowser(USER_AGENT), //是否是支付宝浏览器
isAndroid: isAndroid(USER_AGENT), //用户设备是否是android
alipayDownUrl: ALIPAY_DOWN_URL, //支付宝app下载链接
isChunyu: null, //是否是春雨
submitText: '一键下单' , //submit文字, 默认 一键下单, 可根据客户需求变化
switchPayType: '可切换支付方式', //默认 可切换支付方式, 可根据客户需求变化

}
},
mounted() {
this.storeQueryParams();
this.getGoodsDetails();
},
methods: {

// 缓存通过扫码得到的商品id
storeQueryParams() {
let params = this.$route.query;
this.initDealContent(params.goodsNo);
console.log("扫码传过来的参数", params);
if(isNotNull(params.goodsNo)) {
this.goodsNo = params.goodsNo;
this.$store.commit('goodsNo', params.goodsNo);
this.$store.commit('userId', params.userId);
} else {
this.$router.push({path: '/404'})
}
},
// 初始化协议内容,根据不同客户的商品id显示不同的协议内容
initDealContent(goodsNo) {
if(goodsNo === '1452515524181975040') {
this.isAlipayShow = true;
} else if(goodsNo === '1462964210433548288' || goodsNo === '1472882092902715392' || goodsNo === '1479390914305277952') {
this.isAmountShow = false;
} else if (goodsNo === '1483687825375969280') { //翼校云定制的商品id
this.agreement.title = '电子学生证AI套餐开通服务协议';
this.isNewCustom = false;
this.isAmountShow = true;
} else if (goodsNo === '889') {
this.isChunyu = true;
this.submitText = '下一步';
this.switchPayType = '支付方案'
}
else {
this.isAmountShow = true;
}
},
// 根据商品id获取商品详情
getGoodsDetails() {
APIAlipay.getGoodsDetails(this.goodsNo)
.then(res => {
if(res.data.code === 20000) {
let good = res.data.data.goods;
console.log("good", good);
// 图片路径
this.goodsData.imgPath = IMAGE_URL[ process.env.NODE_ENV ] + good.goodsImg;
// 价格
this.goodsData.price = good.price;
// 是否是老用户
this.isOld = good.descriptionText === '' ? true : false;
// 商品名称
this.goodsData.name = good.mainTitle;
//商品描述 根据\n换行符来把数据进行换行
this.goodsData.description = good.descriptionText === '' ? this.goodsData.defDescription : good.descriptionText.replace(/\\n/g,"<br/>");
// 分期数
let goodCount = good.periodizationJson.substring(1, good.periodizationJson.length - 1).split(',');
this.goodsData.goodCount = Math.max(...goodCount);
this.goodsData.defCount = Math.max(...goodCount).toString();
this.antPayRadio = Math.max(...goodCount).toString();
this.countList = goodCount.map(g => {
return {
value: g,
label: g
}
}).reverse();
console.log("this.countList", this.countList);
} else {
this.$notify({
message: '系统出现错误,请联系管理员!',
type: 'warning',
duration: 1000
});
}
})
},
// 单选支付宝花呗发生变化时
onRadioChange(values) {
this.isAntpay = values === '2' ? true : false;
this.radio = values;
this.goodsData.payType = Number(values);
},
// 选择分期数改变时
onChange(values) {
this.goodsData.count = values;
},
// 我要开通花呗弹窗
onOpenAntpay() {
this.$dialog.confirm({
title: '如何开通花呗?',
message: `
<p>进入支付宝APP-右下角【我的】-【花呗】,点击后按页面提示操作开通即可。</p>
`,
showCancelButton: false,
messageAlign: 'center',
confirmButtonColor: '#1989fa'
})
},
// 打开协议
onOpenAgreement() {
this.agreement.show = true;
this.checkCount ++;
if(this.checkCount <= 1) {
this.agreement.timer = setInterval(() =>{
this.agreement.countDown --;
if(this.agreement.countDown === 0) {
this.agreement.isButtonShow = true;
clearInterval(this.agreement.timer);
this.agreement.countDown = 3;
}
},1000)
} else if(this.checkCount >= 2){
this.agreement.isButtonShow = true;
}
},
// 复选框绑定值变化时
onCheckChange() {
if(this.checkCount < 1) {
// 首次选择复选框自动打开协议
this.onOpenAgreement();
this.checkCount ++;
} else if (this.checkCount >= 2) {
this.agreement.isButtonShow = true;
}
},

// 不同意
onDisAgree() {
this.checked = false;
this.resetCountDown();
},
// 同意
onAgree() {
this.checked = true;
this.resetCountDown();
},
// 重置倒计时和关闭弹窗
resetCountDown() {
this.agreement.show = false;
this.agreement.isButtonShow = false;
clearInterval(this.agreement.timer);
this.agreement.countDown = 3;
},
// 一键下单提交按钮
onSubmit() {
if(this.checked === false && !this.isChunyu) {
this.$notify({
message: `请阅读并勾选同意${this.agreement.title}`,
type: 'warning',
duration: 1500
})
}else if( this.isChunyu ) {
this.$router.push({path: 'chunyuForm', query: {isAmountShow: this.isAmountShow}})
}
else {
this.$router.push({path: 'form', query: {isAmountShow: this.isAmountShow}})
}
},
// 点击下载支付宝app
onDownAlipay() {
window.location.href = this.alipayDownUrl.ios;
},
// 复制网址
onCopy() {
let oInput = document.createElement('input');
oInput.value = this.alipayDownUrl.android;
document.body.appendChild(oInput);
oInput.select(); // 选择对象;
console.log(oInput.value)
document.execCommand("Copy"); // 执行浏览器复制命令
this.$toast.success('已复制到粘贴板!');
oInput.remove()
}
}
}
</script>

<style scoped lang="scss">
.index-container {
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
overflow: hidden;
box-shadow: rgba(241, 241, 245, 0.932) 0px 30px 60px -12px inset, rgba(239, 242, 243, 0.884) 0px 18px 36px -18px inset;
.index-banner{
height: 40vh;
width: 100vw;
padding: 5px 5px 0 5px;
.img-contanier {
height: calc(40vh - 5px);
width: calc(100vw - 10px);
}
}
.index-body {
flex: 1;
margin: 0 5px 5px 5px;
padding: 0 10px 10px 10px;
overflow: scroll;
box-shadow: rgba(0, 0, 0, 0.09) 0px 2px 1px, rgba(0, 0, 0, 0.09) 0px 4px 2px, rgba(0, 0, 0, 0.09) 0px 8px 4px, rgba(0, 0, 0, 0.09) 0px 16px 8px, rgba(0, 0, 0, 0.09) 0px 32px 16px;
.set-meal-title {
font-size: 16px;
text-align: left;
padding: 5px 0 5px 0;
.set-meal-price {
font-size: 24px;
color: red;
}
}
.index-tips {
font-size: 16px;
text-align: left;
margin: 5px 0;
}
.van-cell {
height: 45px;
line-height: 45px;
padding: 0;
border: 0.5px solid #dcdee2;
border-radius: 10px;
margin-top: 10px;
}
.radio-group {
.radio-group-span {
padding-right: 5px;
label {
color: red;
}
}
.antpay-container {
height: 50px;
line-height: 50px;
/* padding: 5px 0; */
background-color: white;
}
.van-row, .antpay-row-col-18{
height: 50px;
line-height: 50px;
.antpay-row-col-6 {
p {
text-align: left;
font-size: 16px;
}
}
.antpay-row-col-18 {
display: flex;
/* justify-content: center;
align-items: center; */
line-height: 40px;
.van-radio-group {
overflow-x: auto;
white-space: nowrap;
}
.van-radio-group::-webkit-scrollbar {
display: none;
}
.van-button {
height: 40px;
width: 120px;
display: inline-block;
border-radius: 5px;
}
}
}
}
.open-antpay, .agreement {
height: 20px;
line-height: 20px;
text-decoration:underline;
text-align: left;
font-size: 14px;
margin: 5px 0px;
}
.open-antpay {
color: red;
}
.agreement {
margin: 5px 0px;
}
.agreement-container {
.agreement-content {
height: 500px;
padding: 5px 10px;
border-top: .5px soild;
border-bottom: .5px soild;
text-align: left;
overflow: scroll;
h5 {
padding: 5px;
}
p {
padding: 5px;
font-size: 14px;
line-height: 20px;

}
.agreement-button {
padding: 10px;
display: flex;
justify-content: space-around;
align-items: center;
.van-button {
height: 30px;
width: 120px;
border-radius: 10px;
}
}
}
}
.pay-icon {
height: 30px;
width: 30px;
margin: 5px;
}
}
.index-footer-out, .index-footer {
height: 15vh;
width: 100vw;
padding: 10px 10px ;
.index-footer {
position: absolute;
left: 0;
bottom: 0;
z-index: 999;
display: flex;
justify-content: center;
flex-direction: column;
.checkbox-container {
margin: 5px 0;
}
.footer-button {
/* box-shadow: rgb(217, 218, 219) 0 20px 30px -15px; */
.van-button {
background-color: #1989fa;
color: white;
border-radius: 5px;
&.notSubmit {
background-color: rgba(150, 150, 146, 0.904);
}
}
}
}
}
.alipay-dialog {
p {
padding: 10px;
line-height: 20px;
text-align: left;
font-size: 14px;
}
.down {
display: block;
color: #1989fa;
text-decoration: #1989fa;
}
.copy-span {
color: red;
}
.close-text {
text-align: center;
}
}
}
</style>

+ 0
- 36
src/views/AliPayRedirect.vue ファイルの表示

@@ -1,36 +0,0 @@
<!--
* @Date: 2022-01-19 16:54:08
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 10:26:29
* @FilePath: \AntpayFrontEnd\src\views\AliPayRedirect.vue
* @description:
-->
<template>
<div></div>
</template>

<script>
export default {
name:'alipay-redirect',
data(){
return {
queryData: this.$route.query.alipayForm, //接收上一个页面传过来的支付宝表单文件
}
},
mounted() {
this.createAlipayPage();
},
methods: {
createAlipayPage() {
const div = document.createElement('div'); //在当前页面创建一个div的节点
div.innerHTML = this.queryData; //将支付宝的form表单数据添加到div里面
document.body.appendChild(div); //把这个节点添加到页面的body里面去
document.forms[0].submit(); //自动调用form表单的submit方法正式调起支付宝的收银台界面
}
}
}
</script>

<style scoped lang="scss">

</style>

+ 0
- 173
src/views/AliPayResult.vue ファイルの表示

@@ -1,173 +0,0 @@
<!--
* @Date: 2022-01-19 16:55:03
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 14:11:16
* @FilePath: \AntpayFrontEnd\src\views\AliPayResult.vue
* @description:
注意:本地调试需要手动在url添加参数
?tradeno='860009040228082'&outtradeno='860009040228082'
-->

<template>
<div class="pay-result-container">
<!-- 接口轮询时加载动画以及空状态 -->
<van-empty v-show="isResultBack" image="https://img01.yzcdn.cn/vant/custom-empty-image.png" />
<van-loading v-show="isResultBack" type="spinner" >数据加载中...</van-loading>
<!-- 接口轮询完成后 -->
<div class="pay-result-content" v-show="!isResultBack">
<div class="result-header">
<h5 v-if="isPaySuccess">{{ checkSuccess.tips }}</h5>
<h5 v-if="isPaySuccess">{{ checkSuccess.title }}</h5>
<h5 v-if="!isPaySuccess">{{checkFail.tips}}</h5>
<p v-if="isPaySuccess">接下来将按分期每月从你的支付宝余额扣{{(price/count).toFixed(2)}}元。</p>
<p>{{isPaySuccess ? checkSuccess.content : checkFail.content}}</p>
</div>
<!-- 页脚 -->
<div class="result-footer">
<p>商家订单号: </p>
<p>{{alipayOrder.outradeNo}}</p>
<p>请保存好该订单号截图,方便售后服务。</p>

</div>
</div>

</div>
</template>

<script>
import { isNotNull } from "../utils/index";
import { APIAlipay } from "../api/alipay";
export default {
name:'alipay-result',
data(){
return {
alipayOrder: {
outradeNo: '',
tradeNo: '',
}, //支付宝返回的订单号
timer: "", //计时器
num: 1, //轮询次数
price: this.$store.getters.price,
count: this.$store.getters.count,
isPaySuccess: null, //是否支付成功
isResultBack: true, //是否有结果返回
checkSuccess: {
tips: "恭喜你!",
title: '支付宝分期业务办理成功!',
content: "可进入支付宝-->我的-->花呗-->我的账单,查询应还、或提前还款。"
}, //查询支付结果成功时
checkFail: {
tips: "查询交易信息失败!",
content: "请进入支付宝-->我的-->花呗-->我的账单,查询应还、或提前还款。"
}, //查询支付结果失败时

}
},
mounted() {
this.getParamsData();
this.closeTime();
},
methods: {
// 获取url拼接的params
getParamsData() {
let params = this.$route.query;
console.log("支付宝返回的信息", params);
if (isNotNull(params)) {
this.alipayOrder.outradeNo = params.out_trade_no;
this.alipayOrder.tradeNo = params.trade_no;
this.getPayResult();
}
},
// 根据订单号轮询获取订单结果和状态
getPayResult() {
let that = this;
let reqBody = {
outTradeNo: this.alipayOrder.outradeNo,
tradeNo: this.alipayOrder.tradeNo
};
if(that.num > 30 ) {
if(that.timer){
clearInterval(that.timer);
}
} else {
that.timer = setInterval(() => {
that.num ++;
APIAlipay.getAlipayResult(reqBody)
.then(res => {
if(res.data.code === 20000) {
this.isResultBack = false;
this.isPaySuccess = true;
if(that.timer) {
clearInterval(that.timer)
}
}
}).catch(e => {
console.log(e)
})
}, 2000)
}
},
// 30秒后关闭轮询
closeTime() {
setTimeout(() => {
clearInterval(this.timer);
console.log("即将关闭轮询");
if(this.isPaySuccess === null && this.isResultBack === true) {
this.isResultBack = false;
this.isPaySuccess = false;
}
}, 30000);
},
}
}
</script>

<style scoped lang="scss">
.pay-result-container {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
/* background-color: whitesmoke; */
.pay-result-content {
height: 100vh;
width: 100vw;
.result-header, .result-footer {
display: flex;
justify-content: center;
/* align-items: center; */
flex-direction: column;
padding: 30px;
text-align: left;
}
.result-header {
height: 50vh;
background-color: #f2f2f2;
h5 {
color: red;
font-size: 26px;
padding: 10px;
font-weight: bold;
}
p {
font-size: 16px;
padding: 10px;
}
}
.result-footer {
height: 50vh;
p {
font-size: 16px;
padding: 10px;
}
p:nth-child(2) {
padding: 20px;
color: red;
background-color: antiquewhite;
}
}
}
}
</style>

+ 0
- 46
src/views/ComponentsTest.vue ファイルの表示

@@ -1,46 +0,0 @@
<!--
* @Date: 2022-02-28 09:46:25
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 10:14:03
* @FilePath: \AntpayFrontEnd\src\views\ComponentsTest.vue
* @description: 组件测试页面
-->
<template>
<div>
<AgreementDialog
:title="title"
:show="true"
:count="count"
:price="price"
:description="description"/>
</div>
</template>

<script>
import AgreementDialog from '../components/AgreementDialog'
export default {
name:'components-test',
components: { AgreementDialog },
data(){
return {
title: '标题',
description: 'description',
count: 24,
price: 240

}
},
mounted() {
this.getGoodsDetails();
},
methods: {
getGoodsDetails() {

}
}
}
</script>

<style scoped lang="scss">

</style>

+ 0
- 501
src/views/chunyu/AliPayForm.vue ファイルの表示

@@ -1,501 +0,0 @@
<!--
* @Date: 2022-01-19 16:53:16
* @LastEditors: JinxChen
* @LastEditTime: 2022-03-04 15:48:09
* @FilePath: \AntpayFrontEnd\src\views\chunyu\AliPayForm.vue
* @description: 春雨个性化表单
-->
<template>
<div class="form-container">
<!-- 头部 -->
<div class="form-header">
<div class="img-left">
<van-image :src="goodsData.imgPath" height="120"></van-image>
</div>
<div class="content-right">
<p>
<strong>套餐名字:</strong>
</p>
<p>{{goodsData.mainTitle}}</p>
<p>
<strong>月套餐费:</strong>
</p>
<p>
<span>¥{{ (goodsData.price/goodsData.count).toFixed(2) }}</span> x
<span>{{goodsData.count}}期</span>
<span v-show="goodsData.isAmountShow">=¥{{goodsData.price}}</span>
</p>
</div>
</div>
<!-- 中部表单 -->
<div class="form-body">
<van-form @submit="onSubmit" @failed="onFailed">
<div class="form-box">
<!-- <van-field
v-model="form.phoneNumber"
name="phoneNumber"
label="电话"
type="tel"
placeholder="必填"
maxlength="11"
required
clearable
:rules="[{ required: true, message: '请填写电话' }]"
/>
<van-field
v-model="form.schoolName"
name="schoolName"
label="学校"
placeholder="必填"
maxlength="30"
required
clearable
:rules="[{ required: true, message: '请填写学校' }]"
/>
<van-field
v-model="form.className"
name="className"
label="班级"
placeholder="必填"
maxlength="10"
required
clearable
:rules="[{ required: true, message: '请填写班级' }]"
/>
<van-field
v-model="form.studentName"
name="studentName"
label="学生"
placeholder="必填"
maxlength="10"
required
clearable
:rules="[{ required: true, message: '请填写学生' }]"
/> -->
<!-- 省市区选择详情见 https://vant-contrib.gitee.io/vant/v2/#/zh-CN/area -->
<van-field
readonly
clickable
name="area"
:value="form.address"
label="地区:"
placeholder="点击选择省市区"
@click="showArea = true"
required
:rules="[{ validator}]"
/>
<van-popup v-model="showArea" position="bottom">
<van-area
:area-list="areaList"
@confirm="onConfirmAddress"
@cancel="showArea = false"
/>
</van-popup>
<!-- 请选择学校 -->
<van-field
readonly
clickable
name="school"
:value="form.schoolName"
label="学校:"
placeholder="点击选择学校"
@click="showSchool = true"
required
:rules="[{ validator}]"
/>
<van-popup v-model="showSchool" position="bottom">
<van-picker
show-toolbar
:columns="schoolColumns"
@confirm="onConfirmSchool"
@cancel="showSchool = false"
/>
</van-popup>
<!-- 选择年级班级 -->
<van-field
readonly
clickable
name="class"
:value="form.className"
label="年级班级:"
placeholder="点击选择年级班级"
@click="showClass = true"
required
:rules="[{ validator}]"
/>
<van-popup v-model="showClass" round position="bottom">
<van-cascader
v-model="form.className"
title="请选择年级班级"
:options="classOptions"
@close="showClass = false"
@finish="onClassFinish"
/>
</van-popup>

<!-- 请选择学生名字 -->
<van-field
readonly
clickable
name="school"
:value="form.studentName"
label="学生:"
placeholder="点击选择学生"
@click="showStudent = true"
required
:rules="[{ validator}]"
/>
<van-popup v-model="showStudent" position="bottom">
<van-picker
show-toolbar
:columns="studentColumns"
@confirm="onConfirmStudent"
@cancel="showStudent = false"
/>
</van-popup>

<!-- 请选择家长手机号码 -->
<van-field
readonly
clickable
name="school"
:value="form.phoneNumber"
label="手机号码:"
placeholder="点击选择家长手机号码"
@click="showPhone = true"
required
:rules="[{ pattern, message: '请输入正确的手机号码' }]"
/>
<van-popup v-model="showPhone" position="bottom">
<van-picker
show-toolbar
:columns="phoneColumns"
@confirm="onConfirmPhone"
@cancel="showPhone = false"
/>
</van-popup>

</div>
<!-- '请知悉' 提示, -->
<div class="know-tips">
<h5>请知悉!</h5>
<p>点击以下按钮,启动支付宝页面"立即支付"</p>
<p>成功后,将分期每月从你的余额扣{{ (goodsData.price/goodsData.count).toFixed(2) }}元</p>
</div>
<div class="form-footer">
<Checkbox @SendCheckStatus="SendCheckStatus" />
<AgreementDialog
:show="goodsData.isShow"
:title="goodsData.title"
:count="goodsData.count"
:price="goodsData.price"
:description="goodsData.description"
:countDown="goodsData.countDown"
:isButtonShow="goodsData.isButtonShow"
/>
<van-button
:class="['van-button', {notSubmit: !goodsData.newChecked}]"
native-type="onSubmit"
>{{submitText}}</van-button>
</div>
</van-form>
</div>
</div>
</template>

<script>
import { APIAlipay } from "../../api/alipay";
import Checkbox from "../../components/Checkbox";
import AgreementDialog from "../../components/AgreementDialog";
import { IMAGE_URL } from '../../config/models';
//Vant 官方提供了一份默认的省市区数据,可以通过 @vant/area-data 引入:
import { areaList } from '@vant/area-data';
import { isNotNull } from '../../utils';
export default {
name:'alipay-form',
components: { Checkbox, AgreementDialog },
data(){
return {
goodsData: {
imgPath: '', //图片地址
price: null, //价格
count: null, //分期数
isAmountShow: '', //是否显示金额总数, 目前根据首页商品来控制是否需要显示, 后期可根据接口来控制
mainTitle: '', //商品mainTitle
description: '', //协议说明
title: '4G电子学生证资费套餐开通服务协议',
newChecked: false, //单选框的值
checkCount: 0, //点击单选框的次数
isButtonShow: false, //显示协议组件里面的同意不同意按钮是否需要显示
countDown: 3, //协议按钮倒计时
timer: '', //定时器
isShow: false, //是否显示协议弹窗
}, //接收从首页传过来的数据
form: {
phoneNumber: '', //手机号码
schoolName: '', //学校名字
className: '', //班级名字
studentName: '', //学生名字
deviceImei: '', //设备Imei, 接口参数, 可为空,
address: '', //地址, todo, 接口暂时没有这个字段,待接口实现
}, //输入的表单数据
alipayForm: '', //接收支付宝接口返回的表单
submitText: '一键下单', //submit标题
showArea: false,
// todo 以下数据以接口实际数据为准
areaList, //省市区数据
showSchool: false,
schoolColumns: ['学校1', '学校2', '学校3', '学校4', '学校5'], //学校数据
showClass: false,
classOptions: [
{
text: '高一',
value: '1',
children: [
{ text: '一班', value: '1' },
{ text: '二班', value: '1' },
{ text: '三班', value: '1' }
],
},
{
text: '高二',
value: '2',
children: [
{ text: '一班', value: '2' },
{ text: '二班', value: '2' },
{ text: '三班', value: '2' },
],
},
],
showStudent: false,
studentColumns: [
'学生1', '学生2', '学生3', '学生4', '学生5'
],
showPhone: false,
phoneColumns: [
'18277426712', '18277426712', '18277426712', '18277426712', '18277426712'
],
pattern: /^1[3456789]\d{9}$/,




}
},
mounted() {
this.getGoodsDetails();
this.getCheckStatus();

},
methods: {
// 获取从协议弹窗传过来的单选框状态
getCheckStatus() {
this.$bus.$on('getCheckStatus', (data) => {
this.goodsData.newChecked = data;
this.goodsData.isShow = false;
})
},
// 根据商品编号获取商品详情
getGoodsDetails() {
APIAlipay.getGoodsDetails(this.$store.getters.goodsNo)
.then(res => {
if(res.data.code === 20000) {
let good = res.data.data.goods;
console.log("good", good);
// 图片路径
this.goodsData.imgPath = IMAGE_URL[ process.env.NODE_ENV ] + good.goodsImg;
// 价格
this.goodsData.price = good.price;
// 是否是老用户
this.isOld = good.descriptionText === '' ? true : false;
// 商品名称
this.goodsData.mainTitle = good.mainTitle;
//商品描述 根据\n换行符来把数据进行换行
this.goodsData.description = good.descriptionText === '' ? this.goodsData.defGoodDescription : good.descriptionText.replace(/\\n/g,"<br/>");
// 分期数
let count = good.periodizationJson.substring(1, good.periodizationJson.length - 1).split(',');
// 是否显示金额总数 todo 后期需从接口获取
this.goodsData.isAmountShow = JSON.parse(this.$route.query.isAmountShow);
this.goodsData.count = Math.max(...count);
this.goodsData.goodDefCount = Math.max(...count).toString();
}
})
},
// 办理支付宝分期业务表单校验通过后
onSubmit(values) {
if(this.goodsData.newChecked === false) {
this.$notify({
message: `请阅读并勾选同意${this.goodsData.title}`,
type: 'warning',
duration: 1500
});
} else if( values ) {
let reqBody = {
username: this.form.studentName,
deviceImei: this.form.deviceImei === '' ? '123' : this.form.deviceImei,
schoolName: this.form.schoolName,
className: this.form.className,
phoneNumber: this.form.phoneNumber,
periodizationNum: Number(this.goodsData.count),
goodsNo: this.$store.getters.goodsNo,
alipayStateType: Number(this.goodsData.payType),
userId: this.$store.getters.userId,
}
APIAlipay.getAlipayForm(reqBody)
.then(res => {
this.alipayForm = res.data;
this.$store.commit('price', Number(this.goodsData.price));
this.$store.commit('count', Number(this.goodsData.count));
// 跳转到一个中转页 form,再通过这个中转页来调起支付宝的收银台
this.$router.push({path: 'redirect', query: {alipayForm: this.alipayForm}});
})
.catch(error => {
console.log(error);
})
}
},
// 表单不通过时
onFailed() {
console.log("表单输入不完整!");
},
// 接收 checkbox 组件的SendCheckStatus事件
SendCheckStatus(value) {
//通知 checkbox 组件改变。
this.goodsData.newChecked = value;
this.goodsData.isShow = value;
this.initAgreement();

},
// 初始化协议组件内容
initAgreement() {
this.goodsData.checkCount ++;
if(this.goodsData.checkCount <= 1) {
this.goodsData.timer = setInterval(() =>{
this.goodsData.countDown --;
if(this.goodsData.countDown === 0) {
this.goodsData.isButtonShow = true;
clearInterval(this.goodsData.timer);
this.goodsData.countDown = 3;
}
},1000)
} else if(this.goodsData.checkCount >= 2){
this.goodsData.isButtonShow = true;
this.goodsData.isShow = false;
}
},
// 选择省市区
onConfirmAddress(values) {
this.form.address = values
.filter((item) => !!item)
.map((item) => item.name)
.join('/');
this.showArea = false;
},
// 选择学校
onConfirmSchool(values) {
this.form.schoolName = values;
this.showSchool = false;
},
// 选择年级班级
onClassFinish({ selectedOptions }) {
this.showClass = false;
this.form.className = selectedOptions.map((option) => option.text).join('/');
},
// 选择学生
onConfirmStudent(values) {
this.form.studentName = values;
this.showStudent = false;
},
// 选择家长手机号码
onConfirmPhone(values) {
this.form.phoneNumber = Number(values);
this.showPhone = false;
},
// 校验不为空
validator(value) {
return isNotNull(value);
},
}
}
</script>

<style scoped lang="scss">
.form-container {
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
overflow: hidden;
/* padding: 5px;
border-radius: 20px; */
background-color: #f7f8fa;
.form-header {
height: 25vh;
display: flex;
justify-content: center;
align-items: center;
padding: 10px;
box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px,
rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
background-color: rgba(235, 233, 229, 0.726);
.img-left {
width: 120px;
}
.content-right {
flex: 1;
p {
font-size: 14px;
text-align: left;
padding: 5px 10px;
strong {
text-align: left;
}
}
}
}
.form-body {
flex: 1;
position: relative;
overflow: scroll;
/* padding: 10px; */
box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px,
rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
.know-tips {
height: 120px;
width: 100%;
padding: 10px;
h5 {
font-size: 16px;
text-align: left;
padding: 5px;
color: red;
}
p {
font-size: 14px;
padding: 5px;
text-align: left;
}
}
}
.form-footer {
height: 15vh;
width: 100%;
position: absolute;
padding: 10px;
bottom: 10px;
left: 0;
display: flex;
justify-content: center;
flex-direction: column;
.van-button {
height: 40px;
background-color: #1989fa;
color: white;
border-radius: 5px;
&.notSubmit {
background-color: rgba(150, 150, 146, 0.904);
}
}
}
}
</style>

+ 28
- 0
src/views/index.vue ファイルの表示

@@ -0,0 +1,28 @@
<template>
<div @click="onClick">测试</div>
</template>

<script>
export default {
name:'',
data(){
return {

}
},
methods: {
onClick() {
this.$router.push({
name: 'packageList',
query: {
imei: '45555'
}
})
}
}
}
</script>

<style scoped>

</style>

+ 117
- 0
src/views/package-home/index.vue ファイルの表示

@@ -0,0 +1,117 @@
<!--
* @Date: 2023-02-24 14:18:25
* @LastEditors: JinxChen
* @LastEditTime: 2023-02-24 15:39:49
* @FilePath: \TelpoH5FrontendWeb\src\views\package-home\index.vue
* @description:
-->
<template>
<div class="package-home"></div>
</template>

<script>
import { APIPay } from "@/api/pay";
import APICore from "@/api/core";
import { isNotNull } from "@/utils/index";
export default {
name: "",
data() {
return {
params: {

}
};
},
created() {
this.getParams();
this.getToken();
this.getAuth();
this.checkBrowser();
},
methods: {
// checkBrowser 检查扫码的浏览器内核
checkBrowser() {
const userAgent = window.navigator.userAgent;
console.log("浏览器内核", userAgent);
if (/AlipayClient/.test(userAgent)) {
console.log("alipay");
} else if (/MicroMessenger/.test(userAgent)) {
console.log("wx");
let url = window.location.href.split("?code=")[1];
console.log("获取授权code的url", url);
if (
isNotNull(url) ||
window.location.href.indexOf("code") > -1
) {
let timeStamp = new Date().getTime();
let code = url.split("&")[0];
if (isNotNull(code)) {
this.$store.commit("wxAuthCode", `${code}`);
/* this.getOpenId(); */
}
} else {
this.getWxCode();
console.log("获取token");
}
} else {
console.log("当前浏览器内核并非支付宝或者微信");
}
},
// 获取b端接口的token
getAuth() {
let manufactorId = "5bf13062-a41e-4d00-ba14-1101aad12650";
APICore.getAuth({ manufactorId: manufactorId }).then(res => {
this.$store.commit("gatewayToken", res.data.data);
});
},
// 获取token
getToken() {
let manufacturerNo = '9f166b07-ff83-4991-84dc-ca6ad4a6b95b';
APIPay.getToken(manufacturerNo).then(res => {
console.log("token的数据", res.data)
let data = res.data;
if(data.code === 20000) {
this.$store.commit("token", data.token);
console.log("token的数据", localStorage.getItem('token'))
}
})
},
// 根据code获取openId
getOpenId() {
let code = this.$store.getters.wxAuthCode;
APIPay.getOpenId(code).then(res => {
let data= res.data;
if(data.code === 20000) {
this.$store.commit("openId", data.data.openId);
}
})
},
// 获取微信code
getWxCode() {
let params = this.params;
let commonUrl = process.env.VUE_APP_BASE_API;
/* let testUrl = encodeURIComponent(`https://id.ssjlai.com/h5-frontendweb/#/${params.routerName}?imei=${params.imei}&appId=${params.appId}`);
let proUrl = encodeURIComponent(`https://ai.ssjlai.com/h5-frontendweb/#/${params.routerName}?imei=${params.imei}&appId=${params.appId}`); */
let redUrl = encodeURIComponent(`${commonUrl}/h5-frontendweb/#/${params.routerName}?imei=${params.imei}&appId=${params.appId}&iccid=${params.iccid}`);
console.log("redUrl", redUrl);
let url = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${params.appId}&redirect_uri=${redUrl}&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`
window.location.href = url;
},
// 获取url传过来的参数
getParams() {
let params = this.$route.query;
if (params) {
console.log("params", params);
this.params = {...params};
this.$store.commit("appId", params.appId);
console.log("this.params", this.params);
}
},
}
};
</script>

<style scoped lang="scss">
.package-home {
}
</style>

+ 563
- 0
src/views/package-list/index.vue ファイルの表示

@@ -0,0 +1,563 @@
<!--
* @Date: 2022-03-29 16:57:58
* @LastEditors: JinxChen
* @LastEditTime: 2023-02-25 15:52:29
* @FilePath: \TelpoH5FrontendWeb\src\views\package-list\index.vue
* @description: TODO 小台风充值h5
-->
<template>
<div class="package-list-container">
<van-nav-bar :left-arrow="false" :border="true">
<template #title>
<h5 style="font-size: 16px">{{topupTitle}}</h5>
</template>
</van-nav-bar>
<!-- 灰色线条 -->
<div class="gray-line"></div>
<!-- 套餐说明 -->
<div class="order-description" v-show="packageOrderList.length">
<h5>套餐说明:</h5>
<h5>每月200分钟通话时长,1G流量。</h5>
</div>
<!-- 套餐列表 -->
<div class="topup-container">
<div class="main">
<!-- <div class="tips" v-show="!isCanTopup">
<p>非本公司发行的SIM卡,</p>
<p>无此服务。</p>
<div class="cancel-button" @click="onNavBack">返回</div>
</div> -->
<!-- 无套餐时显示 -->
<div class="noData_container" v-show="packageOrderList.length === 0 && isShowNoData">
<p>暂无相关套餐数据,请您联系管理员~</p>
</div>
<!-- 套餐订购 -->
<div
class="package-order-container"

v-for="(item, index) in packageOrderList"
:key="index"
>
<!-- 推荐 -->
<div class="recom" v-show="index === 0">
<div class="shape"></div>
<div class="square">
<p>推荐</p>
</div>
</div>
<!-- 套餐内容 -->
<div class="order-content">
<div class="title">
<p>{{item.packageName}}<!-- :{{(item.packagePrice/item.packageIssue).toFixed(0)}}元/月 --></p>
</div>
<div class="details">
<p>
低至
<span
class="orange"
>{{(item.packagePrice/(item.packageIssue === 0 ? 1: item.packageIssue)).toFixed(0)}}</span>元/月
</p>
<p class="orange">
<span class="orange price">{{item.packagePrice}}元</span>
</p>
<div class="buy-btn" @click="onBuy(item)">
<p>话费充值</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>

<script>
import APIWx from "@/api/wx";
import { APIPay } from "@/api/pay";
let wx = require("weixin-js-sdk"); // TODO 再封装,可拦截错误提示等操作
import APICore from "@/api/core";
import axios from "axios";
import { isNotNull } from "@/utils/index";
export default {
name: "packageList",
data() {
return {
topupTitle: "请选择套餐充值激活电话卡",
wxItem: "",
packageOrderList: [],
outTradeNo: "", //订单号
price: "", //价格,
isShowNoData: false, //是否显示无套餐内容, 默认false
params: {
imei: '',
iccid: '',
manufactorId: '',
appId: '',

},
};
},
computed: {
isCanTopup() {
return this.$route.query.isCanTopup;
},
serialNo() {
return this.$route.query.serialNo;
}
},
created() {
this.getParams();
this.getWxAutograph();
this.getLiveBasePackage();
},
/* mounted() {
this.getParams();
this.getWxAutograph();
this.getLiveBasePackage();
}, */
methods: {
// 根据code获取openId
getOpenId() {
let code = this.$store.getters.wxAuthCode;
APIPay.getOpenId(code).then(res => {
let data= res.data;
if(data.code === 20000) {
this.$store.commit("openId", data.data.openId);
}
})
},
// 获取b端接口的token
getAuth() {
let manufactorId = "5bf13062-a41e-4d00-ba14-1101aad12650";
APICore.getAuth({ manufactorId: manufactorId }).then(res => {
this.$store.commit("gatewayToken", res.data.data);
});
},
// 获取url传过来的参数
getParams() {
let params = this.$route.query;
if (params) {
let url = window.location.href.split("?code=")[1];
if ( isNotNull(url) || window.location.href.indexOf("code") > -1) {
let timeStamp = new Date().getTime();
let code = url.split("&")[0];
if (isNotNull(code)) {
this.$store.commit("wxAuthCode", `${code}`);
this.getOpenId();
}
}
this.params = {...params};
}
},
// 获取基本套餐信息
getLiveBasePackage() {
this.$toast.loading({
message: "获取套餐中",
duration: 1500
});
let reqBody = {
imei: this.params.imei
}
APICore.QueryLiveBasePackage(reqBody)
.then(res => {
if (res.data.code === 106 || res.data.code === 104) {
// token过期
this.getAuth();
setTimeout(() => {
this.getLiveBasePackage();
}, 1500);
} else if (res.data.code === 0 && res.data.data === null) {
this.isShowNoData = true;
}else {
let data = res.data.data.packageList;
if(data === null) {
this.isShowNoData = true;
} else {
this.packageOrderList = data.reverse();
console.log("套餐数据::", data);
}
}
this.$toast.success({
message: "成功获取套餐",
duration: 1500
});
})
.catch(error => {
this.$dialog.confirm({
title: "获取套餐数据失败",
message: error
});
})
.finally(() => {
setTimeout(() => {
this.$toast.clear();
}, 1500);
});
},
// 返回
onNavBack() {
},
// 获取微信jssdk
getWxAutograph() {
let that = this;
return new Promise((resolve, reject) => {
APIWx.createJSSDK({
sUrl: window.location.href.split("#")[0],
userId: '',
appId: this.params.appId
})
.then(res => {
let item = res.data.data;
this.wxItem = res.data.data;
wx.config({
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: item.appId, // 必填,公众号的唯一标识
timestamp: item.timeStamp, // 必填,生成签名的时间戳
nonceStr: item.nonceStr, // 必填,生成签名的随机串
signature: item.signature, // 必填,签名
jsApiList: ["chooseWXPay"] // 必填,需要使用的JS接口列表
});

wx.ready(() => {
resolve(true);
/* that.canScan = true; */
});
})
.catch(err => {
reject(false);
console.log(err);
});
});
},
// 话费充值
onBuy(data) {
let payType = data.packagePayType;
this.price = data.packagePrice;
// 需要区分是要用微信支付还是支付宝花呗支付
if (payType === "支付宝花呗") {
this.aliPay(data);
} else {
this.wxPay(data);
}
},
// 微信支付
wxPay(data) {
this.$toast.loading({
message: "加载中"
});
let orderData = data;
let reqBody = {
openId: this.$store.getters.openId, //openId
imei: this.params.imei, //imei
productId: data.productId, //套餐id
packageName: data.productModel + ',' + data.packageName, //套餐名字
packagePayType: this.shiftType(data.packagePayType), //支付类型
packageIssue: data.packageIssue, //分期
packagePrice: process.env.NODE_ENV === "production" ? data.packagePrice * 100 : 1 //总金额单位为分,测试环境写死
};
APICore.payLiveBaseDevice(reqBody)
.then(res => {
this.$toast.clear();
if (res.data.code === 104 || res.data.code === 106) {
this.getAuth();
setTimeout(() => {
this.wxPay(orderData);
}, 1000);
}
let that = this;
let wxData = res.data.data;
that.outTradeNo = wxData.out_trade_no;
console.log("wxData", wxData);
// 本地测试
that.$router.push({
name: "payResult",
query: {
outTradeNo: that.outTradeNo,
price: that.price,
rechargeUrl: data.rechargeUrl || '',
iccid: this.params.iccid,
isAdmin: this.$route.query.isAdmin,
serialNo: this.params.imei,
routerName: this.params.routerName,
issue: data.packageIssue
}
});
wx.chooseWXPay({
timestamp: wxData.timeStamp, // 支付签名时间戳,注意微信 jssdk 中的所有使用 timestamp 字段均为小写。但最新版的支付后台生成签名使用的 timeStamp 字段名需大写其中的 S 字符
nonceStr: wxData.nonceStr, // 支付签名随机串,不长于 32 位
package: wxData.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
signType: wxData.signType, // 微信支付V3的传入 RSA ,微信支付V2的传入格式与V2统一下单的签名格式保持一致
paySign: wxData.paySign, // 支付签名
success: function(res) {
// 支付成功后的回调函数
that.$router.push({
name: "payResult",
query: {
outTradeNo: that.outTradeNo,
price: that.price,
rechargeUrl: data.rechargeUrl,
iccid: that.params.iccid,
isAdmin: that.$route.query.isAdmin || false,
serialNo: that.$route.query.serialNo,
issue: data.packageIssue
}
});
console.log("微信支付成功::", res);
},
fail: err => {
console.log("支付出错了::", err);
this.$dialog.confirm({
title: "支付失败",
message: "出错了,请您重新进入"
});
},
cancel: function(err) {
// 用户取消支付
this.$dialog.confirm({
message: "您取消了支付"
});
console.log("用户取消了支付::", err);
}
});
})
.catch(error => {
console.log("error", error);
})
.finally(() => {
this.$toast.clear();
});
},
// 跳转到支付宝花呗外部链接
aliPay(data) {
console.log("选择了支付宝::", data);
this.$toast.loading({
message: "加载中"
});
let orderData = data;
let reqBody = {
openId: this.$store.getters.openId, //openId
imei: this.serialNo, //imei
productId: data.productId, //套餐id
packageName: data.productModel + ',' + data.packageName, //套餐名字
packagePayType: this.shiftType(data.packagePayType), //支付类型
packageIssue: data.packageIssue, //分期
packagePrice: process.env.NODE_ENV === "production" ? data.packagePrice * 100 : 1 //总金额单位为分,测试环境写死
};
this.$toast.clear();
APICore.payLiveBaseDevice(reqBody)
.then(res => {
if (res.data.code === 104 || res.data.code === 106) {
this.getAuth();
setTimeout(() => {
this.aliPay(orderData);
}, 1000);
}
let that = this;
let alipayData = res.data.data.xmlStrMap;
this.outTradeNo = alipayData.outTradeNo;
let alipayForm = decodeURI(alipayData.payXmlStr);
that.$store.commit("isFromWx", true);
let alipayUserId = process.env.NODE_ENV === "production" ? 42 : 18
this.$router.push({
name: "payResult",
query: {
rechargeUrl:
data.rechargeUrl ||
`https://id.ssjlai.com/frontend/#/alipay`,
outTradeNo: that.outTradeNo,
price: that.price,
alipayForm: alipayForm,
iccid: that.$route.query.iccid,
isAdmin: that.$route.query.isAdmin || false,
serialNo: that.$route.query.serialNo,
alipayUserId: alipayUserId,
productId: data.productId
}
});
})
.catch(error => {
console.log("error", error);
})
.finally(() => {
this.$toast.clear();
});
},
// 转换类型
shiftType(type) {
switch (type) {
case "微信":
return "1"
/* break; */
case "支付宝花呗":
return "2"
/* break; */
}
}
}
};
</script>
<style lang="scss">
.van-nav-bar__title {
max-width: 80% !important;
font-size: 16px;
}
</style>
<style lang="scss" scoped>
.package-list-container {
background-color: white;
height: 100vh;
.topup-container {
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: column;
background-color: white;
overflow: scroll;
height: calc(100vh - 4rem);
.main {
padding: 0 10px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.tips {
padding: 10px;
}
.noData_container {
margin: 100px auto 0;
height: 120px;
/* background: url(../../../assets/img/news-noData.png) center no-repeat; */
background-size: 165px 120px;
display: flex;
justify-content: center;
align-items: flex-end;
font-size: 16px;
color: #999;
p {
font-size: 16px;
}
/* @include colorAndFont(#999, 28); */
}
p {
padding: 10px;
font-size: 16px;
}
.cancel-button {
width: 30vw;
border-radius: 5px;
background-color: #2599ff;
color: #fff;
min-height: 40px;
display: flex;
justify-content: center;
align-items: center;
font-size: 16px;
}
.package-order-container {
position: relative;
height: 120px;
width: 300px;
padding: 5px 20px;
margin: 10px 0;
z-index: 999;
box-shadow: rgba(14, 30, 37, 0.12) 0 3px 5px 0,
rgba(14, 30, 37, 0.32) 0 2px 16px 0;
.recom {
position: absolute;
top: -7px;
left: -26px;
border-style: solid;
border-width: 0 40px 40px;
border-color: transparent transparent red;
transform: rotate(-45deg);
text-align: center;
z-index: 9999;
p {
padding: 0;
color: white;
font-size: 14px;
}
.shape {
position: absolute;
top: -1px;
left: -21px;
border-style: solid;
border-width: 0 21px 21px;
border-color: transparent transparent white;
}
.square {
height: 15px;
width: 35px;
position: absolute;
top: 21px;
left: -20px;
background: red;
font-size: 14px;
}
}
.order-content {
padding-top: 25px;
.title {
display: flex;
justify-content: flex-start;
p {
font-size: 14px;
font-weight: bold;
}
}
.details {
display: flex;
justify-content: space-between;
align-items: center;
p {
font-size: 14px;
}
.orange {
color: orange;
}
.price {
font-size: 14px;
font-weight: bold;
padding-right: 5px;
}
.buy-btn {
height: 30px;
width: 90px;
display: flex;
justify-content: center;
align-items: center;
background: orange;
border-radius: 20px;
p {
padding: 0;
color: white;
}
}
}
}
.content {
font-size: 14px;
}
}
}
}
.gray-line {
height: 10px;
width: 100%;
background: #f2f4f5;

}
.order-description {
height: 60px;
display: flex;
justify-content: flex-start;
align-items: flex-start;
flex-direction: column;
padding: 5px 0 10px 25px;
h5 {
font-size: 14px;
padding: 10px 0 0 0;
}
}
}
</style>

+ 0
- 32
src/views/page-not-found/index.vue ファイルの表示

@@ -1,32 +0,0 @@
<!--
* @Date: 2022-02-14 15:34:10
* @LastEditors: JinxChen
* @LastEditTime: 2022-02-14 15:39:24
* @FilePath: \alipay-scan-code-front-end\src\views\page-not-found\index.vue
* @description: 404
-->
<template>
<div class="page-not-found">
<van-empty description="扫码出现错误!请您重新扫码!" />
</div>
</template>

<script>
export default {
name:'page-not-found',
data(){
return {

}
}
}
</script>

<style scoped lang="scss">
.page-not-found {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
</style>

+ 386
- 0
src/views/pay-result/index.vue ファイルの表示

@@ -0,0 +1,386 @@
<!--
* @Date: 2023-02-24 16:47:33
* @LastEditors: JinxChen
* @LastEditTime: 2023-02-25 16:02:53
* @FilePath: \TelpoH5FrontendWeb\src\views\pay-result\index.vue
* @description:
-->
<!--
* @Date: 2022-05-29 10:23:28
* @LastEditors: JinxChen
* @LastEditTime: 2023-02-25 10:34:31
* @FilePath: \TelpoH5FrontendWeb\src\views\pay-result\index.vue
* @description:
-->
<template>
<div class="pay-result-container">
<div class="check-container" v-show="pageShow">
<van-nav-bar title="支付结果" :left-arrow="false" :border="true" ></van-nav-bar>
<!-- 头部 -->
<div class="header pos-center">
<img src="../../assets/img/ssjl.jpg" alt />
<p>随手精灵</p>
</div>
<!-- 详细 -->
<div class="details">
<div class="details-item">
<p class="left-text">订单状态</p>
<p>{{isPayStatus ? '支付成功' : '查询失败'}}</p>
</div>
<div class="details-item">
<p class="left-text">订单尾号</p>
<p>{{outTradeNo}}</p>
</div>
<div class="details-item price">
<p class="left-text">支付总额</p>
<p>¥ {{price}}元</p>
</div>
</div>
<!-- 返回 -->
<div class="footer pos-center">
<!-- <div class="back-btn" @click="onNavBack" v-show="!isPayStatus">
<p>返回重新选择套餐购买</p>
</div> -->
<div class="back-btn" @click="onNext" v-show="!isPayStatus">
<p>激活电话卡</p>
</div>
</div>
</div>
<!-- <div class="flush" v-show="isIos">
<div class="back-btn" @click="onFlush">
<p>查询</p>
</div>
</div> -->
</div>
</template>

<script>
import { isNotNull} from "@/utils/index";
import { APIPay } from "@/api/pay";
import APIWx from "@/api/wx";
import axios from "axios";
export default {
name: "payResult",
data() {
return {
pageShow: false,
count: 0,
timer: "", //定时器
isPayStatus: null,
price: this.$route.query.price,
outTradeNo: this.$route.query.outTradeNo,
isIos: null //是否是ios
};
},
created() {
this.checkParams();
this.closeTime();
},
mounted() {
//this.checkParams();
//this.closeTime();
},
methods: {
// checkIosOrAndroid
checkIosOrAndroid() {
let userAgent = navigator.userAgent;
if (userAgent.indexOf("iPhone") > -1) {
this.isIos = true;
}
},
onNavBack() {
this.$router.push({
name: "packageList",
query: {
serialNo: this.$route.query.serialNo,
isAdmin: this.$route.query.isAdmin,
iccid: this.$route.query.iccid,
routerName: this.$route.query.routerName,
}
});
},
// 下一步激活
onNext() {
console.log("激活", );
//this.$toast.loading("激活中");
this.effective();
},
// 激活接口
effective() {
this.$toast.loading('激活中,请稍候...');
let reqBody = {
imei: this.$route.query.serialNo,
iccid: this.$route.query.iccid || '',
issue: Number(this.$route.query.issue) || 0
};
APIWx.Effective(reqBody)
.then(res => {
console.log("res", res);
let data = res.data;
console.log("data", data);
this.$toast.clear();
if(data.stateCode !== 1) {
this.$dialog.confirm({
title: '温馨提示',
message: `${data.message}`,
showCancelButton: false
})
} else if(data.stateCode === 0 && data.message !== null) {
this.$dialog.confirm({
title: '温馨提示',
message: `电话卡激活失败!请进行实名认证与绑定SIM卡。如您已实名认证,请5分钟后,再进行设备绑定。`,
showCancelButton: false
})
/* Dialog.confirm({ title: "SIM卡激活失败", message: data.message, className: "device_confirm", }); */
} else if (data.stateCode === 1 && data.message !== 'ok') {

/* this.countDown(); */
this.$dialog.confirm({ title: "SIM卡激活成功", message: '卡激活成功,5分钟后则可正常使用。', showCancelButton: false});
} else if (data.stateCode === 1 && data.message === 'ok') {
this.$dialog.confirm({ title: "SIM卡激活成功", message: '卡激活成功,5分钟后则可正常使用。', showCancelButton: false});
}
})
.catch(error => {
console.log("出错了:;", error);
this.$dialog.confirm({
title: '温馨提示',
message: `${error.message}`,
showCancelButton: false
})
}).finally(() => {
this.$toast.clear();
})
},
// ios需要手动点击按钮查询
onFlush() {
this.isIos = false;
this.checkParams();
},
// storeParams
checkParams() {
let params = this.$route.query;
let isFromWx = this.$store.getters.isFromWx;
if (params.rechargeUrl && isFromWx === true) {
// 如果存在支付宝跳转链接,则打开外部浏览器跳到支付宝h5
console.log("支付宝");
this.$toast.loading({
message: "跳转中",
});
setTimeout(() => {
this.$store.commit("isFromWx", "");
let alipayForm = encodeURIComponent(params.alipayForm); //对接口返回的form进行编码
let url =
process.env.NODE_ENV === "production"
? `https://ai.ssjlai.com/frontend/#/alipay?goodsNo=${params.productId}&userId=${params.alipayUserId}&isWx=true&alipayForm=${alipayForm}`
: `https://id.ssjlai.com/frontend/#/alipay?goodsNo=${params.productId}&userId=${params.alipayUserId}&isWx=true&alipayForm=${alipayForm}`;
window.location.href = url;
}, 1500);
} else if (params.rechargeUrl && isFromWx === null) {
// todo 轮询支付宝的支付结果
let that = this;
console.log("支付宝结果");
this.$toast.loading({
message: "结果查询中"
});
let reqBody = {
outTradeNo: params.outTradeNo
};
let url =
process.env.NODE_ENV === "production"
? "https://ai.ssjlai.com/telpopay/alipay/order/detail/callback"
: "https://id.ssjlai.com/telpopay/alipay/order/detail/callback";
if (that.count >= 30) {
if (that.timer) {
clearInterval(that.timer);
this.isPayStatus = false;
this.pageShow = true;
this.$toast.clear();
console.log("关闭轮询1");
}
}
that.timer = setInterval(() => {
that.count++;
APIPay.getAlipayResult(reqBody)
.then(res => {
if (res.data.code === 20000) {
this.pageShow = true;
this.isPayStatus = true;
this.$toast.clear();
console.log("关闭轮询2");
if (that.timer) {
clearInterval(that.timer);
}
}
})
.catch(e => {
console.log(e);
});
}, 2000);
} else {
// todo 轮询微信支付的订单,支付成功则激活 (只有直播基地的imei才激活操作)
let that = this;
console.log("微信");
this.$toast.loading({message: "结果查询中"});
let reqBody = {
outTradeNo: params.outTradeNo
};
let url =
process.env.NODE_ENV === "production"
? " https://ai.ssjlai.com/telpopay/api/wx/order/callback"
: "https://id.ssjlai.com/telpopay/api/wx/order/callback";
if (that.count >= 30) {
if (that.timer) {
clearInterval(that.timer);
this.isPayStatus = false;
this.pageShow = true;
this.$toast.clear();
console.log("关闭轮询3");
}
}
that.timer = setInterval(() => {
that.count++;
APIPay.getWxPayResult(reqBody)
.then(res => {
if (res.data.code === 20000) {
this.pageShow = true;
this.isPayStatus = true;
this.$toast.clear();
console.log("关闭轮询4");
if (that.timer) {
clearInterval(that.timer);
}
}
})
.catch(e => {
console.log(e);
});
}, 2000);
}
},
// 获取微信支付接口
getWxPayResult() {
this.$toast.loading({
message: "正在获取支付结果",
duration: 3000
});
setTimeout(() => {
this.pageShow = true;
}, 3000);
},
closeTime() {
let params = this.$route.query;
let isFromWx = this.$store.getters.isFromWx;
setTimeout(() => {
clearInterval(this.timer);
console.log("即将关闭轮询");
this.$toast.clear();
if (this.pageShow === false) {
this.pageShow = true;
}
}, 31000);
}
}
};
</script>

<style scoped lang="scss">
.pay-result-container {
height: 100vh;
width: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
flex-direction: column;
background-color: white;
overflow: scroll;
.check-container {
width: 100%;
}
.pos-center {
display: flex;
justify-content: flex-start;
align-items: center;
flex-direction: column;
}
.header {
width: 100%;
padding: 10px 0;
img {
height: 60px;
width: 60px;
margin: 10px 0;
border-radius: 50%;
}
p {
font-size: 18px;
}
}
.details {
padding: 20px 0;
width: 100%;
p {
font-size: 16px;
}
.details-item {
width: 80%;
display: flex;
justify-content: space-between;
align-items: center;
margin-left: 10%;
padding: 10px 0;
.left-text {
color: gray;
}
}
.price {
padding: 20px 0;
border-bottom: 5px solid $background;
.left-text {
color: gray;
}
}
.details-item:nth-child(2) {
border-bottom: 5px solid $background;
}
}
.footer {
height: 75px;
.back-btn {
height: 45px;
width: 275px;
display: flex;
justify-content: center;
align-items: center;
background: $blue;
border: 1px solid $blue;
border-radius: 25px;
p {
font-size: 18px;
padding: 0;
color: white;
}
}
}
}
.flush {
height: calc(100vh - 2.3784rem);
display: flex;
justify-content: center;
align-items: center;
.back-btn {
height: 45px;
width: 275px;
display: flex;
justify-content: center;
align-items: center;
background: $blue;
border: 1px solid $blue;
border-radius: 25px;
p {
font-size: 18px;
padding: 0;
color: white;
}
}
}
</style>

+ 35
- 3
vue.config.js ファイルの表示

@@ -1,14 +1,22 @@
/*
* @Author: your name
* @Date: 2020-04-15 10:00:32
* @LastEditTime: 2022-02-23 17:36:48
* @LastEditTime: 2023-02-25 15:35:15
* @LastEditors: JinxChen
* @Description: In User Settings Edit
* @FilePath: \AlipayFrontEnd\vue.config.js
* @FilePath: \TelpoH5FrontendWeb\vue.config.js
*/
const autoprefixer = require('autoprefixer'); // 根据屏幕动态改变根元素font-size

const pxtorem = require('postcss-pxtorem'); // 把代码中px转为rem

// const CompressionWebpackPlugin = require('compress-webpack-plugin');

const CompressionPlugin = require("compression-webpack-plugin");
const port = process.env.port || process.env.npm_config_port || 8080;/* 7788 */ // dev port

module.exports = {
// 注意: 多页面配置 不再使用全路径,单页面时可以开启
publicPath: './',
outputDir: 'dist',
// assetsDir: 'static',
@@ -32,10 +40,34 @@ module.exports = {
// 允许生成 CSS source maps?
sourceMap: true,
// pass custom options to pre-processor loaders. e.g. to pass options to // sass-loader, use { sass: { ... } }
loaderOptions: {},
loaderOptions: {
sass: {
// 比如你可以这样向所有 Sass/Less 样式传入共享的全局变量
prependData: `@import "@/assets/css/public.scss";`
},
postcss: {
plugins: [
autoprefixer({
overrideBrowserslist: ["last 15 versions"]
}),
pxtorem({
rootValue: 37.5, // 换算的基数
// rootValue: 75, // 换算的基数
/* selectorBlackList: ["van"], */
propList: ["*"],
//exclude: /node_modules/
})
]
}
},
// Enable CSS modules for all css / pre-processor files. // This option does not affect *.vue files.
requireModuleExtension: true
},
configureWebpack: {
externals: {
'AMap': 'AMap'
}
},
chainWebpack: config => {
// 该配置用来配置打包生成的文件是否带hash值后缀,该值默认为true,
// 在模式为production的时候,打包出的js和css文件会自动添加hash值后缀。


読み込み中…
キャンセル
保存