master
Aiden 9 months ago
parent 26608e65ad
commit b51ad6874b

2
.gitignore vendored

@ -0,0 +1,2 @@
/node_modules
*unpackage

@ -0,0 +1,44 @@
import http from "./interface";
const sendCode = (data) => {
return http.request({
url: "/api/staff/send",
method: "POST",
data,
});
};
const login = (data) => {
return http.request({
url: "/api/staff/login",
method: "POST",
data,
});
};
const qrCodeInfo = (data) => {
return http.request({
url: "/api/smart/appointment/get/ticket/info",
method: "POST",
data,
});
};
const checkQr = (data) => {
return http.request({
url: "/api/smart/check/verify/qrCode",
method: "POST",
data,
});
};
const openPicUrl = (data) => {
return http.request({
url: "/api/smart/check/start/camera",
method: "POST",
data,
});
};
export default {
sendCode,
login,
qrCodeInfo,
checkQr,
openPicUrl,
};

@ -0,0 +1,169 @@
/**
* 通用uni-app网络请求
* 基于 Promise 对象实现更简单的 request 使用方式支持请求和响应拦截
*/
export default {
config: {
baseUrl: "https://warehouse.szjixun.cn/ticket", //"http://172.16.100.93:9051", //"http://192.168.88.175:9021",//'https://warehouse.szjixun.cn'
header: {
"Content-Type": "application/json;charset=UTF-8",
// 'Content-Type':'application/x-www-form-urlencoded'
},
data: {},
method: "GET",
dataType: "json" /* 如设为json会对返回的数据做一次 JSON.parse */,
responseType: "text",
success() {},
fail() {},
complete() {},
},
interceptor: {
request: null,
response: null,
},
request(options) {
if (!options) {
options = {};
}
options.baseUrl = options.baseUrl || this.config.baseUrl;
options.dataType = options.dataType || this.config.dataType;
options.url = options.baseUrl + options.url;
options.data = options.data || {};
options.method = options.method || this.config.method;
//TODO 加密数据
options.header = options.header || this.config.header;
//TODO 数据签名
let _token = {
StaffAuthorization: uni.getStorageSync("token") || "undefined",
};
options.header = Object.assign({}, options.header, _token);
/*
_sign = {'sign': sign(JSON.stringify(options.data))}
options.header = Object.assign({}, options.header, _token,_sign)
*/
return new Promise((resolve, reject) => {
let _config = null;
options.complete = (response) => {
let statusCode = response.statusCode;
response.config = _config;
if (process.env.NODE_ENV === "development") {
if (statusCode === 200) {
// console.log("【" + _config.requestId + "】 结果:" + JSON.stringify(response.data))
}
}
if (this.interceptor.response) {
let newResponse = this.interceptor.response(response);
if (newResponse) {
response = newResponse;
}
}
if (response.data?.status === 401) {
let curPage = getCurrentPages();
let route = curPage[curPage.length - 1].route; //获取当前页面的路由
if (route !== "pages/login/index") {
uni.navigateTo({
url: "/pages/login/index",
});
}
}
// 统一的响应日志记录
_reslog(response);
if (statusCode === 200) {
//成功
resolve(response.data);
} else {
reject(response);
}
};
_config = Object.assign({}, this.config, options);
_config.requestId = new Date().getTime();
if (this.interceptor.request) {
this.interceptor.request(_config);
}
// 统一的请求日志记录
_reqlog(_config);
uni.request(_config);
});
},
get(url, data, options) {
if (!options) {
options = {};
}
options.url = url;
options.data = data;
options.method = "GET";
return this.request(options);
},
post(url, data, options, header) {
if (!options) {
options = {};
}
options.url = url;
options.data = data;
options.header = header;
options.method = "POST";
return this.request(options);
},
put(url, data, options) {
if (!options) {
options = {};
}
options.url = url;
options.data = data;
options.method = "PUT";
return this.request(options);
},
delete(url, data, options) {
if (!options) {
options = {};
}
options.url = url;
options.data = data;
options.method = "DELETE";
return this.request(options);
},
};
/**
* 请求接口日志记录
*/
function _reqlog(req) {
if (process.env.NODE_ENV === "development") {
// console.log("【" + req.requestId + "】 地址:" + req.url)
if (req.data) {
// console.log("【" + req.requestId + "】 请求参数:" + JSON.stringify(req.data))
}
}
//TODO 调接口异步写入日志数据库
}
/**
* 响应接口日志记录
*/
function _reslog(res) {
let _statusCode = res.statusCode;
if (process.env.NODE_ENV === "development") {
// console.log("【" + res.config.requestId + "】 地址:" + res.config.url)
if (res.config.data) {
// console.log("【" + res.config.requestId + "】 请求参数:" + JSON.stringify(res.config.data))
}
// console.log("【" + res.config.requestId + "】 响应结果:" + JSON.stringify(res))
}
//TODO 除了接口服务错误外,其他日志调接口异步写入日志数据库
switch (_statusCode) {
case 200:
break;
case 401:
break;
case 404:
break;
default:
break;
}
}

