First commit
|
@ -0,0 +1,2 @@
|
||||||
|
> 1%
|
||||||
|
last 2 versions
|
|
@ -0,0 +1,6 @@
|
||||||
|
# just a flag
|
||||||
|
ENV = 'development'
|
||||||
|
|
||||||
|
# base api
|
||||||
|
VUE_APP_BASE_API = '/dev-api'
|
||||||
|
VUE_APP_BASE_PORT = 1024
|
|
@ -0,0 +1,6 @@
|
||||||
|
# just a flag
|
||||||
|
ENV = 'production'
|
||||||
|
|
||||||
|
# base api
|
||||||
|
VUE_APP_BASE_API = '/'
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
.DS_Store
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
|
||||||
|
# local env files
|
||||||
|
.env.local
|
||||||
|
.env.*.local
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.idea
|
||||||
|
.vscode
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
*.sw?
|
|
@ -0,0 +1,29 @@
|
||||||
|
# vue-general
|
||||||
|
|
||||||
|
## Project setup
|
||||||
|
```
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and hot-reloads for development
|
||||||
|
```
|
||||||
|
npm run serve
|
||||||
|
```
|
||||||
|
|
||||||
|
### Compiles and minifies for production
|
||||||
|
```
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run your tests
|
||||||
|
```
|
||||||
|
npm run test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lints and fixes files
|
||||||
|
```
|
||||||
|
npm run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customize configuration
|
||||||
|
See [Configuration Reference](https://cli.vuejs.org/config/).
|
|
@ -0,0 +1,12 @@
|
||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
'@vue/app'
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
['import', {
|
||||||
|
libraryName: 'vant',
|
||||||
|
libraryDirectory: 'es',
|
||||||
|
style: true
|
||||||
|
}, 'vant']
|
||||||
|
]
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"name": "vue-general",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"serve": "vue-cli-service serve",
|
||||||
|
"build": "vue-cli-service build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@nutui/nutui": "^3.1.20",
|
||||||
|
"axios": "0.19.0",
|
||||||
|
"core-js": "^2.6.5",
|
||||||
|
"exif-js": "^2.3.0",
|
||||||
|
"image-conversion": "^1.1.9",
|
||||||
|
"mockjs": "^1.1.0",
|
||||||
|
"normalize.css": "7.0.0",
|
||||||
|
"qrcodejs2": "^0.0.2",
|
||||||
|
"vant": "^2.1.1",
|
||||||
|
"vue": "^2.6.10",
|
||||||
|
"vue-router": "^3.0.3",
|
||||||
|
"weixin-js-sdk": "^1.4.0-test"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vue/cli-plugin-babel": "^3.11.0",
|
||||||
|
"@vue/cli-service": "^3.11.0",
|
||||||
|
"babel-plugin-import": "^1.11.0",
|
||||||
|
"stylus": "^0.54.5",
|
||||||
|
"stylus-loader": "^3.0.2",
|
||||||
|
"vue-template-compiler": "^2.6.10"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
autoprefixer: {}
|
||||||
|
}
|
||||||
|
}
|
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,14 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||||
|
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||||
|
<title><%= webpackConfig.name %></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<!-- built files will be auto injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<template>
|
||||||
|
<div id="app">
|
||||||
|
<keep-alive>
|
||||||
|
<router-view/>
|
||||||
|
</keep-alive>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style lang="stylus">
|
||||||
|
#app
|
||||||
|
font-family 'Avenir', Helvetica, Arial, sans-serif
|
||||||
|
-webkit-font-smoothing antialiased
|
||||||
|
-moz-osx-font-smoothing grayscale
|
||||||
|
color #2c3e50
|
||||||
|
min-height 100vh
|
||||||
|
position relative
|
||||||
|
padding 0
|
||||||
|
margin 0
|
||||||
|
a
|
||||||
|
font-weight bold
|
||||||
|
color #2c3e50
|
||||||
|
&.router-link-exact-active
|
||||||
|
color #42b983
|
||||||
|
</style>
|
|
@ -0,0 +1,16 @@
|
||||||
|
import request from 'utils/request'
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过人脸认证返回的code获取个人二维码字符串
|
||||||
|
* @param {string} code
|
||||||
|
*/
|
||||||
|
export function GetQRCode(code){
|
||||||
|
return request({
|
||||||
|
url:'/api/v1/personverify/qrcode',
|
||||||
|
method:'get',
|
||||||
|
params:{
|
||||||
|
code
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
import request from 'utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 传入页面url,获取微信扫一扫调用签名
|
||||||
|
* @param {string} url
|
||||||
|
*/
|
||||||
|
export function GetScanParams(url){
|
||||||
|
return request({
|
||||||
|
url:'/app/v1/wechat/getjsparam',
|
||||||
|
method:'get',
|
||||||
|
params:{
|
||||||
|
url
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过二维码字符串获取运动员个人信息
|
||||||
|
* @param {string} code
|
||||||
|
*/
|
||||||
|
export function GetPeopleData(code){
|
||||||
|
return request({
|
||||||
|
url:'/api/v1/checking/get',
|
||||||
|
method:'get',
|
||||||
|
params:{
|
||||||
|
code
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 传入用户个人codemd5和编号进行绑定
|
||||||
|
* @param {string} CodeMd5
|
||||||
|
* @param {number} No
|
||||||
|
*/
|
||||||
|
export function AddNo(CodeMd5,No){
|
||||||
|
return request({
|
||||||
|
url:'/api/v1/checking/addno',
|
||||||
|
method:'post',
|
||||||
|
data:{
|
||||||
|
CodeMd5,
|
||||||
|
No
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
import request from 'utils/request'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 提交人脸及姓名、身份证号码,进行身份认证
|
||||||
|
* @param {object} data
|
||||||
|
*/
|
||||||
|
export function Login(data){
|
||||||
|
return request({
|
||||||
|
url:'/api/v1/wechat/runnerlogin',
|
||||||
|
method:'post',
|
||||||
|
data:{
|
||||||
|
Name: data.Name,
|
||||||
|
Phone:data.Phone
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Runnerverify(data){
|
||||||
|
return request({
|
||||||
|
url:'/api/v1/wechat/runnerverify',
|
||||||
|
method:'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import request from 'utils/request'
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理员登陆接口
|
||||||
|
* @param {number} Name
|
||||||
|
* @param {numebr} Password
|
||||||
|
*/
|
||||||
|
export function Login(loginForm){
|
||||||
|
return request({
|
||||||
|
url:'/api/v1/Users/login',
|
||||||
|
method:'post',
|
||||||
|
data:{
|
||||||
|
username:loginForm.username,
|
||||||
|
password:loginForm.password
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 101 KiB |
After Width: | Height: | Size: 140 KiB |
After Width: | Height: | Size: 364 KiB |
After Width: | Height: | Size: 135 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 426 KiB |
After Width: | Height: | Size: 442 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 1.3 MiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.2 MiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 5.6 KiB |
|
@ -0,0 +1,9 @@
|
||||||
|
import busVue from 'vue'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 在原型上挂载一个新的vue实例对象
|
||||||
|
* 用于储存公共值的同时,借用vue的$emit/$on/$off实现数据监听
|
||||||
|
*/
|
||||||
|
export default function (vue){
|
||||||
|
vue.prototype.$bus = new busVue()
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
import LoadingComponent from './loading.vue'
|
||||||
|
const Loading = {};
|
||||||
|
|
||||||
|
// 注册Loading
|
||||||
|
Loading.install = function (Vue) {
|
||||||
|
// 生成一个Vue的子类
|
||||||
|
// 同时这个子类也就是组件
|
||||||
|
const LoadingConstructor = Vue.extend(LoadingComponent);
|
||||||
|
// 生成一个该子类的实例
|
||||||
|
const instance = new LoadingConstructor();
|
||||||
|
// 将这个实例挂载在我创建的div上
|
||||||
|
instance.$mount(document.createElement('div'));
|
||||||
|
// 并将此div加入全局挂载点内部
|
||||||
|
document.body.appendChild(instance.$el);
|
||||||
|
// 通过Vue的原型注册一个方法
|
||||||
|
// 让所有实例共享这个方法
|
||||||
|
|
||||||
|
function handlerloading(text = '', full) {
|
||||||
|
instance.text = text; //文字是以最后一个show的展示
|
||||||
|
instance.full = true; //控制填充满屏,但不开放使用;
|
||||||
|
}
|
||||||
|
const loading_main = {
|
||||||
|
show(text = ''){
|
||||||
|
instance.loadings.push('show') //执行一次添加一个
|
||||||
|
handlerloading(text) //把text填充
|
||||||
|
},
|
||||||
|
hidden(){
|
||||||
|
instance.loadings.pop() //执行一次减少一个,通过数组长度控制显示与否(考虑到同时打开多个loading情况)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//将方法挂载全局
|
||||||
|
Vue.prototype.$Loading = loading_main;
|
||||||
|
}
|
||||||
|
export default Loading
|
|
@ -0,0 +1,139 @@
|
||||||
|
<template>
|
||||||
|
<div id="vue-loading" v-show="loadings.length">
|
||||||
|
<div class="filter" v-show="full"></div>
|
||||||
|
<div class="loader-wrap">
|
||||||
|
<!-- <div class="loader"></div> -->
|
||||||
|
<div class="logo">
|
||||||
|
<img src="@/assets/image/loding-logo.png" alt="">
|
||||||
|
</div>
|
||||||
|
<div class="hint">{{text}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name:'Loading',
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
loadings:[],
|
||||||
|
text:'',
|
||||||
|
full:false, //是否展示蒙层
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
#vue-loading
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
position absolute
|
||||||
|
left 0
|
||||||
|
top 0
|
||||||
|
z-index 999
|
||||||
|
.filter
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
background rgba(255,255,255,0.3);
|
||||||
|
.loader-wrap
|
||||||
|
position absolute
|
||||||
|
left 50%
|
||||||
|
top 50%
|
||||||
|
transform translate(-50%,-50%)
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
justify-content center
|
||||||
|
.logo
|
||||||
|
// width 100%
|
||||||
|
text-align center
|
||||||
|
img
|
||||||
|
animation scal 0.8s infinite
|
||||||
|
opacity 0.8
|
||||||
|
width 16vw
|
||||||
|
.hint
|
||||||
|
margin-top 10px
|
||||||
|
font-size 14px
|
||||||
|
color #666
|
||||||
|
text-shadow 1px 1px 3px white
|
||||||
|
.loader
|
||||||
|
width 2.5em
|
||||||
|
height 2.5em
|
||||||
|
transform rotate(165deg)
|
||||||
|
position relative
|
||||||
|
&:before
|
||||||
|
animation before 2s infinite
|
||||||
|
&:after
|
||||||
|
animation after 2s infinite
|
||||||
|
&:before,
|
||||||
|
&:after
|
||||||
|
content ''
|
||||||
|
position absolute
|
||||||
|
top 50%
|
||||||
|
left 50%
|
||||||
|
display block
|
||||||
|
width 0.5em
|
||||||
|
height 0.5em
|
||||||
|
border-radius 0.25em
|
||||||
|
transform translate(-50%, -50%)
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@keyframes scal {
|
||||||
|
0%{
|
||||||
|
transform:scale(0.8);
|
||||||
|
}
|
||||||
|
50%{
|
||||||
|
transform:scale(1);
|
||||||
|
}
|
||||||
|
100%{
|
||||||
|
transform:scale(0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes before {
|
||||||
|
0% {
|
||||||
|
width: 0.5em;
|
||||||
|
box-shadow: 1em -0.5em rgba(225, 20, 98, 0.75), -1em 0.5em rgba(111, 202, 220, 0.75);
|
||||||
|
}
|
||||||
|
35% {
|
||||||
|
width: 2.5em;
|
||||||
|
box-shadow: 0 -0.5em rgba(225, 20, 98, 0.75), 0 0.5em rgba(111, 202, 220, 0.75);
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
width: 0.5em;
|
||||||
|
box-shadow: -1em -0.5em rgba(225, 20, 98, 0.75), 1em 0.5em rgba(111, 202, 220, 0.75);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
box-shadow: 1em -0.5em rgba(225, 20, 98, 0.75), -1em 0.5em rgba(111, 202, 220, 0.75);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes after {
|
||||||
|
0% {
|
||||||
|
height: 0.5em;
|
||||||
|
box-shadow: 0.5em 1em rgba(61, 184, 143, 0.75), -0.5em -1em rgba(233, 169, 32, 0.75);
|
||||||
|
}
|
||||||
|
35% {
|
||||||
|
height: 2.5em;
|
||||||
|
box-shadow: 0.5em 0 rgba(61, 184, 143, 0.75), -0.5em 0 rgba(233, 169, 32, 0.75);
|
||||||
|
}
|
||||||
|
70% {
|
||||||
|
height: 0.5em;
|
||||||
|
box-shadow: 0.5em -1em rgba(61, 184, 143, 0.75), -0.5em 1em rgba(233, 169, 32, 0.75);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
box-shadow: 0.5em 1em rgba(61, 184, 143, 0.75), -0.5em -1em rgba(233, 169, 32, 0.75);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Attempt to center the whole thing!
|
||||||
|
*/
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.loader {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(50% - 1.25em);
|
||||||
|
left: calc(50% - 1.25em);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import ToastComponent from './toast.vue'
|
||||||
|
const Toast = {};
|
||||||
|
|
||||||
|
// 注册Toast
|
||||||
|
Toast.install = function (Vue) {
|
||||||
|
// 生成一个Vue的子类
|
||||||
|
// 同时这个子类也就是组件
|
||||||
|
const ToastConstructor = Vue.extend(ToastComponent);
|
||||||
|
// 生成一个该子类的实例
|
||||||
|
const instance = new ToastConstructor();
|
||||||
|
// 将这个实例挂载在我创建的div上
|
||||||
|
instance.$mount(document.createElement('div'));
|
||||||
|
// 并将此div加入全局挂载点内部
|
||||||
|
document.body.appendChild(instance.$el);
|
||||||
|
//定义一个外部的变量,用于控制调用多次提示组件时,清除延时器
|
||||||
|
let timer;
|
||||||
|
// 通过Vue的原型注册一个方法
|
||||||
|
// 让所有实例共享这个方法
|
||||||
|
class message_main {
|
||||||
|
constructor(){}
|
||||||
|
static all_message(msg, type, duration) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
timer = setTimeout(() => {
|
||||||
|
instance.successMessage = []
|
||||||
|
instance.errorMessage = [];
|
||||||
|
}, duration);
|
||||||
|
if(type == 'success'){
|
||||||
|
instance.successMessage = [msg];
|
||||||
|
instance.errorMessage = [];
|
||||||
|
}else if (type == 'error'){
|
||||||
|
instance.successMessage = [];
|
||||||
|
instance.errorMessage = [msg];
|
||||||
|
}
|
||||||
|
instance.type = type;
|
||||||
|
}
|
||||||
|
success(msg, duration = 2000) { //默认两秒停留时长
|
||||||
|
message_main.all_message({txt:msg,key:new Date().getTime()}, 'success', duration);
|
||||||
|
}
|
||||||
|
error(msg, duration = 2000) {
|
||||||
|
message_main.all_message({txt:msg,key:new Date().getTime()}, 'error', duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//将方法挂载全局
|
||||||
|
Vue.prototype.$Toast = new message_main();
|
||||||
|
}
|
||||||
|
export default Toast
|
|
@ -0,0 +1,57 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 全局提示框 -->
|
||||||
|
<transition-group name="fade">
|
||||||
|
<div name='fade' v-for="item in successMessage" :key='item.key' class="dialog-tips">
|
||||||
|
<span>{{item.txt}}</span>
|
||||||
|
</div>
|
||||||
|
</transition-group>
|
||||||
|
|
||||||
|
<transition-group name="fade">
|
||||||
|
<div v-for="item in errorMessage" :key='item.key' class="dialog-tips error">
|
||||||
|
<span>{{item.txt}}</span>
|
||||||
|
</div>
|
||||||
|
</transition-group>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
successMessage: [],
|
||||||
|
errorMessage:[],
|
||||||
|
type:'success',
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
$Height = 35px
|
||||||
|
|
||||||
|
.dialog-tips
|
||||||
|
position absolute
|
||||||
|
z-index 999
|
||||||
|
width 100vw
|
||||||
|
height $Height
|
||||||
|
background-color rgba(123,210,57,0.85)
|
||||||
|
color white
|
||||||
|
border-radius 0 0 3px 3px
|
||||||
|
left 50%
|
||||||
|
top 0
|
||||||
|
transform translate(-50%,0)
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
transition all 0.2s
|
||||||
|
align-items center
|
||||||
|
&.error
|
||||||
|
background-color rgba(255,70,0,0.85)
|
||||||
|
span
|
||||||
|
font-size 14px
|
||||||
|
line-height $Height
|
||||||
|
color red
|
||||||
|
// 通知动画
|
||||||
|
.fade-enter-active, .fade-leave-active
|
||||||
|
transform translate(-50%,0%)
|
||||||
|
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */
|
||||||
|
transform translate(-50%,-100%)
|
||||||
|
</style>
|
|
@ -0,0 +1,37 @@
|
||||||
|
import Vue from 'vue'
|
||||||
|
import App from './App.vue'
|
||||||
|
import router from './router'
|
||||||
|
import 'normalize.css/normalize.css' // 重置、初始化css样式的库
|
||||||
|
import '@/permission' // 挂载路由后添加路由拦截器(守卫 )
|
||||||
|
|
||||||
|
// import NutUI from "@nutui/nutui";
|
||||||
|
// import "@nutui/nutui/dist/style.css";
|
||||||
|
// Vue.use(NutUI)
|
||||||
|
|
||||||
|
import Loading from 'globalComponents/Loading'
|
||||||
|
import Toast from 'globalComponents/Toast'
|
||||||
|
Vue.use(Toast) //启用全局提示组件
|
||||||
|
Vue.use(Loading) //使用全局loading组件
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果需要bus总线模式
|
||||||
|
* this.$bus.$data.xxx = xxx
|
||||||
|
* this.$bus.emit('change',data)
|
||||||
|
* this.$bus.$on('change',data => console.log(data))
|
||||||
|
* this.$bus.$off('change')
|
||||||
|
*/
|
||||||
|
// import bus from './bus'
|
||||||
|
// Vue.use(bus) //使用BUS总线模式,实现组件间任意传值
|
||||||
|
|
||||||
|
Vue.config.productionTip = false //生产模式下关闭vue在控制台的提示
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV == 'development'){
|
||||||
|
require('./mock/index.js');
|
||||||
|
}
|
||||||
|
|
||||||
|
const vm = new Vue({
|
||||||
|
router,
|
||||||
|
render: h => h(App),
|
||||||
|
}).$mount('#app')
|
||||||
|
|
||||||
|
export default vm
|
|
@ -0,0 +1,11 @@
|
||||||
|
let runnerlogin = {
|
||||||
|
code: 0,
|
||||||
|
data: ['https://blog.skywt.cn/usr/themes/Daydream/assets/img/avatar.png'],
|
||||||
|
msg: '成功'
|
||||||
|
}
|
||||||
|
|
||||||
|
let home = {
|
||||||
|
runnerlogin
|
||||||
|
}
|
||||||
|
|
||||||
|
export default home
|
|
@ -0,0 +1,16 @@
|
||||||
|
import Mock from 'mockjs'
|
||||||
|
|
||||||
|
import login from './login'
|
||||||
|
import home from './home'
|
||||||
|
|
||||||
|
Mock.mock('/api/v1/Users/login', 'post', () => {
|
||||||
|
return login.login_request
|
||||||
|
})
|
||||||
|
|
||||||
|
Mock.mock('/api/v1/wechat/runnerlogin', 'post', () => {
|
||||||
|
return home.runnerlogin
|
||||||
|
})
|
||||||
|
|
||||||
|
Mock.mock('/dev-api/api/v1/wechat/runnerlogin', 'post', () => {
|
||||||
|
return home.runnerlogin
|
||||||
|
})
|
|
@ -0,0 +1,9 @@
|
||||||
|
let login_request = {
|
||||||
|
code: 200
|
||||||
|
}
|
||||||
|
|
||||||
|
let login = {
|
||||||
|
login_request
|
||||||
|
}
|
||||||
|
|
||||||
|
export default login
|
|
@ -0,0 +1,47 @@
|
||||||
|
import router from './router'
|
||||||
|
import getPageTitle from 'utils/getPageTitle'
|
||||||
|
import { Checkrunner } from 'api/home'
|
||||||
|
|
||||||
|
|
||||||
|
import Vue from 'vue';
|
||||||
|
import { Toast } from 'vant';
|
||||||
|
Vue.use(Toast);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 路由拦截
|
||||||
|
// router.beforeEach(async(to, from, next) => {
|
||||||
|
// document.title = getPageTitle(to.meta.title) // set page title
|
||||||
|
// if(to.name ==='Admin'){
|
||||||
|
// if(sessionStorage.loginStatus){
|
||||||
|
// next()
|
||||||
|
// }else{
|
||||||
|
// next('/login')
|
||||||
|
// Toast('请登录!')
|
||||||
|
// }
|
||||||
|
// }else if(to.name === 'Home'){
|
||||||
|
// let skipUrl = 'http://5gmalasong.hnabc.cn/app'
|
||||||
|
// let wechatUrl = 'http://5gmalasong.hnabc.cn'
|
||||||
|
// let routerUrl = escape('/#/home')
|
||||||
|
// Checkrunner().then(res =>{
|
||||||
|
// if(res.code === 0){
|
||||||
|
// sessionStorage.Code = res.data.Code
|
||||||
|
// next('/QRCode')
|
||||||
|
// }else if(res.code === 3009){
|
||||||
|
// location.href = wechatUrl + '/wechat/login/runner?returnurl=' + skipUrl + routerUrl
|
||||||
|
// // alert(baseUrl + 'wechat/login/runner?returnurl=' + baseUrl + '#/home')
|
||||||
|
// }else{
|
||||||
|
// next()
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }else{
|
||||||
|
// next()
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//跳转完成后
|
||||||
|
router.afterEach(() => {
|
||||||
|
//to do something
|
||||||
|
})
|
|
@ -0,0 +1,45 @@
|
||||||
|
import Vue from 'vue'
|
||||||
|
import Router from 'vue-router'
|
||||||
|
import Home from './views/home'
|
||||||
|
|
||||||
|
|
||||||
|
Vue.use(Router)
|
||||||
|
|
||||||
|
export default new Router({
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/',
|
||||||
|
redirect:'/login'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/login',
|
||||||
|
name:'Login',
|
||||||
|
component:() => import('./views/login'),
|
||||||
|
meta:{ title:'登陆' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/home',
|
||||||
|
name:'Home',
|
||||||
|
component:() => import('./views/home'),
|
||||||
|
meta:{ title:'人脸注册' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path:'/photos',
|
||||||
|
name:'Photos',
|
||||||
|
component:() => import('./views/photos'),
|
||||||
|
meta:{ title:'' }
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// path:'/QRCode',
|
||||||
|
// name:'QRCode',
|
||||||
|
// component:() => import('./views/QRCode'),
|
||||||
|
// meta:{ title:'身份二维码' }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// path:'/admin',
|
||||||
|
// name:'Admin',
|
||||||
|
// component:() => import('./views/admin'),
|
||||||
|
// meta:{ title:'物资发放' }
|
||||||
|
// },
|
||||||
|
]
|
||||||
|
})
|
|
@ -0,0 +1,2 @@
|
||||||
|
export const title = '2019长沙国际马拉松纪念照' //标签页title
|
||||||
|
export const globalSuccessToast = true //是否在request中开启全局请求成功的成功提示(基于全局Toast)
|
|
@ -0,0 +1,132 @@
|
||||||
|
$themeColor = rgb(128,51,134);
|
||||||
|
$fontColor = rgb(77,9,86)
|
||||||
|
|
||||||
|
Button()
|
||||||
|
background linear-gradient(135deg,#fa2c19 0%,#fa6419 100%)
|
||||||
|
color white
|
||||||
|
padding 10px
|
||||||
|
width 85%
|
||||||
|
text-align center
|
||||||
|
border-radius 25px
|
||||||
|
border: 1px solid transparent
|
||||||
|
|
||||||
|
hint()
|
||||||
|
width 100%
|
||||||
|
box-sizing border-box
|
||||||
|
position absolute
|
||||||
|
text-indent 2em
|
||||||
|
z-index 9999
|
||||||
|
padding 10px
|
||||||
|
background rgba(255,255,255,0.8)
|
||||||
|
color rgb(0,133,208)
|
||||||
|
font-size 12px
|
||||||
|
line-height 1.4em
|
||||||
|
|
||||||
|
.home-wrap
|
||||||
|
overflow hidden
|
||||||
|
height: 100vh
|
||||||
|
width: 100%
|
||||||
|
.bottom-img
|
||||||
|
position absolute
|
||||||
|
bottom 0px
|
||||||
|
width 100%
|
||||||
|
left 0
|
||||||
|
.hint
|
||||||
|
width 100%
|
||||||
|
box-sizing border-box
|
||||||
|
position absolute
|
||||||
|
text-indent 2em
|
||||||
|
z-index 9999
|
||||||
|
padding 10px
|
||||||
|
background rgba(255,255,255,0.3)
|
||||||
|
backdrop-filter: blur(30)
|
||||||
|
color white
|
||||||
|
font-size 12px
|
||||||
|
line-height 1.4em
|
||||||
|
bottom 0
|
||||||
|
.background-wrap
|
||||||
|
position: fixed
|
||||||
|
z-index: -1
|
||||||
|
// .background-image
|
||||||
|
.top-brand-wrap
|
||||||
|
color: white
|
||||||
|
text-align: center
|
||||||
|
margin-top: 15vh
|
||||||
|
.info-card
|
||||||
|
position relative
|
||||||
|
// z-index 999
|
||||||
|
width 90%
|
||||||
|
box-shadow: 0 4px 10px #00000012
|
||||||
|
-webkit-box-shadow: 0px 4px 10px 0px rgba(0,0,0,.07)
|
||||||
|
background rgba(255, 255, 255, 0.7)
|
||||||
|
backdrop-filter: blur(20px)
|
||||||
|
-webkit-backdrop-filter: blur(20px)
|
||||||
|
margin 0 auto
|
||||||
|
margin-top 10vh
|
||||||
|
z-index 500
|
||||||
|
padding-bottom 30px
|
||||||
|
padding-top 30px
|
||||||
|
.form
|
||||||
|
width 100%
|
||||||
|
padding 30px
|
||||||
|
box-sizing border-box
|
||||||
|
position relative
|
||||||
|
// z-index 999
|
||||||
|
.van-cell
|
||||||
|
height: 48px
|
||||||
|
background: transparent
|
||||||
|
&::after
|
||||||
|
// border-bottom: 2px solid #f5f6f7
|
||||||
|
border-bottom: 2px solid #323233
|
||||||
|
>>>input
|
||||||
|
height 48px
|
||||||
|
// >>>field__body
|
||||||
|
.button
|
||||||
|
background linear-gradient(135deg,#fa2c19 0%,#fa6419 100%)
|
||||||
|
color white
|
||||||
|
padding 10px
|
||||||
|
width 85%
|
||||||
|
text-align center
|
||||||
|
border-radius 25px
|
||||||
|
border: 1px solid transparent
|
||||||
|
margin-bottom: 20px
|
||||||
|
.register
|
||||||
|
background linear-gradient(135deg,rgb(255,158,13) 0%,rgb(255,167,13) 45%,rgb(255,182,13) 83%,rgb(255,190,13) 100%)
|
||||||
|
.flex-container
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
.main
|
||||||
|
width 100vw
|
||||||
|
position relative
|
||||||
|
z-index 800
|
||||||
|
.hint
|
||||||
|
width 70%
|
||||||
|
border-radius 10px
|
||||||
|
height 100px
|
||||||
|
background rgba(255,255,255,0.9)
|
||||||
|
position absolute
|
||||||
|
left 50%
|
||||||
|
top 50%
|
||||||
|
transform translate(-50%,-50%)
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
color rgba(0,133,208,1)
|
||||||
|
.imgs-wrap
|
||||||
|
overflow hidden
|
||||||
|
width 100%
|
||||||
|
padding 8px
|
||||||
|
padding-top 40px
|
||||||
|
padding-bottom 50px
|
||||||
|
box-sizing border-box
|
||||||
|
.imgs-item
|
||||||
|
font-size 0
|
||||||
|
border 1px solid white
|
||||||
|
width 100%
|
||||||
|
margin-bottom 10px
|
||||||
|
border-radius 10px
|
||||||
|
overflow hidden
|
||||||
|
img
|
||||||
|
width 100%
|
|
@ -0,0 +1,55 @@
|
||||||
|
// 微信扫一扫封装,传入callback在扫码执行并接收一个code参数,修改api即可;
|
||||||
|
|
||||||
|
import wx from 'weixin-js-sdk'
|
||||||
|
import { GetScanParams } from 'api/admin'
|
||||||
|
import vm from '@/main.js'
|
||||||
|
|
||||||
|
export default function WeChatScan(callback){
|
||||||
|
GetScanParams(window.location.href.split('#')[0]).then(res => {
|
||||||
|
if(res.code === 0){
|
||||||
|
openScan(res.data,callback)
|
||||||
|
}else{
|
||||||
|
vm.$Toast.error('签名信息获取失败!')
|
||||||
|
}
|
||||||
|
}).catch(err => vm.$Toast.error('签名信息获取失败,请重试!'))
|
||||||
|
}
|
||||||
|
|
||||||
|
function openScan(data,callback){
|
||||||
|
wx.config({
|
||||||
|
debug: false, // 开启调试模式
|
||||||
|
appId: data.appid, // 公众号的唯一标识
|
||||||
|
timestamp: data.Timestamp, // 生成签名的时间戳
|
||||||
|
nonceStr: data.NonceStr, // 生成签名的随机串
|
||||||
|
signature: data.Signature, // 签名
|
||||||
|
jsApiList: [ 'scanQRCode' ] // 需要使用的JS接口列表
|
||||||
|
});
|
||||||
|
|
||||||
|
wx.ready(function () {
|
||||||
|
var isBack = callback
|
||||||
|
wx.checkJsApi({ // 判断当前客户端版本是否支持指定JS接口
|
||||||
|
jsApiList: [ 'scanQRCode' ],
|
||||||
|
success: function (res) { // 以键值对的形式返回,可用true,不可用false。如:{"checkResult":{"scanQRCode":true},"errMsg":"checkJsApi:ok"}
|
||||||
|
if (res.checkResult.scanQRCode === true) {
|
||||||
|
wx.scanQRCode({ // 微信扫一扫接口
|
||||||
|
needResult: 1, // 默认为0,扫描结果由微信处理,1则直接返回扫描结果,
|
||||||
|
scanType: ['qrCode', 'barCode'], // 可以指定扫二维码还是一维码,默认二者都有
|
||||||
|
success: function (res) {
|
||||||
|
const getCode = res.resultStr // 当needResult 为 1 时,扫码返回的结果
|
||||||
|
isBack(getCode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
vm.$Toast.error('抱歉,当前客户端版本不支持扫一扫!')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fail: function (res) { // 检测getNetworkType该功能失败时处理
|
||||||
|
vm.$Toast.error('失败' + res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
/* 处理失败验证 */
|
||||||
|
wx.error(function (res) {
|
||||||
|
vm.$Toast.error('签名信息错误: ' + res.errMsg)
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { title } from '@/settings'
|
||||||
|
|
||||||
|
export default function getPageTitle(pageTitle) {
|
||||||
|
if (pageTitle) {
|
||||||
|
return `${pageTitle} - ${title}`
|
||||||
|
}
|
||||||
|
return `${title}`
|
||||||
|
}
|
|
@ -0,0 +1,167 @@
|
||||||
|
import EXIF from 'exif-js' //获取拍照时的信息的库(角度),用于调正图片展示角度
|
||||||
|
import imageConversion from 'image-conversion' //图片压缩、转换处理库
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 压缩文件函数
|
||||||
|
* 传入图片-压缩后的尺寸(kb)-压缩率
|
||||||
|
* 返回压缩后的文件
|
||||||
|
* @param {file} imageFile
|
||||||
|
* @param {number} compressSize
|
||||||
|
* @param {number} quality
|
||||||
|
*/
|
||||||
|
export function JudgeCompress(imageFile, compressSize, quality = 0.99) { //传入图片文件-规定压缩后的尺寸(kb)-压缩率
|
||||||
|
return new Promise(function (resolve,reject) {
|
||||||
|
if(imageFile.size < 100 * 1024) { //如果图片小于规定尺寸,则直接返回
|
||||||
|
resolve(imageFile)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imageConversion.compressAccurately(imageFile,{size:compressSize,accuracy:quality,scale:0.5}).then(res =>{ //压缩函数
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片文件转base64 DataUrl
|
||||||
|
* @param {file} file
|
||||||
|
*/
|
||||||
|
export function FiletoDataURL(file){
|
||||||
|
return new Promise((resolve,reject) => {
|
||||||
|
imageConversion.filetoDataURL(file).then(res => {
|
||||||
|
resolve(res)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断文件类型是否为image
|
||||||
|
* @param {file} file
|
||||||
|
*/
|
||||||
|
export function CheckFile(file) {
|
||||||
|
if (!/image\/\w+/.test(file.type)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旋转图片总体函数
|
||||||
|
* 传入文件,返回旋转后的文件
|
||||||
|
* @param {file} imageFile
|
||||||
|
*/
|
||||||
|
export function RotateImage(imageFile) {
|
||||||
|
return new Promise((resolve,reject)=>{
|
||||||
|
imageConversion.filetoDataURL(imageFile).then(res =>{ //把文件转成图片格式用于旋转
|
||||||
|
var image = new window.Image();
|
||||||
|
image.src = res
|
||||||
|
image.onload = function () {
|
||||||
|
// 旋转图片
|
||||||
|
let newImage = handleRotate(image)
|
||||||
|
imageConversion.dataURLtoFile(newImage.src).then(res => {
|
||||||
|
resolve(res) //返回的是file(文件)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// 使用如上filetoDataURL插件方法实现文件转url 而 替代本手写方法 by:luqiang 20191012
|
||||||
|
// var reader = new FileReader();
|
||||||
|
// reader.onload = function(e){
|
||||||
|
// }
|
||||||
|
// reader.readAsDataURL(imageFile); //先挂载onload方法再绑定read事件
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理旋转函数,传入图片,返回旋转正确的图片
|
||||||
|
* @param {img} image
|
||||||
|
*/
|
||||||
|
function handleRotate(image){ //处理旋转的函数
|
||||||
|
var width = image.width;
|
||||||
|
var height = image.height;
|
||||||
|
var canvas = document.createElement("canvas")
|
||||||
|
var ctx = canvas.getContext('2d');
|
||||||
|
var newImage = new Image();
|
||||||
|
//旋转图片操作
|
||||||
|
EXIF.getData(image, function () {
|
||||||
|
var orientation = EXIF.getTag(this, 'Orientation');
|
||||||
|
let imageDate = null
|
||||||
|
switch (orientation) {
|
||||||
|
//正常状态
|
||||||
|
case 1:
|
||||||
|
// alert('旋转0°');
|
||||||
|
newImage.src = image.src;
|
||||||
|
break;
|
||||||
|
//旋转90度
|
||||||
|
case 6:
|
||||||
|
// alert('旋转90°');
|
||||||
|
canvas.height = width;
|
||||||
|
canvas.width = height;
|
||||||
|
ctx.rotate(Math.PI / 2);
|
||||||
|
ctx.translate(0, -height);
|
||||||
|
ctx.drawImage(image,0,0)
|
||||||
|
imageDate = canvas.toDataURL('image/jpeg', 1)
|
||||||
|
newImage.src = imageDate;
|
||||||
|
break;
|
||||||
|
//旋转180°
|
||||||
|
case 3:
|
||||||
|
// alert('旋转180°');
|
||||||
|
canvas.height = height;
|
||||||
|
canvas.width = width;
|
||||||
|
ctx.rotate(Math.PI);
|
||||||
|
ctx.translate(-width, -height);
|
||||||
|
ctx.drawImage(image,0,0)
|
||||||
|
imageDate = canvas.toDataURL('image/jpeg', 1)
|
||||||
|
newImage.src = imageDate;
|
||||||
|
break;
|
||||||
|
//旋转270°
|
||||||
|
case 8:
|
||||||
|
// alert('旋转270°');
|
||||||
|
canvas.height = width;
|
||||||
|
canvas.width = height;
|
||||||
|
ctx.rotate(-Math.PI / 2);
|
||||||
|
ctx.translate(-height, 0);
|
||||||
|
ctx.drawImage(image, -810,0) //????安卓要-810????
|
||||||
|
// ctx.drawImage(image)
|
||||||
|
imageDate = canvas.toDataURL('image/jpeg', 1)
|
||||||
|
newImage.src = imageDate;
|
||||||
|
break;
|
||||||
|
//undefined时不旋转
|
||||||
|
case undefined:
|
||||||
|
// alert('旋转0°');
|
||||||
|
newImage.src = image.src;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
newImage.src = image.src;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return newImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 压缩图片函数 --> by:luqiang 20191012 使用imageConversion库代替手写操作以精准控制压缩后的文件尺寸
|
||||||
|
// function Compress(image, quality) {
|
||||||
|
// var canvas = document.createElement('canvas')
|
||||||
|
// var ctx = canvas.getContext('2d');
|
||||||
|
// var width = image.width;
|
||||||
|
// var height = image.height;
|
||||||
|
// canvas.width = width;
|
||||||
|
// canvas.height = height;
|
||||||
|
// ctx.drawImage(image, 0, 0, width, height);
|
||||||
|
// //压缩操作
|
||||||
|
// var imageData = canvas.toDataURL("image/jpeg", quality);
|
||||||
|
// var imageLength = image.src.length;
|
||||||
|
// console.log("压缩前:" + imageLength);
|
||||||
|
// console.log("压缩后:" + imageData.length,imageData);
|
||||||
|
// console.log("压缩率:" + ~~(100 * (imageLength - imageData.length) / imageLength) + "%");
|
||||||
|
// return imageData;
|
||||||
|
// }
|
|
@ -0,0 +1,52 @@
|
||||||
|
import axios from 'axios'
|
||||||
|
import router from '@/router'
|
||||||
|
import vm from '@/main.js'
|
||||||
|
import { globalSuccessToast } from '@/settings'
|
||||||
|
|
||||||
|
const service = axios.create({
|
||||||
|
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
||||||
|
withCredentials: true, // 设置是否在请求中携带cookie
|
||||||
|
timeout: 30000 // 请求超时时间
|
||||||
|
})
|
||||||
|
|
||||||
|
// request interceptor(请求拦截器)
|
||||||
|
service.interceptors.request.use(
|
||||||
|
config => {
|
||||||
|
vm.$Loading.show()
|
||||||
|
// 给config统一配置属性
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
return Promise.reject(error)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
//response (响应拦截器)
|
||||||
|
service.interceptors.response.use(
|
||||||
|
response => {
|
||||||
|
vm.$Loading.hidden()
|
||||||
|
const res = response.data
|
||||||
|
const code = response.status
|
||||||
|
if (code !== 200) {
|
||||||
|
vm.$Toast.error(res.msg)
|
||||||
|
return Promise.reject(new Error(res.msg || 'Error'))
|
||||||
|
} else {
|
||||||
|
if (globalSuccessToast && res.code == 0) { //全局成功提示
|
||||||
|
// vm.$Toast.success('查询成功!') //暂时不要
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error => {
|
||||||
|
vm.$Loading.hidden()
|
||||||
|
if (error.response.status && error.response.status == 401) { //拦截401,代表登陆失效,触发页面刷新后再触发路由拦截,拦截到重新登录
|
||||||
|
// 401一般是权限问题或者登录失效
|
||||||
|
// router.push('/login') //如果项目存在登录验证,应该在这里返回登录页面重新登录;
|
||||||
|
console.log('response status is 401')
|
||||||
|
}
|
||||||
|
vm.$Toast.error(error)
|
||||||
|
return Promise.reject(error) //请求错误不return出去,直接在这里处理toast
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default service
|
|
@ -0,0 +1,33 @@
|
||||||
|
import waterMark from '@/assets/image/waterMark.png'
|
||||||
|
function drawAndShareImage(imgUrl){
|
||||||
|
return new Promise((resolve,reject) => {
|
||||||
|
var canvas = document.createElement("canvas");
|
||||||
|
canvas.width = 1280;
|
||||||
|
canvas.height = 720;
|
||||||
|
var context = canvas.getContext("2d");
|
||||||
|
|
||||||
|
// context.rect(0 , 0 , canvas.width , canvas.height);
|
||||||
|
// context.fillStyle = "#fff";
|
||||||
|
// context.fill();
|
||||||
|
|
||||||
|
var myImage = new Image();
|
||||||
|
myImage.crossOrigin = 'Anonymous'; //允许跨域
|
||||||
|
myImage.src = imgUrl; //背景图片
|
||||||
|
myImage.onload = function(){
|
||||||
|
context.drawImage(myImage , 0 , 0 , 1280 , 720);
|
||||||
|
// context.font = "60px Courier New";
|
||||||
|
// context.fillText("我是文字",350,450);
|
||||||
|
var waterMarkImg = new Image();
|
||||||
|
waterMarkImg.crossOrigin = 'Anonymous';
|
||||||
|
waterMarkImg.src = waterMark; //水印图
|
||||||
|
|
||||||
|
waterMarkImg.onload = function(){ //第二次绘制,绘制logo即可
|
||||||
|
context.drawImage(waterMarkImg , 0 , 0 , 499 , 210);
|
||||||
|
var base64 = canvas.toDataURL("image/jpg"); //"image/png" 这里注意一下
|
||||||
|
resolve(base64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export default drawAndShareImage
|
|
@ -0,0 +1,152 @@
|
||||||
|
<template>
|
||||||
|
<div class='QR-code-wrap'>
|
||||||
|
<div class="info-card">
|
||||||
|
<div class="title">身份二维码</div>
|
||||||
|
<div class="QR-wrap">
|
||||||
|
<div class="temp">
|
||||||
|
<div class="QRImg" ref="qrCodeUrl"></div>
|
||||||
|
</div>
|
||||||
|
<div class="hint">
|
||||||
|
<div>本码用于领取物资!请妥善保管二维码!</div>
|
||||||
|
<div>(刷新倒计时:<span style="color:red">{{times}}s</span>)
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="button" @click="Update">刷新</div>
|
||||||
|
</div>
|
||||||
|
<img class="bottom-img" src="@/assets/image/logo.png" alt="">
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import QRCode from 'qrcodejs2'
|
||||||
|
import { GetQRCode } from 'api/QRCode'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name:'QRCode',
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
times: 0,
|
||||||
|
Code: null,
|
||||||
|
timer: null,
|
||||||
|
upDateTime:30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activated(){
|
||||||
|
this.Code = sessionStorage.Code
|
||||||
|
if(this.Code){
|
||||||
|
this.getQRCode(this.Code)
|
||||||
|
}else{
|
||||||
|
this.$Toast.error('未认证人脸信息!即将返回!')
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$router.push('/home')
|
||||||
|
},800)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deactivated(){
|
||||||
|
clearInterval(this.timer)
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
getQRCode(code,flag){
|
||||||
|
GetQRCode(code).then(res =>{
|
||||||
|
if(res.code === 0){
|
||||||
|
this.QRCode = res.data.Code
|
||||||
|
this.creatQrCode(this.QRCode)
|
||||||
|
if(flag){ //如果是刷新操作则提示一下
|
||||||
|
this.$Toast.success('二维码刷新成功')
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
this.$Toast.error('查询二维码失败!即将返回!')
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$router.push('/home')
|
||||||
|
},800)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Update(){ //刷新二维码
|
||||||
|
this.getQRCode(this.Code,true)
|
||||||
|
},
|
||||||
|
creatQrCode(text) { //创建二维码
|
||||||
|
clearInterval(this.timer)
|
||||||
|
this.times = this.upDateTime
|
||||||
|
this.$refs.qrCodeUrl.innerHTML = '' //每次创建二维码先清空之前的二维码图片
|
||||||
|
var qrcode = new QRCode(this.$refs.qrCodeUrl, {
|
||||||
|
text:text,
|
||||||
|
width:200,
|
||||||
|
height:200,
|
||||||
|
colorDark: '#000000',
|
||||||
|
colorLight: '#ffffff',
|
||||||
|
correctLevel: QRCode.CorrectLevel.H
|
||||||
|
})
|
||||||
|
// 每三十秒刷新一次二维码
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
if(this.times == 0){
|
||||||
|
this.getQRCode(this.Code,true)
|
||||||
|
}else{
|
||||||
|
this.times --
|
||||||
|
}
|
||||||
|
},1000)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.QR-code-wrap
|
||||||
|
box-sizing border-box
|
||||||
|
width 100%
|
||||||
|
overflow hidden
|
||||||
|
height 100vh
|
||||||
|
position relative
|
||||||
|
.bottom-img
|
||||||
|
position absolute
|
||||||
|
bottom 0px
|
||||||
|
width 100%
|
||||||
|
left 0
|
||||||
|
.info-card
|
||||||
|
position relative
|
||||||
|
z-index 999
|
||||||
|
width 90%
|
||||||
|
border-radius 15px
|
||||||
|
background white
|
||||||
|
margin 0 auto
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
padding-bottom 30px
|
||||||
|
overflow hidden
|
||||||
|
margin-top 70px
|
||||||
|
.title
|
||||||
|
Title()
|
||||||
|
.button
|
||||||
|
Button()
|
||||||
|
.QR-wrap
|
||||||
|
width 100%
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
flex-direction column
|
||||||
|
align-items center
|
||||||
|
padding 20px
|
||||||
|
box-sizing border-box
|
||||||
|
.temp
|
||||||
|
width 224px
|
||||||
|
height 224px
|
||||||
|
box-sizing border-box
|
||||||
|
padding 10px
|
||||||
|
border 2px dotted #eee
|
||||||
|
border-radius 5px
|
||||||
|
.QRImg
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
font-size 0
|
||||||
|
.hint
|
||||||
|
font-size 12px
|
||||||
|
color #666
|
||||||
|
margin-top 10px
|
||||||
|
text-align center
|
||||||
|
div
|
||||||
|
margin-top 15px
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,296 @@
|
||||||
|
<template>
|
||||||
|
<div class="admin-wrap">
|
||||||
|
<!-- <div class="title">操作中心</div> -->
|
||||||
|
<div class="scan-wrap">
|
||||||
|
<div class="main" @click="onScan">
|
||||||
|
<img src="@/assets/image/scan1.png" alt="" class="outside">
|
||||||
|
<img src="@/assets/image/scan2.png" alt="" class="interior">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="info">
|
||||||
|
<div class="main">
|
||||||
|
<div class="detail">
|
||||||
|
<div class="main">
|
||||||
|
<div class="temp">
|
||||||
|
<div class="userInfo">
|
||||||
|
<span>姓名:</span>
|
||||||
|
<span class="value">{{userData.Name}}</span>
|
||||||
|
</div>
|
||||||
|
<div class="userInfo">
|
||||||
|
<span class='type'>身份证号:</span>
|
||||||
|
<span class="value">{{idCard}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="img-wrap">
|
||||||
|
<!-- <div class="imgs" :style="{backgroundImage:`url(${userData.imgUrl})`}" @click="showPreview = true"></div> -->
|
||||||
|
<van-image
|
||||||
|
class="imgs"
|
||||||
|
fit="contain"
|
||||||
|
:src="userData.FaceImgUrl"
|
||||||
|
@click="showPreview = true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input-wrap">
|
||||||
|
<input v-model="code" type="text" placeholder='请输入编号'>
|
||||||
|
<div class="button" @click="onSubmit">确认发放</div>
|
||||||
|
</div>
|
||||||
|
<van-image-preview
|
||||||
|
v-model="showPreview"
|
||||||
|
:images="images"
|
||||||
|
>
|
||||||
|
</van-image-preview>
|
||||||
|
<img class="bottom-img" src="@/assets/image/logo.png" alt="">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import {Icon, ImagePreview, Image,Dialog } from 'vant'
|
||||||
|
import WeChatScan from 'utils/WeChatScan.js'
|
||||||
|
import Vue from 'vue';
|
||||||
|
Vue.use(ImagePreview);
|
||||||
|
import { GetPeopleData, AddNo } from 'api/admin'
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name:"Admin",
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
userData:{IdCard:'',Name:''},
|
||||||
|
showPreview:false,
|
||||||
|
code:'',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components:{
|
||||||
|
[Icon.name] :Icon,
|
||||||
|
[Image.name]:Image,
|
||||||
|
[Dialog.name]:Dialog,
|
||||||
|
},
|
||||||
|
computed:{
|
||||||
|
images(){
|
||||||
|
return [this.userData.FaceImgUrl]
|
||||||
|
},
|
||||||
|
idCard(){
|
||||||
|
if(this.userData.IdCard){
|
||||||
|
let str = this.userData.IdCard
|
||||||
|
let difference = str.length - 5 - 3;
|
||||||
|
return str.slice(0, 5) + '*'.repeat(difference) + str.slice(-3)
|
||||||
|
}else{
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// let replaceStr = new Array(difference + 1).join('*')
|
||||||
|
// return this.userData.IdCard.replace(/^(.{5})(?:\d+)(.{3})$/,'$1' + replaceStr + '$2');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activated(){
|
||||||
|
this.$Toast.success('欢迎您!管理员!')
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
onScan(){
|
||||||
|
WeChatScan(this.handleScanCode) //调用微信扫一扫一系列流程,传入回调函数
|
||||||
|
},
|
||||||
|
handleScanCode(ScanCode){
|
||||||
|
this.userData = {}
|
||||||
|
GetPeopleData(ScanCode).then(res => {
|
||||||
|
if(res.code === 0){
|
||||||
|
this.$Toast.success('查询成功!')
|
||||||
|
this.userData = res.data
|
||||||
|
if(res.data.No){
|
||||||
|
Dialog.alert({
|
||||||
|
title: '改用户已经绑定,无需再次绑定',
|
||||||
|
message: '绑定编号为:' + this.userData.No
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
this.$Toast.error(res.msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onSubmit(){
|
||||||
|
var reg = new RegExp('^[0-9]*$')
|
||||||
|
if(this.code){
|
||||||
|
if(!reg.test(this.code)){
|
||||||
|
this.$Toast.error('请输入数字!')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
AddNo(this.userData.CodeMd5,this.code).then(res=> {
|
||||||
|
if(res.code != 0 && res.code != 2018){
|
||||||
|
this.$Toast.error('绑定失败:' + res.msg)
|
||||||
|
}
|
||||||
|
if(res.code === 0){
|
||||||
|
this.$Toast.success('绑定成功!')
|
||||||
|
}else if(res.code === 2018){
|
||||||
|
Dialog.alert({
|
||||||
|
title: '改用户已经绑定,请勿重复绑定',
|
||||||
|
message: '绑定编号为:' + this.userData.No
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.userData = {} //操作成功清空
|
||||||
|
this.code = ''
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
this.$Toast.error('请输入编号')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@keyframes rotate{
|
||||||
|
0%{
|
||||||
|
transform: rotate(0deg) scale(1);
|
||||||
|
}
|
||||||
|
50%{
|
||||||
|
transform:rotate(180deg) scale(1.2)
|
||||||
|
}
|
||||||
|
100%{
|
||||||
|
transform: rotate(360deg) scale(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.admin-wrap
|
||||||
|
width 100%
|
||||||
|
.bottom-img
|
||||||
|
position absolute
|
||||||
|
bottom 0px
|
||||||
|
width 100%
|
||||||
|
left 0
|
||||||
|
.title
|
||||||
|
padding 10px
|
||||||
|
font-size 14px
|
||||||
|
background rgb(64,158,255)
|
||||||
|
text-align center
|
||||||
|
color white
|
||||||
|
.scan-wrap
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
padding 30px 0
|
||||||
|
.main
|
||||||
|
width 25%
|
||||||
|
position relative
|
||||||
|
.outside
|
||||||
|
width 100%
|
||||||
|
animation rotate 5s linear 0s normal infinite
|
||||||
|
.interior
|
||||||
|
position absolute
|
||||||
|
left 50%
|
||||||
|
top 50%
|
||||||
|
transform translate(-50%,-50%)
|
||||||
|
width 50%
|
||||||
|
.info
|
||||||
|
width 90%
|
||||||
|
border-radius 5px
|
||||||
|
margin 0 auto
|
||||||
|
min-height 100px
|
||||||
|
background white
|
||||||
|
overflow hidden
|
||||||
|
.title
|
||||||
|
background #eee
|
||||||
|
color black
|
||||||
|
.main
|
||||||
|
width 100%
|
||||||
|
padding 10px
|
||||||
|
box-sizing border-box
|
||||||
|
display flex
|
||||||
|
justify-content space-between
|
||||||
|
.img-wrap
|
||||||
|
width 26%
|
||||||
|
height 0
|
||||||
|
background rgb(250,250,250)
|
||||||
|
padding-bottom 30%
|
||||||
|
box-sizing border-box
|
||||||
|
position relative
|
||||||
|
.imgs
|
||||||
|
position absolute
|
||||||
|
left 5px
|
||||||
|
top 5px
|
||||||
|
right 5px
|
||||||
|
bottom 5px
|
||||||
|
.detail
|
||||||
|
width 72%
|
||||||
|
box-sizing border-box
|
||||||
|
vertical-align top
|
||||||
|
height 0
|
||||||
|
padding-bottom 30%
|
||||||
|
background rgb(250,250,250)
|
||||||
|
position relative
|
||||||
|
font-size 16px
|
||||||
|
.main
|
||||||
|
position absolute
|
||||||
|
left 0
|
||||||
|
right 0
|
||||||
|
top 0
|
||||||
|
bottom 0
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
.temp
|
||||||
|
width 100%
|
||||||
|
.userInfo
|
||||||
|
color #666
|
||||||
|
margin 10px 0
|
||||||
|
word-wrap break-word
|
||||||
|
white-space:normal
|
||||||
|
font-size 14px
|
||||||
|
.type
|
||||||
|
width 5em
|
||||||
|
display inline-block
|
||||||
|
vertical-align top
|
||||||
|
.value
|
||||||
|
width calc(100% - 5em)
|
||||||
|
display inline-block
|
||||||
|
color #0086ff
|
||||||
|
font-size 15px
|
||||||
|
.input-wrap
|
||||||
|
background white
|
||||||
|
margin 0 auto
|
||||||
|
width 90%
|
||||||
|
border-radius 5px
|
||||||
|
overflow hidden
|
||||||
|
padding 20px 0
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
align-items center
|
||||||
|
margin-top 5px
|
||||||
|
box-sizing border-box
|
||||||
|
position relative
|
||||||
|
z-index 999
|
||||||
|
input
|
||||||
|
border none
|
||||||
|
border-bottom 1px solid rgb(64,158,255)
|
||||||
|
width 110px
|
||||||
|
text-align center
|
||||||
|
padding 10px
|
||||||
|
border-radius 0
|
||||||
|
font-size 25px
|
||||||
|
color rgb(64,158,255)
|
||||||
|
&::-webkit-input-placeholder
|
||||||
|
text-align center
|
||||||
|
font-size 16px
|
||||||
|
color rgba(64,158,255,0.7)
|
||||||
|
.button
|
||||||
|
Button()
|
||||||
|
margin-top 25px
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
<template>
|
||||||
|
<div class="addPhoto-wrap">
|
||||||
|
<div class="main-wrap">
|
||||||
|
<!-- <div class="img-title">
|
||||||
|
<span>请上传人脸照片</span>
|
||||||
|
</div> -->
|
||||||
|
<div class="main">
|
||||||
|
<div class="img-item" >
|
||||||
|
<div class="template-wrap">
|
||||||
|
<!-- 使用背景图展示 -->
|
||||||
|
<!-- <div class="imgs" :style="{backgroundImage:`url(${photo.url})`}"></div> -->
|
||||||
|
<!-- 用image组件展示 -->
|
||||||
|
<div class="img-wrap">
|
||||||
|
<van-image
|
||||||
|
v-show="photo"
|
||||||
|
class="imgs"
|
||||||
|
fit="contain"
|
||||||
|
:src="photo"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="temp" v-show="!photo" >
|
||||||
|
<!-- <img class="cameraIcon" src="@/assets/image/camera-icon.png" alt=""> -->
|
||||||
|
<svg class="cameraIcon" viewBox="0 0 24 24"><path fill="currentColor" d="M20,4H16.83L15,2H9L7.17,4H4A2,2 0 0,0 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V6A2,2 0 0,0 20,4M20,18H4V6H8.05L9.88,4H14.12L15.95,6H20V18M12,7A5,5 0 0,0 7,12A5,5 0 0,0 12,17A5,5 0 0,0 17,12A5,5 0 0,0 12,7M12,15A3,3 0 0,1 9,12A3,3 0 0,1 12,9A3,3 0 0,1 15,12A3,3 0 0,1 12,15Z" /></svg>
|
||||||
|
<span>头像上传</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input :key="isKey" @change="onChange($event)" id="myInput" ref="myInput" type="file" accept="image/*">
|
||||||
|
<!-- <input :key="isKey" @change="onChange($event)" id="myInput" ref="myInput" type="file" accept="image/*"> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 用来放添加按钮 -->
|
||||||
|
<!-- <div class="img-item" v-show="!photo.url">
|
||||||
|
<div class="template-wrap">
|
||||||
|
<input :key="isKey" @change="onChange($event)" id="myInput" ref="myInput" type="file" accept="image/*" capture="camera">
|
||||||
|
<div class="img-wrap">
|
||||||
|
<div class="temp">
|
||||||
|
<img class="cameraIcon" src="@/assets/image/camera-icon.png" alt="">
|
||||||
|
<span>头像上传</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { JudgeCompress, RotateImage, CheckFile, FiletoDataURL } from '@/utils/handleImage'
|
||||||
|
import { Image } from 'vant'
|
||||||
|
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name:'AddPhoto',
|
||||||
|
// props:{
|
||||||
|
// photo:Object,
|
||||||
|
// },
|
||||||
|
components:{
|
||||||
|
[Image.name]:Image,
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
isKey:0,
|
||||||
|
compressSize:100,
|
||||||
|
photo:'',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
onChange(e) {
|
||||||
|
if(!e.target.files[0]){ //用户可能取消选择,此时啥都不用做
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.$emit('readyHandle') //告诉父级已经开始处理.
|
||||||
|
this.photo = ''
|
||||||
|
let file = e.target.files[0];
|
||||||
|
let _this = this
|
||||||
|
if(file){
|
||||||
|
var imageFile = CheckFile(file);
|
||||||
|
if(!imageFile){
|
||||||
|
this.$Toast.error('文件格式错误!')
|
||||||
|
return
|
||||||
|
}else{
|
||||||
|
RotateImage(imageFile).then(res =>{ //传入文件,旋转后返回文件进行压缩
|
||||||
|
JudgeCompress(res,this.compressSize,0.95).then(res => { //传入文件,压缩返回压缩后的文件
|
||||||
|
FiletoDataURL(res).then(res => { //传入文件,返回base64 DataURL
|
||||||
|
_this.photo = res
|
||||||
|
_this.$emit('changePhoto', res)
|
||||||
|
_this.isKey = (new Date()).getTime() //修改key以防止重新选择同一张图不触发change
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="stylus" scoped>
|
||||||
|
.addPhoto-wrap
|
||||||
|
width 100%
|
||||||
|
position relative
|
||||||
|
z-index 999
|
||||||
|
.main-wrap
|
||||||
|
width 100%
|
||||||
|
padding 0
|
||||||
|
box-sizing border-box
|
||||||
|
.img-title
|
||||||
|
// background rgb(64,158,255)
|
||||||
|
padding 10px
|
||||||
|
text-align center
|
||||||
|
font-size 14px
|
||||||
|
align-items center
|
||||||
|
color black
|
||||||
|
padding-left 5px
|
||||||
|
.main
|
||||||
|
width 100%
|
||||||
|
box-sizing border-box
|
||||||
|
padding 40px 5px
|
||||||
|
display flex
|
||||||
|
justify-content center
|
||||||
|
.img-item
|
||||||
|
width 50%
|
||||||
|
height 0
|
||||||
|
padding-bottom 50%
|
||||||
|
position relative
|
||||||
|
overflow hidden
|
||||||
|
box-sizing border-box
|
||||||
|
display inline-block
|
||||||
|
.template-wrap
|
||||||
|
box-sizing border-box
|
||||||
|
position absolute
|
||||||
|
overflow hidden
|
||||||
|
bottom 5px
|
||||||
|
top 5px
|
||||||
|
left 5px
|
||||||
|
overflow hidden
|
||||||
|
right 5px
|
||||||
|
// background rgba(0,133,208,0.7)
|
||||||
|
padding 5px
|
||||||
|
.img-wrap
|
||||||
|
box-sizing border-box
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
border-radius 5px
|
||||||
|
overflow hidden
|
||||||
|
.imgs
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
.temp
|
||||||
|
position absolute
|
||||||
|
top 5px
|
||||||
|
bottom 5px
|
||||||
|
left 5px
|
||||||
|
right 5px
|
||||||
|
border-radius 5px
|
||||||
|
overflow hidden
|
||||||
|
position absolute
|
||||||
|
left 50%
|
||||||
|
top 50%
|
||||||
|
transform translate(-50%, -50%)
|
||||||
|
display flex
|
||||||
|
flex-direction column
|
||||||
|
justify-content center
|
||||||
|
align-items center
|
||||||
|
span
|
||||||
|
color black
|
||||||
|
margin-top 10px
|
||||||
|
font-size 14px
|
||||||
|
.cameraIcon
|
||||||
|
width 60px
|
||||||
|
height 60px
|
||||||
|
color black
|
||||||
|
#myInput
|
||||||
|
position absolute
|
||||||
|
left 0
|
||||||
|
top 0
|
||||||
|
z-index 500
|
||||||
|
display inline-block
|
||||||
|
opacity 0
|
||||||
|
width 100%
|
||||||
|
height 100%
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,123 @@
|
||||||
|
<template>
|
||||||
|
<div class='home-wrap'>
|
||||||
|
<div class="background-wrap">
|
||||||
|
<img class="background-image" src="@/assets/image/track.jpg" />
|
||||||
|
</div>
|
||||||
|
<!-- <div class="top-bgimg-wrap">
|
||||||
|
<img class="top-img" src="@/assets/image/bgimg-top.png"/>
|
||||||
|
<div class="logo-wrap">
|
||||||
|
<img class="yidong-img" src="@/assets/image/yidong.png"/>
|
||||||
|
<img class="fiveG-img" src="@/assets/image/5g.png"/>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
<div class="info-card flex-container">
|
||||||
|
<add-photo @changePhoto="changePhoto" @readyHandle='readyHandle'></add-photo>
|
||||||
|
<div class="form">
|
||||||
|
<van-field required v-model="formData.Name" clearable placeholder="请输入姓名" />
|
||||||
|
<van-field required type='number' v-model="formData.Phone" clearable placeholder="请输入手机号" />
|
||||||
|
<!-- <van-field required type='text' v-model="formData.Code" clearable placeholder="请输入参赛编号" /> -->
|
||||||
|
</div>
|
||||||
|
<div class="button" @click="onSubmit">提交</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="hint">
|
||||||
|
温馨提示:请使用只包含本人正面头像的清晰照片进行注册
|
||||||
|
</div> -->
|
||||||
|
<!-- <img class="bottom-img" src="@/assets/image/bgimg-bottom.png" alt=""> -->
|
||||||
|
<!-- <van-image-preview v-model="showPreview" :images="images"> </van-image-preview> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import addPhoto from "./components/addPhoto"
|
||||||
|
import { Field, Dialog } from 'vant';
|
||||||
|
import { Runnerverify} from 'api/home'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name:'Home',
|
||||||
|
components:{
|
||||||
|
addPhoto,
|
||||||
|
[Field.name]:Field,
|
||||||
|
[Dialog.name]:Dialog
|
||||||
|
},
|
||||||
|
activated(){
|
||||||
|
|
||||||
|
},
|
||||||
|
watch:{
|
||||||
|
Code(val){
|
||||||
|
sessionStorage.Code = val
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
photo:'',
|
||||||
|
formData:{
|
||||||
|
Name:'',
|
||||||
|
Phone:'',
|
||||||
|
Code:''
|
||||||
|
},
|
||||||
|
Code:null, //存入本地的code
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
changePhoto(imgBase64){
|
||||||
|
this.photo = imgBase64
|
||||||
|
this.$Loading.hidden()
|
||||||
|
},
|
||||||
|
readyHandle(){
|
||||||
|
this.$Loading.show('正在处理图片...')
|
||||||
|
},
|
||||||
|
onSubmit(){
|
||||||
|
if(this.verifyForm()){
|
||||||
|
let data = {
|
||||||
|
Name: this.formData.Name,
|
||||||
|
facePic: this.photo,
|
||||||
|
Phone:this.formData.Phone
|
||||||
|
}
|
||||||
|
this.$Loading.show('正在注册...')
|
||||||
|
Runnerverify(data).then(res => {
|
||||||
|
if(res.code === 0){
|
||||||
|
this.$Toast.success('注册成功!')
|
||||||
|
this.$router.push('/photos')
|
||||||
|
localStorage.images = JSON.stringify(res.data)
|
||||||
|
}else if(res.code === 2004){ //号码已被使用
|
||||||
|
Dialog.alert({
|
||||||
|
title: '温馨提示',
|
||||||
|
message: '号码已被占用,请使用新的手机号码进行注册!'
|
||||||
|
});
|
||||||
|
}else if(res.code == 2021){ //如果返回没有照片则提示用户
|
||||||
|
localStorage.images = []
|
||||||
|
this.$router.push({
|
||||||
|
path:'/photos',
|
||||||
|
query:{
|
||||||
|
type:'hintPage'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
this.$Toast.error('注册失败:' + res.msg)
|
||||||
|
}
|
||||||
|
this.$Loading.hidden()
|
||||||
|
}).catch(err => {
|
||||||
|
this.$Loading.hidden()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
verifyForm(){ //表单校验
|
||||||
|
// let idcardReg = /^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X|x)$/;
|
||||||
|
// let IDcardFlag = idcardReg.test(this.formData.IDcard) ? true : false;
|
||||||
|
let NameFlag = this.formData.Name.length && this.formData.Name.length > 0 ? true : false
|
||||||
|
if(!this.photo){
|
||||||
|
this.$Toast.error('请上传人脸照片!')
|
||||||
|
return
|
||||||
|
}else if(!NameFlag){
|
||||||
|
this.$Toast.error('请填写姓名!')
|
||||||
|
return
|
||||||
|
}else if(this.formData.Phone.length !== 11){
|
||||||
|
this.$Toast.error('请填写正确的手机号码!')
|
||||||
|
return
|
||||||
|
}else{
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,93 @@
|
||||||
|
<template>
|
||||||
|
<div class='home-wrap'>
|
||||||
|
<div class="background-wrap">
|
||||||
|
<img class="background-image" src="@/assets/image/track.jpg" />
|
||||||
|
</div>
|
||||||
|
<!-- <div class="top-bgimg-wrap">
|
||||||
|
<img class="top-img" src="@/assets/image/bgimg-top.png"/>
|
||||||
|
<div class="logo-wrap">
|
||||||
|
<img class="yidong-img" src="@/assets/image/yidong.png"/>
|
||||||
|
<img class="fiveG-img" src="@/assets/image/5g.png"/>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
<div class="top-brand-wrap">
|
||||||
|
<h1 class="title">5G 赛道</h1>
|
||||||
|
</div>
|
||||||
|
<div class="info-card flex-container">
|
||||||
|
<div class="form">
|
||||||
|
<van-field required v-model="formData.Name" clearable placeholder="请输入姓名" />
|
||||||
|
<van-field required type='number' v-model="formData.Phone" clearable placeholder="请输入手机号" />
|
||||||
|
</div>
|
||||||
|
<div class="button register" @click="onRegister">注册</div>
|
||||||
|
<div class="button" @click="onLogin">登陆</div>
|
||||||
|
</div>
|
||||||
|
<!-- <div class="hint">
|
||||||
|
已使用“5G赛道”小程序完成人脸注册的用户,请直接输入注册时的姓名和手机号码,登陆并领取照片。
|
||||||
|
</div> -->
|
||||||
|
<!-- <img class="bottom-img" src="@/assets/image/bgimg-bottom.png" alt=""> -->
|
||||||
|
<!-- <van-image-preview v-model="showPreview" :images="images"> </van-image-preview> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Field, Toast, CellGroup, Dialog } from 'vant';
|
||||||
|
import { Login } from 'api/home'
|
||||||
|
|
||||||
|
import imgs1 from '@/assets/image/imgs-01.jpg'
|
||||||
|
import imgs2 from '@/assets/image/imgs-02.jpg'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name:'Home',
|
||||||
|
components:{
|
||||||
|
[Field.name]:Field,
|
||||||
|
[CellGroup.name]:CellGroup,
|
||||||
|
},
|
||||||
|
activated(){
|
||||||
|
|
||||||
|
},
|
||||||
|
watch:{
|
||||||
|
Code(val){
|
||||||
|
sessionStorage.Code = val
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
photo:'',
|
||||||
|
formData:{
|
||||||
|
Name:'',
|
||||||
|
Phone:'',
|
||||||
|
},
|
||||||
|
Code:null, //存入本地的code
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
onLogin(){
|
||||||
|
if(!this.formData.Name){
|
||||||
|
this.$Toast.error('请填写姓名!')
|
||||||
|
return
|
||||||
|
}else if(!this.formData.Phone || this.formData.Phone.length != 11){
|
||||||
|
this.$Toast.error('请填写正确的手机号!')
|
||||||
|
return
|
||||||
|
}else{
|
||||||
|
this.$Loading.show('正在登陆...')
|
||||||
|
Login(this.formData).then(res => {
|
||||||
|
if(res.code === 0){
|
||||||
|
this.$Toast.success('登陆成功!')
|
||||||
|
this.$router.push('/photos')
|
||||||
|
localStorage.images = JSON.stringify(res.data)
|
||||||
|
// localStorage.images = JSON.stringify([imgs1,imgs2,imgs1,imgs2])
|
||||||
|
}else{
|
||||||
|
this.$Toast.error('登陆失败:' + res.msg)
|
||||||
|
}
|
||||||
|
this.$Loading.hidden()
|
||||||
|
}).catch(err => {
|
||||||
|
this.$Loading.hidden()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRegister(){
|
||||||
|
this.$router.push('/home')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,104 @@
|
||||||
|
<template>
|
||||||
|
<div class='home-wrap'>
|
||||||
|
<div class="background-wrap">
|
||||||
|
<img class="background-image" src="@/assets/image/track.jpg" />
|
||||||
|
</div>
|
||||||
|
<!-- <div class="top-bgimg-wrap">
|
||||||
|
<img class="top-img" src="@/assets/image/bgimg-top.png"/>
|
||||||
|
<div class="logo-wrap">
|
||||||
|
<img class="yidong-img" src="@/assets/image/yidong.png"/>
|
||||||
|
<img class="fiveG-img" src="@/assets/image/5g.png"/>
|
||||||
|
</div>
|
||||||
|
</div> -->
|
||||||
|
<div class="flex-container">
|
||||||
|
<template v-if="!hintFlag">
|
||||||
|
<div class="top-brand-wrap">
|
||||||
|
<h1 class="title">您的 5G 纪念册</h1>
|
||||||
|
</div>
|
||||||
|
<div class="main">
|
||||||
|
<div class="imgs-wrap">
|
||||||
|
<div class="imgs-item" v-for="(item,index) in imgs" :key="index">
|
||||||
|
<img :src="item" alt="" >
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hint" v-show='showHint'>
|
||||||
|
<span>您没有任何纪念照哦!</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div class="button" @click="onRegister">重新注册</div>
|
||||||
|
<template v-if="hintFlag">
|
||||||
|
<div class="title">您的5G纪念册为空</div>
|
||||||
|
<div class="hint-wrap">
|
||||||
|
<div class="main">
|
||||||
|
<div class="info-title">温馨提示</div>
|
||||||
|
<div class="info">
|
||||||
|
<p>1、为保证识别效果,请使用只有自己正面头像的清晰照片注册;</p>
|
||||||
|
<p>2、若之前上传的照片效果不佳,没有匹配到照片,可以使用新的手机号码和头像照片,重新注册。</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
<!-- <img class="bottom-img" src="@/assets/image/bgimg-bottom.png" alt=""> -->
|
||||||
|
<!-- <van-image-preview v-model="showPreview" :images="imgs"> </van-image-preview> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { Field, CellGroup, Dialog } from 'vant';
|
||||||
|
// import { ImagePreview} from 'vant'
|
||||||
|
// import Vue from 'vue';
|
||||||
|
// Vue.use(ImagePreview);
|
||||||
|
import { GetUserAttestation } from 'api/home'
|
||||||
|
import drawAndShareImage from '@/utils/waterMark'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name:'Home',
|
||||||
|
components:{
|
||||||
|
[Field.name]:Field,
|
||||||
|
[CellGroup.name]:CellGroup,
|
||||||
|
[Dialog.name]:Dialog,
|
||||||
|
},
|
||||||
|
activated(){
|
||||||
|
this.hintFlag = this.$route.query.type
|
||||||
|
if(this.hintFlag) return
|
||||||
|
let imgs = JSON.parse(localStorage.images)
|
||||||
|
if(imgs){
|
||||||
|
console.log(imgs,47)
|
||||||
|
if(imgs.length === 0){
|
||||||
|
this.showHint = true
|
||||||
|
}
|
||||||
|
this.handlerMark(imgs)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data(){
|
||||||
|
return {
|
||||||
|
imgs:[],
|
||||||
|
hintFlag:false, //空白页提示flag
|
||||||
|
// showPreview:false,
|
||||||
|
showHint:false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods:{
|
||||||
|
onRegister(){
|
||||||
|
Dialog.alert({
|
||||||
|
title: '温馨提示',
|
||||||
|
message: '请务必使用新的手机号码重新注册!'
|
||||||
|
}).then(() => {
|
||||||
|
this.$router.replace('/home')
|
||||||
|
});
|
||||||
|
},
|
||||||
|
handlerMark(arr){
|
||||||
|
this.imgs = []
|
||||||
|
arr.forEach(ele => {
|
||||||
|
this.$Loading.show('正在处理图片...')
|
||||||
|
drawAndShareImage(ele).then(res =>{
|
||||||
|
this.imgs.push(res)
|
||||||
|
this.$Loading.hidden()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,49 @@
|
||||||
|
'use strict'
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
const resolve = dir => path.join(__dirname, dir)
|
||||||
|
|
||||||
|
const titleName = '5G 赛道' // 页面默认title,在路由中被覆盖(刚进入页面路由之前会展示这一段,之后会被路由中的逻辑覆盖)
|
||||||
|
const port = process.env.VUE_APP_BASE_PORT || process.env.npm_config_port || 8088 // dev port 端口号
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
publicPath: process.env.NODE_ENV === "production" ? "./" : "/", //生产环境改成相对路径
|
||||||
|
outputDir: 'dist',
|
||||||
|
assetsDir: 'static', //打包后其他静态资源所在文件夹
|
||||||
|
productionSourceMap: false, //设置成false加快打包速度,同时放弃生产环境的镜像map,也就是不能准确定位报错行数;
|
||||||
|
devServer: {
|
||||||
|
port: port,
|
||||||
|
open: true,
|
||||||
|
proxy: {
|
||||||
|
[process.env.VUE_APP_BASE_API]: {
|
||||||
|
target: `http://5gmalasong.hnabc.cn`,
|
||||||
|
changeOrigin: true,
|
||||||
|
pathRewrite: {
|
||||||
|
['^' + process.env.VUE_APP_BASE_API]: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configureWebpack: {
|
||||||
|
name: titleName, //在index.html中可通过webpackConfig.name使用
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': resolve('src'),
|
||||||
|
'components': resolve('src/components'),
|
||||||
|
'globalComponents':resolve('src/globalComponents'),
|
||||||
|
'utils':resolve('src/utils'),
|
||||||
|
'assets':resolve('src/assets'),
|
||||||
|
'api':resolve('src/api'),
|
||||||
|
'styles':resolve('src/styles'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
loaderOptions: {
|
||||||
|
// 给 stylus-loader 传递选项,使得指定stylus公共变量可以全局使用
|
||||||
|
stylus: {
|
||||||
|
import: ['~@/styles/variables.styl']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|