@ -1,39 +1,36 @@
<template>
<div class="content2" :style="styleColor">
<div class="wrap1" v-for="item in result">
<div class="wrap1">
<div class="wrap1_1">
<slot :name="Object.keys(item).find(x => x.includes('l'))"></slot>
<slot name="l1"></slot>
</div>
<div class="wrap1_2">
<slot :name="Object.keys(item).find(x => x.includes('r'))"></slot>
<slot name="r1"></slot>
</div>
</div>
<div class="wrap1">
<div class="wrap1_1">
<slot name="l2"></slot>
</div>
<div class="wrap1_2">
<slot name="r2"></slot>
</div>
</div>
</div>
</template>
<script setup>
import { useSlots, ref, defineProps } from 'vue'
const slots = useSlots();
const prop = defineProps({
<script >
export default {
props: {
styleColor: {
type: Object,
default: () => {
return { backgroundColor: '#fff' }
}
}
})
const groupObjectsByNumberKeys = (obj) => {
const grouped = {};
for (const key in obj) {
const numericPart = key.slice(1);
if (!grouped[numericPart]) {
grouped[numericPart] = {};
}
grouped[numericPart][key] = obj[key];
}
return Object.values(grouped);
}
const result = ref(groupObjectsByNumberKeys(slots))
</script>

@ -0,0 +1,92 @@
<template>
<div class="content2" :style="styleColor">
<div class="wrap1">
<div class="wrap1_1">
<slot name="l1"></slot>
</div>
<div class="wrap1_2">
<slot name="r1"></slot>
</div>
</div>
<div class="wrap1">
<div class="wrap1_1">
<slot name="l2"></slot>
</div>
<div class="wrap1_2">
<slot name="r2"></slot>
</div>
</div>
<div class="wrap1">
<div class="wrap1_1">
<slot name="l3"></slot>
</div>
<div class="wrap1_2">
<slot name="r3"></slot>
</div>
</div>
<div class="wrap1">
<div class="wrap1_1">
<slot name="l4"></slot>
</div>
<div class="wrap1_2">
<slot name="r4"></slot>
</div>
</div>
<div class="wrap1">
<div class="wrap1_1">
<slot name="l5"></slot>
</div>
<div class="wrap1_2">
<slot name="r5"></slot>
</div>
</div>
</div>
</template>
<script >
export default {
props: {
styleColor: {
type: Object,
default: () => {
return { backgroundColor: '#fff' }
}
}
}
}
</script>
<style lang="scss" scoped>
.content2 {
border-radius: 24rpx;
padding-left: 18rpx;
padding-right: 32rpx;
.wrap1 {
padding-left: 14rpx;
padding-top: 26rpx;
padding-bottom: 22rpx;
border-bottom: 1rpx solid #E4EAF1;
display: flex;
&:last-child {
border-bottom: none;
}
.wrap1_2 {
flex-grow: 1;
padding-left: 36rpx;
font-size: 24rpx;
color: #939393;
}
.wrap1_1 {
display: flex;
align-items: center;
width: 192rpx;
border-right: 1rpx solid #E4EAF1;
}
}
}
</style>

@ -1,10 +1,15 @@
import App from "./App";
import uView from "uview-ui";
import request from "@/api/index.js";
// import Vconsole from "vconsole";
// new Vconsole();
// #ifndef VUE3
import Vue from "vue";
import "./uni.promisify.adaptor";
Vue.config.productionTip = false;
Vue.use(uView);
Vue.prototype.$request = request;
App.mpType = "app";
const app = new Vue({
...App,

99
package-lock.json generated

@ -0,0 +1,99 @@
{
"name": "museum-H5-V2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"vconsole": "^3.15.1"
}
},
"node_modules/@babel/runtime": {
"version": "7.23.6",
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.23.6.tgz",
"integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/copy-text-to-clipboard": {
"version": "3.2.0",
"resolved": "https://registry.npmmirror.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz",
"integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q==",
"engines": {
"node": ">=12"
}
},
"node_modules/core-js": {
"version": "3.34.0",
"resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.34.0.tgz",
"integrity": "sha512-aDdvlDder8QmY91H88GzNi9EtQi2TjvQhpCX6B1v/dAZHU1AuLgHvRh54RiOerpEhEW46Tkf+vgAViB/CWC0ag==",
"hasInstallScript": true
},
"node_modules/mutation-observer": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/mutation-observer/-/mutation-observer-1.0.3.tgz",
"integrity": "sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA=="
},
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"node_modules/vconsole": {
"version": "3.15.1",
"resolved": "https://registry.npmmirror.com/vconsole/-/vconsole-3.15.1.tgz",
"integrity": "sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==",
"dependencies": {
"@babel/runtime": "^7.17.2",
"copy-text-to-clipboard": "^3.0.1",
"core-js": "^3.11.0",
"mutation-observer": "^1.0.3"
}
}
},
"dependencies": {
"@babel/runtime": {
"version": "7.23.6",
"resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.23.6.tgz",
"integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==",
"requires": {
"regenerator-runtime": "^0.14.0"
}
},
"copy-text-to-clipboard": {
"version": "3.2.0",
"resolved": "https://registry.npmmirror.com/copy-text-to-clipboard/-/copy-text-to-clipboard-3.2.0.tgz",
"integrity": "sha512-RnJFp1XR/LOBDckxTib5Qjr/PMfkatD0MUCQgdpqS8MdKiNUzBjAQBEN6oUy+jW7LI93BBG3DtMB2KOOKpGs2Q=="
},
"core-js": {
"version": "3.34.0",
"resolved": "https://registry.npmmirror.com/core-js/-/core-js-3.34.0.tgz",
"integrity": "sha512-aDdvlDder8QmY91H88GzNi9EtQi2TjvQhpCX6B1v/dAZHU1AuLgHvRh54RiOerpEhEW46Tkf+vgAViB/CWC0ag=="
},
"mutation-observer": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/mutation-observer/-/mutation-observer-1.0.3.tgz",
"integrity": "sha512-M/O/4rF2h776hV7qGMZUH3utZLO/jK7p8rnNgGkjKUw8zCGjRQPxB8z6+5l8+VjRUQ3dNYu4vjqXYLr+U8ZVNA=="
},
"regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
"vconsole": {
"version": "3.15.1",
"resolved": "https://registry.npmmirror.com/vconsole/-/vconsole-3.15.1.tgz",
"integrity": "sha512-KH8XLdrq9T5YHJO/ixrjivHfmF2PC2CdVoK6RWZB4yftMykYIaXY1mxZYAic70vADM54kpMQF+dYmvl5NRNy1g==",
"requires": {
"@babel/runtime": "^7.17.2",
"copy-text-to-clipboard": "^3.0.1",
"core-js": "^3.11.0",
"mutation-observer": "^1.0.3"
}
}
}
}

@ -0,0 +1,5 @@
{
"dependencies": {
"vconsole": "^3.15.1"
}
}

@ -4,9 +4,39 @@
},
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"path": "pages/login/index",
"style": {
"navigationBarTitleText": "藏品活动详情页",
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"app-plus": {
"titleNView": false //
}
}
},
{
"path": "pages/check/index",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"app-plus": {
"titleNView": false //
}
}
},
{
"path": "pages/scan/index",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"app-plus": {
"titleNView": false //
}
}
},
{
"path": "pages/persomInfo/index",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false,
"app-plus": {
"titleNView": false //

@ -0,0 +1,42 @@
<template>
<div class="main">
<image src="@/static/bg2.png" mode="aspectFill" class="img" />
<u-button type="primary" :text="'审核员 ' + name" shape="circle" color="#AB2F23"
style="width:700rpx ;margin-top: 50rpx;"></u-button>
<u-button type="primary" text="扫一扫" shape="circle" color="#000" style="width:700rpx ;margin-top: 50rpx"
@click="goScan"></u-button>
</div>
</template>
<script >
export default {
data() {
return {
name: uni.getStorageSync('nickName')
}
},
methods: {
goScan() {
uni.navigateTo({
url: '/pages/scan/index'
})
}
}
}
</script>
<style lang="scss" scoped>
.main {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
background: url('@/static/bg.png');
background-size: cover;
.img {
width: 100%;
height: 1256rpx;
}
}
</style>

@ -0,0 +1,128 @@
<template>
<div class="main">
<image src="@/static/33@2x.png" mode="aspectFill" class="img" />
<div class="loginInfo">
<card>
<template #l1>
<div class="box-left">
手机号(+86)
</div>
</template>
<template #r1>
<u--input placeholder="请输入手机号" clearable type="number" border="none" v-model="tel"
style="width: 320rpx;"></u--input>
</template>
<template #l2>
<div class="box-left">
验证码
</div>
</template>
<template #r2>
<div class="box-right">
<u--input placeholder="请输入验证码" border="none" v-model="code">
<template #suffix>
<u-code ref="uCodeRef" @change="codeChange" seconds="60" changeText="x秒重新获取"
endText="重新获取"></u-code>
<u-button @tap="getCode" :text="tips" type="success" size="mini"></u-button>
</template>
</u--input>
</div>
</template>
</card>
<u-button type="primary" text="登录" shape="circle" color="#000" style="width:436rpx ;"
@click="goCheck"></u-button>
</div>
</div>
</template>
<script>
import card from '@/components/card/index.vue'
export default {
components: {
card
},
data() {
return {
tips: '',
tel: null,
code: null,
uCodeRef: null
}
},
methods: {
codeChange(text) {
console.log(text)
this.tips = text;
},
getCode() {
if (this.$refs.uCodeRef.canGetCode) {
uni.showLoading({
title: '正在获取验证码',
});
this.$request.sendCode({ telNum: this.tel }).then((res) => {
console.log(res)
if (res.status === 0) {
uni.hideLoading();
uni.$u.toast('验证码已发送');
this.$refs.uCodeRef.start();
} else {
uni.hideLoading();
uni.$u.toast(res.msg);
}
})
}
},
goCheck() {
this.$request.login({
telNum: this.tel,
code: this.code
}).then((res) => {
if (res.status === 0) {
uni.setStorageSync("token", res.data.token);
uni.setStorageSync("nickName", res.data.accountInfo.nickName);
uni.navigateTo({
url: '/pages/check/index'
})
} else {
uni.$u.toast(res.msg);
}
})
}
},
}
</script>
<style lang="scss" scoped>
.main {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
background: url('@/static/bg.png');
background-size: cover;
.img {
width: 100%;
height: 1000rpx;
}
.loginInfo {
height: 100%;
padding: 42rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
.box-left {
font-size: 28rpx;
}
}
}
</style>

@ -0,0 +1,156 @@
<template>
<div class="main">
<u-button type="primary" :text="'审核员 ' + name" shape="circle" color="#AB2F23" style="width:700rpx "></u-button>
<image :src="ticketsInfo.ticketCoverPic" mode="scaleToFill" class="img" />
<card>
<template #l1>
<div class="box-left">
姓名
</div>
</template>
<template #r1>
{{ userInfo.userName || '' }}
</template>
<template #l2>
<div class="box-left">
身份证号
</div>
</template>
<template #r2>
<div class="box-right">
{{ userInfo.idCard || '' }}
</div>
</template>
<template #l3>
<div class="box-left">
领票日期
</div>
</template>
<template #r3>
{{ ticketsInfo.drawDay }}
</template>
<template #l4>
<div class="box-left">
核验项目
</div>
</template>
<template #r4>
{{ ticketsInfo.ticketName }}
</template>
<template #l5 v-if="userInfo.checkTime">
<div class="box-left">
核验日期
</div>
</template>
<template #r5 v-if="userInfo.checkTime">
{{ userInfo.checkTime }}
</template>
</card>
<u-button type="primary" text="核验人像" shape="circle" color="#000" style="width:436rpx " @click="openPicUrl"
v-if="ticketsInfo.status === 1"></u-button>
</div>
</template>
<script>
import card from '@/components/card/moreDataCard'
export default {
components: {
card
},
data() {
return {
appointmentUid: '',
ticketsInfo: {},
userInfo: {},
name: uni.getStorageSync('nickName')
}
},
onLoad(option) {
console.log(option.qrcode)
this.appointmentUid = option.qrcode
this.getQrInfo()
},
methods: {
getQrInfo() {
this.$request.qrCodeInfo({ appointmentUid: this.appointmentUid }).then((res) => {
if (res.status === 0) {
this.ticketsInfo = res.data.ticketsInfo
this.userInfo = res.data.userInfo[0]
} else {
uni.$u.toast(res.msg);
}
})
},
checkPerson() {
uni.connectSocket({
url: `wss://warehouse.szjixun.cn/ticket/api/smart/check/issue/msg?AppointmentUid=${this.appointmentUid}`,
success: function () {
console.log('WebSocket连接已创建成功');
}
});
uni.onSocketOpen((res) => {
console.log(res, 'onSocketOpen')
});
uni.onSocketMessage((res) => {
console.log('WebSocket接收到消息', res);
if (res.data) {
this.checkQr(res.data)
}
});
uni.onSocketError(function (res) {
console.log(res);
});
uni.onSocketClose(function (res) {
console.log('WebSocket 已关闭!', res);
});
},
openPicUrl() {
this.$request.openPicUrl({ appointmentUid: this.appointmentUid }).then((res) => {
if (res.status === 0) {
this.checkPerson()
} else {
uni.$u.toast(res.msg);
}
})
},
checkQr(img) {
this.$request.checkQr({
appointmentUid: this.appointmentUid,
imageUrl: img
}).then((res) => {
if (res.status === 0) {
this.getQrInfo()
} else {
uni.$u.toast(res.msg);
}
})
}
},
}
</script>
<style lang="scss" scoped>
.main {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-around;
background: url('@/static/bg.png');
background-size: cover;
box-sizing: border-box;
padding: 42rpx 26rpx;
.img {
width: 100%;
height: 354rpx;
margin-top: 40rpx;
}
.box-left {
font-size: 28rpx;
}
}
</style>

@ -12,24 +12,20 @@ import mumuGetQrcode from "../../components/mumu-getQrcode/mumu-getQrcode.vue";
export default {
components: {
mumuGetQrcode
},
data() {
return {
title: 'Hello'
}
},
onLoad() {
},
methods: {
qrcodeSucess(res) {
uni.navigateTo({ url: '/pages/persomInfo/index?qrcode=' + res })
},
qrcodeError(err) {
console.log(err);
uni.showModal({
title: res,
content: res,
});
title: "摄像头授权失败",
content: "摄像头授权失败,请检测当前浏览器是否有摄像头权限。",
success: () => {
uni.navigateBack({});
},
qrcodeError(res) {
console.log(res);
});
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Loading…
Cancel
Save