修改
17
App.vue
Normal file
@ -0,0 +1,17 @@
|
||||
<script>
|
||||
export default {
|
||||
onLaunch: function() {
|
||||
console.log('App Launch')
|
||||
},
|
||||
onShow: function() {
|
||||
console.log('App Show')
|
||||
},
|
||||
onHide: function() {
|
||||
console.log('App Hide')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
|
||||
@import "uview-ui/index.scss";
|
||||
</style>
|
||||
17
api/addexam/index.js
Normal file
@ -0,0 +1,17 @@
|
||||
import request from "../request.js"
|
||||
|
||||
export function getExamList() {
|
||||
return request({
|
||||
url: `/exam/api/exam/exam/getExamList?examType=2&userId=${uni.getStorageSync('examh5user').id}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export function save(data) {
|
||||
return request({
|
||||
url: `/exam/api/exam/registration/save`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
4
api/baseurl.js
Normal file
@ -0,0 +1,4 @@
|
||||
var baseurl = "http://8.131.93.145:54012";
|
||||
|
||||
|
||||
export default baseurl
|
||||
8
api/examlist/index.js
Normal file
@ -0,0 +1,8 @@
|
||||
import request from "../request.js"
|
||||
|
||||
export function getRegExamList() {
|
||||
return request({
|
||||
url: `/exam/api/exam/registration/getRegExamList?userId=${uni.getStorageSync('examh5user').id}`,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
10
api/login/index.js
Normal file
@ -0,0 +1,10 @@
|
||||
import request from "../request.js"
|
||||
|
||||
//注册
|
||||
export function login(data) {
|
||||
return request({
|
||||
url: `/exam/api/sys/user/login`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
10
api/register/index.js
Normal file
@ -0,0 +1,10 @@
|
||||
import request from "../request.js"
|
||||
|
||||
//注册
|
||||
export function reg(data) {
|
||||
return request({
|
||||
url: `/exam/api/sys/user/reg`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
53
api/request.js
Normal file
@ -0,0 +1,53 @@
|
||||
import baseurl from './baseurl.js'
|
||||
|
||||
var request = function(config) {
|
||||
return new Promise((resolve, rejected) => {
|
||||
uni.showLoading({
|
||||
title: ''
|
||||
});
|
||||
uni.request({
|
||||
url: baseurl + config.url,
|
||||
data: config.data,
|
||||
method: config.method,
|
||||
timeout: 10000,
|
||||
header: {
|
||||
...config.header,
|
||||
token: uni.getStorageSync('examh5token')
|
||||
},
|
||||
success(res) {
|
||||
uni.hideLoading();
|
||||
if (res.data.code == 0) {
|
||||
resolve(res.data)
|
||||
} else if (res.data.code == 401 || res.data.code == 10010002 || res.data.code ==
|
||||
90010001 || res.data.code == 90010002 || res.data.code == 90010005) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: res.data.msg,
|
||||
showCancel: false,
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
uni.clearStorageSync();
|
||||
uni.reLaunch({
|
||||
url: "/pages/login/login"
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
showCancel: false,
|
||||
content: res.data.msg,
|
||||
success: function(res) {}
|
||||
});
|
||||
}
|
||||
},
|
||||
fail(err) {
|
||||
uni.hideLoading();
|
||||
rejected(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default request
|
||||
12
api/user/index.js
Normal file
@ -0,0 +1,12 @@
|
||||
import request from "../request.js"
|
||||
|
||||
export function info(data) {
|
||||
return request({
|
||||
url: `/exam/api/sys/user/info`,
|
||||
method: 'post',
|
||||
header: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
data
|
||||
})
|
||||
}
|
||||
52
components/signature/signature.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<view class="signature" style="background-color: #F4F5F7;height: 800rpx;">
|
||||
<Signature @init="onSignInit" style='background-color: #fff;height: 700rpx;width: 100%;'></Signature>
|
||||
<view class="btns">
|
||||
<button @click="clear">清空</button>
|
||||
<button @click="revoke">撤回</button>
|
||||
<button @click="saveTempFilePath">保存</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import Signature from '@/components/v-sign/v-sign.vue'
|
||||
export default {
|
||||
components: {
|
||||
Signature
|
||||
},
|
||||
methods: {
|
||||
onSignInit(signCtx) {
|
||||
this.signCtx = signCtx
|
||||
},
|
||||
// 清空
|
||||
clear() {
|
||||
this.signCtx.clear()
|
||||
},
|
||||
// 撤回
|
||||
revoke() {
|
||||
this.signCtx.revoke()
|
||||
},
|
||||
// 保存为临时图片路径,h5返回 base64
|
||||
async saveTempFilePath() {
|
||||
const res = await this.signCtx.canvasToTempFilePath()
|
||||
this.$emit('userSignaturePictureUrl', res)
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss'>
|
||||
.signature {
|
||||
height: 800rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.btns {
|
||||
margin-top: 50rpx;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 30%;
|
||||
}
|
||||
</style>
|
||||
15
components/v-sign/utils.js
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 判断是否未数值
|
||||
* @param {Object} val
|
||||
*/
|
||||
export function isNumber(val) {
|
||||
return !isNaN(Number(val))
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理大小单位
|
||||
* @param {Object} val
|
||||
*/
|
||||
export function formatSize(val) {
|
||||
return isNumber(val) ? `${val}rpx` : val
|
||||
}
|
||||
162
components/v-sign/v-sign-action.vue
Normal file
@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<view class="v-sign-action" :style="[customStyle]">
|
||||
<view
|
||||
v-for="item in btns"
|
||||
:key="item.label"
|
||||
:class="['btn', { border: border }]"
|
||||
:style="[{ 'margin-right': formatSize(space) }]"
|
||||
@click="onBtnClick(item)"
|
||||
>
|
||||
<image :class="['icon', 'icon-' + item.action]" :src="item.icon"></image>
|
||||
<text class="text">{{ item.label }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* v-sign-action 控制按钮组(v-sign 子组件)
|
||||
* @description 控制 v-sign 组件的一些按钮
|
||||
* @tutorial
|
||||
* @property {Array} actions 按钮配置 所有值: 清空(clear), 撤回(prev) 保存图片(save)
|
||||
* @property {Boolean} border 按钮是否有边框
|
||||
* @property {String/Number} space 按钮间隔
|
||||
* @property {Object} customStyle 根元素自定义样式
|
||||
* @event {Function} 点击对应类型按钮触发对应事件, 例如点击 clear 则触发 clear 事件
|
||||
* @example 示例
|
||||
**/
|
||||
import { formatSize } from './utils'
|
||||
|
||||
// v-sign 父组件提供的接口
|
||||
let vSignInterface
|
||||
// 按钮类型
|
||||
const btn_type = {
|
||||
CLEAR: 'clear', // 清空
|
||||
PREV: 'prev', // 撤回/上一步
|
||||
// NEXT: 'next',
|
||||
SAVE: 'save' // 保存临时图片
|
||||
}
|
||||
const all_action = Object.values(btn_type)
|
||||
const btnsConf = [
|
||||
{
|
||||
label: '清空',
|
||||
action: btn_type.CLEAR,
|
||||
icon: '/static/v-sign/clear.png'
|
||||
},
|
||||
{
|
||||
label: '撤回',
|
||||
action: btn_type.PREV,
|
||||
icon: '/static/v-sign/prev.png'
|
||||
},
|
||||
// {
|
||||
// label: '取消撤回',
|
||||
// action: btn_type.NEXT,
|
||||
// icon: '/static/v-sign/next.png'
|
||||
// },
|
||||
{
|
||||
label: '保存',
|
||||
action: btn_type.SAVE,
|
||||
icon: '/static/v-sign/save.png'
|
||||
}
|
||||
]
|
||||
export default {
|
||||
name: 'v-sign-action',
|
||||
props: {
|
||||
// 按钮配置
|
||||
actions: {
|
||||
type: Array,
|
||||
default: () => all_action
|
||||
},
|
||||
// 按钮是否有边框
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 按钮间隔
|
||||
space: {
|
||||
type: [String, Number],
|
||||
default: 12
|
||||
},
|
||||
// 根元素自定义样式
|
||||
customStyle: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
inject: ['getInterface'],
|
||||
data() {
|
||||
return {
|
||||
formatSize
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
btns() {
|
||||
return btnsConf.filter(item => this.actions.includes(item.action))
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
vSignInterface = this.getInterface()
|
||||
},
|
||||
methods: {
|
||||
async onBtnClick(btn) {
|
||||
// console.log(btn, btn.action)
|
||||
let emit_result
|
||||
switch (btn.action) {
|
||||
case btn_type.CLEAR:
|
||||
vSignInterface.clear()
|
||||
break
|
||||
case btn_type.PREV:
|
||||
vSignInterface.revoke()
|
||||
break
|
||||
// case btn_type.NEXT:
|
||||
// console.log('next')
|
||||
// break
|
||||
case btn_type.SAVE:
|
||||
emit_result = await vSignInterface.canvasToTempFilePath()
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
// console.log(btn.action, emit_result);
|
||||
// 触发按钮对应类型事件
|
||||
this.$emit(btn.action, emit_result)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-sign-action {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
.btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 12rpx;
|
||||
min-width: 88rpx;
|
||||
white-space: nowrap;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
&.border {
|
||||
border: 2rpx solid #666;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
.icon {
|
||||
width: 28rpx;
|
||||
height: 28rpx;
|
||||
&.icon-clear,
|
||||
&.icon-prev,
|
||||
&.icon-next {
|
||||
margin-right: 4rpx;
|
||||
}
|
||||
&.icon-save {
|
||||
}
|
||||
}
|
||||
.text {
|
||||
color: #666;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
211
components/v-sign/v-sign-pen.vue
Normal file
@ -0,0 +1,211 @@
|
||||
<template>
|
||||
<view class="v-sign-pen">
|
||||
<view class="label" v-if="label">{{ label }}</view>
|
||||
<view class="options">
|
||||
<view
|
||||
class="opt-item"
|
||||
:style="{
|
||||
minHeight: minWrapHeight,
|
||||
marginRight: space + 'rpx'
|
||||
}"
|
||||
v-for="item in csizes"
|
||||
:key="item.size"
|
||||
@click="onItemClick(item)"
|
||||
>
|
||||
<view
|
||||
:class="type"
|
||||
:style="{
|
||||
border:
|
||||
border && currentSelect.size === item.size
|
||||
? `${borderWidth}rpx solid ${activeColor}`
|
||||
: ''
|
||||
}"
|
||||
>
|
||||
<view class="inner" :style="[defaultInnerStyle(item)]"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* v-sign-pen 画笔(v-sign 子组件)
|
||||
* @description 控制 v-sign 画笔的线宽
|
||||
* @tutorial
|
||||
* @property {String} type 选项样式 line / circle
|
||||
* @property {String} label 标签
|
||||
* @property {Array} sizes 画笔大小数组,单位 px
|
||||
* @property {String} color 选项颜色
|
||||
* @property {String} activeColor 选中项颜色
|
||||
* @property {Boolean} border 选中项是否有边框
|
||||
* @property {Number} borderWidth 边框大小,单位 rpx
|
||||
* @property {String} space 选项间隙,单位 rpx
|
||||
* @property {Number} bigger 圆点变大变粗倍数
|
||||
* @property {Number} minSize 圆点最小大小,单位 px
|
||||
* @event {Function} change 选择画笔大小时触发
|
||||
* @example
|
||||
**/
|
||||
// v-sign 父组件提供的接口
|
||||
let vSignInterface
|
||||
// 选项样式
|
||||
const type_style = {
|
||||
CIRCLE: 'circle',
|
||||
LINE: 'line'
|
||||
}
|
||||
export default {
|
||||
name: 'v-sign-pen',
|
||||
props: {
|
||||
// 选项样式
|
||||
type: {
|
||||
type: String,
|
||||
default: type_style.CIRCLE
|
||||
},
|
||||
label: {
|
||||
type: String
|
||||
},
|
||||
// 画笔大小数组,单位是px
|
||||
sizes: {
|
||||
type: Array,
|
||||
default: () => [2, 4, 6, 8, 10]
|
||||
},
|
||||
// 选项颜色
|
||||
color: {
|
||||
type: String,
|
||||
default: '#333'
|
||||
},
|
||||
// 选中项颜色
|
||||
activeColor: {
|
||||
type: String,
|
||||
default: '#333'
|
||||
},
|
||||
// 选中项是否有边框
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 边框大小, 单位 rpx
|
||||
borderWidth: {
|
||||
type: Number,
|
||||
default: 4
|
||||
},
|
||||
// 选项间隙, 单位 rpx
|
||||
space: {
|
||||
type: Number,
|
||||
default: 20
|
||||
},
|
||||
// 圆点变大变粗倍数
|
||||
bigger: {
|
||||
type: Number,
|
||||
default: 2
|
||||
},
|
||||
// 圆点最小大小,单位 px
|
||||
minSize: {
|
||||
type: Number,
|
||||
default: 4
|
||||
}
|
||||
},
|
||||
inject: ['getInterface'],
|
||||
data() {
|
||||
return {
|
||||
type_style,
|
||||
currentSelect: null,
|
||||
csizes: [],
|
||||
maxSize: 0,
|
||||
maxCsize: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
minWrapHeight() {
|
||||
let height
|
||||
switch (this.type) {
|
||||
case type_style.CIRCLE:
|
||||
height = this.maxCsize + 10 + 'px'
|
||||
break
|
||||
case type_style.LINE:
|
||||
height = this.maxSize + 4 + 'px'
|
||||
break
|
||||
}
|
||||
return height
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.csizes = this.sizes.map((size, index) => {
|
||||
const csize = (index + 1) * this.bigger + this.minSize
|
||||
this.maxSize = csize > this.maxSize ? csize : this.maxSize
|
||||
this.maxCsize = csize > this.maxCsize ? csize : this.maxCsize
|
||||
return {
|
||||
size,
|
||||
csize
|
||||
}
|
||||
})
|
||||
this.currentSelect = this.csizes[0]
|
||||
},
|
||||
mounted() {
|
||||
vSignInterface = this.getInterface()
|
||||
this.setLineWidth()
|
||||
},
|
||||
methods: {
|
||||
onItemClick(opt) {
|
||||
this.currentSelect = opt
|
||||
this.setLineWidth()
|
||||
this.$emit('change', opt.size)
|
||||
},
|
||||
setLineWidth() {
|
||||
vSignInterface.setLineWidth(this.currentSelect.size)
|
||||
},
|
||||
defaultInnerStyle(item) {
|
||||
let width
|
||||
let height
|
||||
switch (this.type) {
|
||||
case type_style.CIRCLE:
|
||||
width = `${item.csize}px`
|
||||
height = `${item.csize}px`
|
||||
break
|
||||
case type_style.LINE:
|
||||
width = '20px'
|
||||
height = `${item.size}px`
|
||||
break
|
||||
}
|
||||
const background = this.currentSelect.size === item.size ? this.activeColor : this.color
|
||||
return {
|
||||
width,
|
||||
height,
|
||||
background
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-sign-pen {
|
||||
padding: 12rpx;
|
||||
.label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
.options {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
.opt-item {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: center;
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
.circle {
|
||||
border-radius: 50%;
|
||||
padding: 4rpx;
|
||||
.inner {
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
.line {
|
||||
padding: 4rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
238
components/v-sign/v-sign.vue
Normal file
@ -0,0 +1,238 @@
|
||||
<template>
|
||||
<view class="signature-wrap">
|
||||
<canvas
|
||||
:canvas-id="cid"
|
||||
:id="cid"
|
||||
@touchstart="onTouchStart"
|
||||
@touchmove="onTouchMove"
|
||||
@touchend="onTouchEnd"
|
||||
style="height:600rpx"
|
||||
:style="[{ width: formatSize(width)}, customStyle]"
|
||||
></canvas>
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* sign canvas 手写签名
|
||||
* @description 设置线条宽度、颜色,撤回,清空
|
||||
* @tutorial
|
||||
* @property {String} cid canvas id 不设置则默认为 v-sign-时间戳
|
||||
* @property {String, Number} width canvas 宽度
|
||||
* @property {String, Number} height canvas 高度
|
||||
* @property {Object} customStyle 自定义样式
|
||||
* @property {String} lineColor 画笔颜色
|
||||
* @property {Number} lineWidth 画笔大小,权重大于 v-sign-pen 组件设置的画笔大小
|
||||
* @event {Function} init 当创建完 canvas 实例后触发,向外提供 canvas实例,撤回,清空方法
|
||||
* @example <v-sign @init="signInit"></v-sign>
|
||||
*/
|
||||
import { formatSize } from './utils'
|
||||
// convas 实例
|
||||
let canvasCtx
|
||||
|
||||
export default {
|
||||
name: 'v-sign',
|
||||
props: {
|
||||
// canvas id
|
||||
cid: {
|
||||
type: String,
|
||||
default: `v-sign-${Date.now()}`
|
||||
// required: true
|
||||
},
|
||||
// canvas 宽度
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: '100%'
|
||||
},
|
||||
// canvas 高度
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: 300
|
||||
},
|
||||
// 画笔大小,权重大于 v-sign-pen 组件设置的画笔大小
|
||||
lineWidth: {
|
||||
type: Number
|
||||
},
|
||||
// 线颜色
|
||||
lineColor: {
|
||||
type: String,
|
||||
default: '#000'
|
||||
},
|
||||
// canvas自定义样式
|
||||
customStyle: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
provide() {
|
||||
return {
|
||||
getInterface: this.provideInterface
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
formatSize,
|
||||
lineData: [],
|
||||
winWidth: 0,
|
||||
winHeight: 0,
|
||||
penLineWidth: null, // v-sign-pen 组件设置的画笔大小
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
canvasCtx = uni.createCanvasContext(this.cid, this)
|
||||
// 初始化完成,向外暴露接口
|
||||
this.$emit('init', this.provideInterface())
|
||||
// 获取窗口宽高
|
||||
uni.getSystemInfo({
|
||||
success: res => {
|
||||
this.winWidth = res.windowWidth
|
||||
this.winHeight = res.windowHeight
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
onTouchStart(e) {
|
||||
const pos = e.touches[0]
|
||||
this.lineData.push({
|
||||
style: {
|
||||
color: this.lineColor,
|
||||
width: this.lineWidth || this.penLineWidth || 4
|
||||
},
|
||||
// 屏幕坐标
|
||||
coordinates: [
|
||||
{
|
||||
type: e.type,
|
||||
x: pos.x,
|
||||
y: pos.y
|
||||
}
|
||||
]
|
||||
})
|
||||
this.drawLine()
|
||||
},
|
||||
onTouchMove(e) {
|
||||
const pos = e.touches[0]
|
||||
this.lineData[this.lineData.length - 1].coordinates.push({
|
||||
type: e.type,
|
||||
x: pos.x,
|
||||
y: pos.y
|
||||
})
|
||||
this.drawLine()
|
||||
},
|
||||
onTouchEnd(e) {
|
||||
// console.log(e.type, e)
|
||||
},
|
||||
// 清空画布
|
||||
clear() {
|
||||
this.lineData = []
|
||||
canvasCtx.clearRect(0, 0, this.winWidth, this.winHeight)
|
||||
canvasCtx.draw()
|
||||
},
|
||||
// 撤销
|
||||
revoke() {
|
||||
this.lineData.pop()
|
||||
this.lineData.forEach((item, index) => {
|
||||
canvasCtx.beginPath()
|
||||
canvasCtx.setLineCap('round')
|
||||
canvasCtx.setStrokeStyle(item.style.color)
|
||||
canvasCtx.setLineWidth(item.style.width)
|
||||
item.coordinates.forEach(pos => {
|
||||
if (pos.type == 'touchstart') {
|
||||
canvasCtx.moveTo(pos.x, pos.y)
|
||||
} else {
|
||||
canvasCtx.lineTo(pos.x, pos.y)
|
||||
}
|
||||
})
|
||||
canvasCtx.stroke()
|
||||
})
|
||||
canvasCtx.draw()
|
||||
},
|
||||
// 绘制线条
|
||||
drawLine() {
|
||||
const lineDataLen = this.lineData.length
|
||||
if (!lineDataLen) return
|
||||
const currentLineData = this.lineData[lineDataLen - 1]
|
||||
const coordinates = currentLineData.coordinates
|
||||
const coordinatesLen = coordinates.length
|
||||
if (!coordinatesLen) return
|
||||
let startPos
|
||||
let endPos
|
||||
if (coordinatesLen < 2) {
|
||||
// only start, no move event
|
||||
startPos = coordinates[coordinatesLen - 1]
|
||||
endPos = { x: startPos.x + 1, y: startPos.y }
|
||||
} else {
|
||||
startPos = coordinates[coordinatesLen - 2]
|
||||
endPos = coordinates[coordinatesLen - 1]
|
||||
}
|
||||
|
||||
const style = currentLineData.style
|
||||
canvasCtx.beginPath()
|
||||
canvasCtx.setLineCap('round')
|
||||
canvasCtx.setStrokeStyle(style.color)
|
||||
canvasCtx.setLineWidth(style.width)
|
||||
canvasCtx.moveTo(startPos.x, startPos.y)
|
||||
canvasCtx.lineTo(endPos.x, endPos.y)
|
||||
// const P1 = this.caculateBezier(startPos, endPos, centerPos)
|
||||
// console.log(P1.x, P1.y)
|
||||
// canvasCtx.moveTo(startPos.x, startPos.y)
|
||||
// canvasCtx.quadraticCurveTo(P1.x, P1.y, endPos.x, endPos.y)
|
||||
canvasCtx.stroke()
|
||||
canvasCtx.draw(true)
|
||||
},
|
||||
canvasToTempFilePath(conf = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.canvasToTempFilePath(
|
||||
{
|
||||
canvasId: this.cid,
|
||||
...conf,
|
||||
success: res => {
|
||||
resolve(res.tempFilePath)
|
||||
},
|
||||
fail: err => {
|
||||
console.log('fail', err)
|
||||
reject(err)
|
||||
}
|
||||
},
|
||||
this
|
||||
)
|
||||
})
|
||||
},
|
||||
setLineWidth(numberVal) {
|
||||
this.penLineWidth = numberVal
|
||||
},
|
||||
provideInterface() {
|
||||
return {
|
||||
cid: this.cid,
|
||||
ctx: canvasCtx,
|
||||
clear: this.clear,
|
||||
revoke: this.revoke,
|
||||
canvasToTempFilePath: this.canvasToTempFilePath,
|
||||
setLineWidth: this.setLineWidth
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 计算二次贝塞尔曲线 控制点 P1
|
||||
* 起点 P0(x0,y0)、控制点P1(x1, y1)、P2(x2, y2)、曲线上任意点B(x, y)
|
||||
* 二次贝塞尔公式:B(t) = (1-t)²P0 + 2t(1-t)P1 + t²P2
|
||||
* 代入坐标得:
|
||||
* x = (1-t)²*x0 + 2t(1-t)*x1 + t²*x2
|
||||
* y = (1-t)²*y0 + 2t(1-t)*y1 + t²*y2
|
||||
*/
|
||||
caculateBezier(P0, P2, B, t = 0.5) {
|
||||
const { x: x0, y: y0 } = P0
|
||||
const { x: x2, y: y2 } = P2
|
||||
const { x, y } = B
|
||||
let x1 = (x - (1 - t) * (1 - t) * x0 - t * t * x2) / (2 * t * (1 - t))
|
||||
let y1 = (y - (1 - t) * (1 - t) * y0 - t * t * y2) / (2 * t * (1 - t))
|
||||
return { x: x1, y: y1 }
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.signature-wrap {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
BIN
homepage.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
20
index.html
Normal file
@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<script>
|
||||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
|
||||
CSS.supports('top: constant(a)'))
|
||||
document.write(
|
||||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
|
||||
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
|
||||
</script>
|
||||
<title></title>
|
||||
<!--preload-links-->
|
||||
<!--app-context-->
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"><!--app-html--></div>
|
||||
<script type="module" src="/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
24
main.js
Normal file
@ -0,0 +1,24 @@
|
||||
import App from './App'
|
||||
|
||||
// #ifndef VUE3
|
||||
import Vue from 'vue'
|
||||
import uView from "uview-ui";
|
||||
Vue.use(uView);
|
||||
import './uni.promisify.adaptor'
|
||||
Vue.config.productionTip = false
|
||||
App.mpType = 'app'
|
||||
const app = new Vue({
|
||||
...App
|
||||
})
|
||||
app.$mount()
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE3
|
||||
import { createSSRApp } from 'vue'
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
72
manifest.json
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
"name" : "exam-h5",
|
||||
"appid" : "__UNI__254C48E",
|
||||
"description" : "",
|
||||
"versionName" : "1.0.0",
|
||||
"versionCode" : "100",
|
||||
"transformPx" : false,
|
||||
/* 5+App特有相关 */
|
||||
"app-plus" : {
|
||||
"usingComponents" : true,
|
||||
"nvueStyleCompiler" : "uni-app",
|
||||
"compilerVersion" : 3,
|
||||
"splashscreen" : {
|
||||
"alwaysShowBeforeRender" : true,
|
||||
"waiting" : true,
|
||||
"autoclose" : true,
|
||||
"delay" : 0
|
||||
},
|
||||
/* 模块配置 */
|
||||
"modules" : {},
|
||||
/* 应用发布信息 */
|
||||
"distribute" : {
|
||||
/* android打包配置 */
|
||||
"android" : {
|
||||
"permissions" : [
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||
]
|
||||
},
|
||||
/* ios打包配置 */
|
||||
"ios" : {},
|
||||
/* SDK配置 */
|
||||
"sdkConfigs" : {}
|
||||
}
|
||||
},
|
||||
/* 快应用特有相关 */
|
||||
"quickapp" : {},
|
||||
/* 小程序特有相关 */
|
||||
"mp-weixin" : {
|
||||
"appid" : "",
|
||||
"setting" : {
|
||||
"urlCheck" : false
|
||||
},
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
},
|
||||
"vueVersion" : "2"
|
||||
}
|
||||
28
package-lock.json
generated
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "exam-h5",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "exam-h5",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"uview-ui": "^1.8.8"
|
||||
}
|
||||
},
|
||||
"node_modules/uview-ui": {
|
||||
"version": "1.8.8",
|
||||
"resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.8.8.tgz",
|
||||
"integrity": "sha512-Osal3yzXiHor0In9OPTZuXTaqTbDglMZ9RGK/MPYDoQQs+y0hrBCUD0Xp5T70C8i2lLu2X6Z11zJhmsQWMR7Jg=="
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"uview-ui": {
|
||||
"version": "1.8.8",
|
||||
"resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.8.8.tgz",
|
||||
"integrity": "sha512-Osal3yzXiHor0In9OPTZuXTaqTbDglMZ9RGK/MPYDoQQs+y0hrBCUD0Xp5T70C8i2lLu2X6Z11zJhmsQWMR7Jg=="
|
||||
}
|
||||
}
|
||||
}
|
||||
15
package.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "exam-h5",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"uview-ui": "^1.8.8"
|
||||
}
|
||||
}
|
||||
73
pages.json
Normal file
@ -0,0 +1,73 @@
|
||||
{
|
||||
"easycom": {
|
||||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
|
||||
},
|
||||
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
|
||||
{
|
||||
"path": "pages/login/login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
}, {
|
||||
"path": "pages/examlist/examlist",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationStyle": "custom",
|
||||
"onReachBottomDistance": 40, //距离底部多远时触发 单位为px
|
||||
"enablePullDownRefresh": true //设置参数为true
|
||||
}
|
||||
}, {
|
||||
"path": "pages/user/user",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
}, {
|
||||
"path": "pages/register/register",
|
||||
"style": {
|
||||
"navigationBarTitleText": "注册账号",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
}, {
|
||||
"path": "pages/forgotPassword/forgotPassword",
|
||||
"style": {
|
||||
"navigationBarTitleText": "忘记密码",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
}, {
|
||||
"path": "pages/addexam/addexam",
|
||||
"style": {
|
||||
"navigationBarTitleText": "新增考试",
|
||||
"enablePullDownRefresh": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarBackgroundColor": "#4C7BC9",
|
||||
"backgroundColor": "#4C7BC9"
|
||||
},
|
||||
"uniIdRouter": {},
|
||||
"tabBar": {
|
||||
"color": "#7A7E83",
|
||||
"selectedColor": "#435950",
|
||||
"borderStyle": "black",
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [{
|
||||
"pagePath": "pages/examlist/examlist",
|
||||
"iconPath": "static/homepagew.png",
|
||||
"selectedIconPath": "static/homepagews.png",
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/user/user",
|
||||
"iconPath": "static/userw.png",
|
||||
"selectedIconPath": "static/users.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
379
pages/addexam/addexam.scss
Normal file
@ -0,0 +1,379 @@
|
||||
.app {
|
||||
font-size: 34rpx;
|
||||
padding-top: 10rpx;
|
||||
height: 100%;
|
||||
background: #FFFFFF;
|
||||
padding-bottom: 200rpx;
|
||||
|
||||
.title {
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
font-size: 34rpx;
|
||||
margin: 0px auto;
|
||||
width: 100%;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.mask {
|
||||
.Agreement {
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
text-align: center;
|
||||
height: 1000rpx;
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
width: 94%;
|
||||
left: 3%;
|
||||
font-size: 30rpx;
|
||||
|
||||
.scroll-Y {
|
||||
width: 98%;
|
||||
margin: 0 auto;
|
||||
height: 830rpx;
|
||||
overflow-y: scroll;
|
||||
text-align: left;
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
.cancel {
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: 32rpx;
|
||||
background-color: #F4F5F7;
|
||||
position: absolute;
|
||||
border-top: 1rpx solid #000000;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 50%;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.determine {
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: 32rpx;
|
||||
width: 50%;
|
||||
color: #F4F5F7;
|
||||
background: #4C7BC9;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.addressitem {
|
||||
width: 97%;
|
||||
border-bottom: 1rpx solid #D8D4D4;
|
||||
margin-left: 3%;
|
||||
height: 100%;
|
||||
|
||||
.leftaddress {
|
||||
width: 15%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.addition {
|
||||
color: #666666;
|
||||
display: inline-block;
|
||||
line-height: 50rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.money {
|
||||
font-size: 32rpx;
|
||||
color: #D43953;
|
||||
position: absolute;
|
||||
right: 5%;
|
||||
top: 15%;
|
||||
}
|
||||
|
||||
.user {
|
||||
width: 100%;
|
||||
padding: 10rpx;
|
||||
line-height: 93rpx;
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
.timeyear{
|
||||
.bottomtext{
|
||||
-webkit-overflow-scrolling: touch;
|
||||
width: 96%;
|
||||
margin: 0 auto;
|
||||
.items{
|
||||
display: flex;
|
||||
justify-content:flex-start;
|
||||
flex-wrap: wrap;
|
||||
text-align: center;
|
||||
.timeitem{
|
||||
width: 21%;
|
||||
margin: 0 2% 20rpx;
|
||||
height: 86rpx;
|
||||
border-radius: 5rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 86rpx;
|
||||
border: 2rpx solid #DADADA;
|
||||
}
|
||||
.timeitemtap{
|
||||
width: 21%;
|
||||
margin: 0 2% 20rpx;
|
||||
height: 86rpx;
|
||||
border: 2rpx solid #F44B2F;
|
||||
border-radius: 5rpx;
|
||||
font-size: 28rpx;
|
||||
color: #F44B2F;
|
||||
line-height: 86rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.toptext{
|
||||
-webkit-overflow-scrolling: touch;
|
||||
padding-top: 10rpx;
|
||||
display: flex;
|
||||
justify-content:space-around;
|
||||
height: 50rpx;
|
||||
color: #000000;
|
||||
line-height: 27rpx;
|
||||
margin-bottom: 30rpx;
|
||||
text-align: center;
|
||||
.Soonerorlater{
|
||||
width: 200rpx;
|
||||
font-size: 36rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
.Soonerorlaterclass{
|
||||
font-size: 36rpx;
|
||||
color: #F44B2F;
|
||||
width: 200rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
view:nth-child(2){
|
||||
width: 4rpx;
|
||||
height: 27rpx;
|
||||
background: #C5C3C3;
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item {
|
||||
width: 97%;
|
||||
border-bottom: 1rpx solid #D8D4D4;
|
||||
margin-left: 3%;
|
||||
|
||||
.addition {
|
||||
color: #666666;
|
||||
line-height: 30rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remarks {
|
||||
width: 94%;
|
||||
margin: 10rpx auto;
|
||||
padding: 3%;
|
||||
font-size: 34rpx;
|
||||
height: 96rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
margin-top: 20rpx;
|
||||
position: relative;
|
||||
|
||||
.span {
|
||||
display: inline-block;
|
||||
width: 20%;
|
||||
// overflow: hidden;
|
||||
// text-overflow: ellipsis;
|
||||
// white-space: nowrap;
|
||||
position: absolute;
|
||||
top:50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.input-placeholder{
|
||||
color: #C5C3C3;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
input {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 23%;
|
||||
width: 77%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
.priceback {
|
||||
width: 90%;
|
||||
background: #FFFFFF;
|
||||
height: 100rpx;
|
||||
margin: 0 auto;
|
||||
|
||||
.queren {
|
||||
width: 100%;
|
||||
height: 90rpx;
|
||||
background: #4C7BC9;
|
||||
border-radius: 26rpx;
|
||||
margin: 105rpx 0 0 15rpx;
|
||||
line-height: 90rpx;
|
||||
text-align: center;
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
|
||||
.radio-content {
|
||||
margin: 50rpx auto;
|
||||
width: 70%;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
position: relative;
|
||||
|
||||
.agreement {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 20%;
|
||||
transform: translateY(-50%);
|
||||
color: #878987;
|
||||
}
|
||||
|
||||
.radio-right {
|
||||
height: 100rpx;
|
||||
width: 100rpx;
|
||||
|
||||
.radio {
|
||||
display: inline-block;
|
||||
width: 35rpx;
|
||||
height: 35rpx;
|
||||
border-radius: 70%;
|
||||
border: 2rpx solid #178ffb;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 5%;
|
||||
transform: translateY(-50%);
|
||||
|
||||
.radio-active {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #178ffb;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
// margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Consumablespackage .money {
|
||||
top: 8%;
|
||||
}
|
||||
/* 耗材包 */
|
||||
.Consumablespackage {
|
||||
width: 94%;
|
||||
margin: 10rpx auto;
|
||||
padding: 3% 0 3% 3%;
|
||||
font-size: 34rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
margin-top: 20rpx;
|
||||
position: relative;
|
||||
padding-bottom: 40rpx;
|
||||
::v-deep .u-checkbox__label{
|
||||
width: 100% !important;
|
||||
}
|
||||
.detail {
|
||||
width: 100%;
|
||||
line-height: 100rpx;
|
||||
// padding: 20rpx 0 0 40rpx;
|
||||
position: relative;
|
||||
.itemConsumabletitle{
|
||||
width:55%;
|
||||
position: absolute;
|
||||
top:50%;
|
||||
transform: translateY(-50%);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
/deep/ .u-checkbox{
|
||||
margin: 40rpx 0 0;
|
||||
position: relative;
|
||||
}
|
||||
span{
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
font-size: 28rpx;
|
||||
color: #D43953;
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
right:5%;
|
||||
top:50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 套餐 */
|
||||
.Package {
|
||||
width: 97%;
|
||||
height: 500rpx;
|
||||
font-size: 34rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
margin: 20rpx auto 40rpx;
|
||||
position: relative;
|
||||
.uppicture {
|
||||
border: 1rpx dashed #818181;
|
||||
width: 90%;
|
||||
height: 400rpx;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 35rpx;
|
||||
color: #969394;
|
||||
}
|
||||
}
|
||||
|
||||
.checkboxs{
|
||||
margin-top: 30rpx;
|
||||
::v-deep .u-checkbox{
|
||||
padding-right: 40rpx;
|
||||
}
|
||||
}
|
||||
.detail {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: 31rpx;
|
||||
font-size: 32rpx;
|
||||
color: #666666;
|
||||
line-height: 31rpx;
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 60%;
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.message {
|
||||
width: 94%;
|
||||
background: white;
|
||||
border-radius: 20rpx;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
line-height: 96rpx;
|
||||
}
|
||||
}
|
||||
503
pages/addexam/addexam.vue
Normal file
@ -0,0 +1,503 @@
|
||||
<template>
|
||||
<view class="app">
|
||||
<view class="user">
|
||||
<view class="title">
|
||||
一、个人信息
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>姓名:</span>
|
||||
<span class='addition'>{{personInfo.realName}}</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>手机号:</span>
|
||||
<span class='addition'>{{personInfo.phone}}</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>身份证号:</span>
|
||||
<span class='addition'>{{personInfo.userName}}</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>性别:</span>
|
||||
<span class='addition'>{{personInfo.sex}}</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>出生日期:</span>
|
||||
<span class='addition'>{{personInfo.birthday}}</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>电子邮箱(用于接收考试通知):</span>
|
||||
<span class='addition'>
|
||||
<u-input type="text" placeholder="请输入电子邮箱" v-model="personInfo.email" />
|
||||
</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>通讯地址:</span>
|
||||
<span class='addition'>
|
||||
<u-input type="text" placeholder="请输入通讯地址" v-model="personInfo.address" />
|
||||
</span>
|
||||
</view>
|
||||
</view>
|
||||
<view class="user">
|
||||
<view class="title">
|
||||
二、教育背景
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>最高学历:</span>
|
||||
<span class='addition'>
|
||||
<u-radio-group v-model="personInfo.education" @change="">
|
||||
<u-radio @change="" v-for="(item, index) in educationlist" :key="index" :name="item.label"
|
||||
style="padding: 0 15rpx;" :disabled="item.checked">
|
||||
{{item.name}}
|
||||
</u-radio>
|
||||
</u-radio-group>
|
||||
</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>毕业院校:</span>
|
||||
<span class='addition'>
|
||||
<u-input type="text" placeholder="请输入毕业院校" v-model="personInfo.graduateSchool" />
|
||||
</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>专业(如适用):</span>
|
||||
<span class='addition'>
|
||||
<u-input type="text" placeholder="请输入专业" v-model="personInfo.major" />
|
||||
</span>
|
||||
</view>
|
||||
</view>
|
||||
<view class="user">
|
||||
<view class="title">
|
||||
三、报考信息
|
||||
<span class='addition' @click="examshow=true"
|
||||
style="margin-left:20rpx;padding:6rpx 20rpx;background: #4C7BC9;border-radius: 10rpx;color: #fff;">
|
||||
选择考试
|
||||
</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>考试名称:</span>
|
||||
<span class='addition' v-if="personInfo.title">
|
||||
{{personInfo.title}}
|
||||
</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>考试日期:</span>
|
||||
<span class='addition' v-if="personInfo.title">
|
||||
{{personInfo.startDate}}至{{personInfo.endDate}}
|
||||
</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>考试时间:</span>
|
||||
<span class='addition' v-if="personInfo.title">
|
||||
{{personInfo.startTime}}至{{personInfo.endTime}}
|
||||
</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>考试费用:</span>
|
||||
<span class='addition' v-if="personInfo.title" style="color:red">
|
||||
¥{{personInfo.examFee}}
|
||||
</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>报考类别(可选):</span>
|
||||
<span class='addition'>
|
||||
<u-radio-group v-model="personInfo.regType" @change="">
|
||||
<u-radio @change="" v-for="(item, index) in regTypelist" :key="index" :name="item.label"
|
||||
style="padding: 15rpx;" :disabled="item.checked">
|
||||
{{item.name}}
|
||||
</u-radio>
|
||||
</u-radio-group>
|
||||
</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>培训经历(如有):</span>
|
||||
<span class='addition'>
|
||||
<view class="item" style="padding: 10rpx 0;">
|
||||
<span>机构名称:</span>
|
||||
<span class='addition'>
|
||||
<u-input type="text" placeholder="请输入机构名称" v-model="personInfo.trainInstitution" />
|
||||
</span>
|
||||
</view>
|
||||
<view class="item" style="padding: 10rpx 0;">
|
||||
<span>培训时间:</span>
|
||||
<span class='addition' @click="trainDateshow=true"
|
||||
style="margin-left:50rpx;display: inline-block;padding: 10rpx;background-color: #4C7BC9;border-radius: 10rpx;color: #fff;">
|
||||
选择时间区间
|
||||
</span>
|
||||
<view class="" v-if="personInfo.trainStartDate" style="padding: 16rpx 0;">
|
||||
{{personInfo.trainStartDate+'至'}}{{personInfo.trainEndDate}}
|
||||
</view>
|
||||
</view>
|
||||
</span>
|
||||
</view>
|
||||
</view>
|
||||
<view class="user">
|
||||
<view class="title">
|
||||
四、上传材料
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>身份证正面:</span>
|
||||
<span class='addition'>
|
||||
<u-upload :action="action" :form-data="{
|
||||
type:'cardFrontUrl'
|
||||
}" :header="header" :file-list="fileList" :max-count="1" @on-uploaded="uploadedcardFront"></u-upload>
|
||||
</span>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>身份证反面:</span>
|
||||
<span class='addition'>
|
||||
<u-upload :action="action" :form-data="{
|
||||
type:'cardBackUrl'
|
||||
}" :header="header" :file-list="fileList" :max-count="1" @on-uploaded="uploadedcardBack"></u-upload>
|
||||
</span>
|
||||
</view>
|
||||
<view class="item" style="line-height: 50rpx;">
|
||||
<span>近期白底免冠证件照(1寸,JPG格式,<20KB):</span>
|
||||
<span class='addition'>
|
||||
<u-upload :action="action" :form-data="{
|
||||
type:'photoUrl'
|
||||
}" :header="header" :file-list="fileList" :max-count="1" @on-uploaded="uploadedphoto"></u-upload>
|
||||
</span>
|
||||
</view>
|
||||
<view class="item" style="line-height: 50rpx;">
|
||||
<span>学历证明(毕业证或学信网截图):</span>
|
||||
<span class='addition'>
|
||||
<u-upload :action="action" :form-data="{
|
||||
type:'certificateUrl'
|
||||
}" :header="header" :file-list="fileList" :max-count="1" @on-uploaded="uploadedcertificate"></u-upload>
|
||||
</span>
|
||||
</view>
|
||||
</view>
|
||||
<view class="user">
|
||||
<view class="title">
|
||||
五、声明与签字
|
||||
</view>
|
||||
<view style="line-height: 40rpx;font-size: 32rpx;color:red;padding:0 10rpx">
|
||||
本人确认以上信息真实有效,并同意考试机构核实相关信息。
|
||||
</view>
|
||||
<view class="Package">
|
||||
签名:
|
||||
<span style='color:#C5C3C3;padding-left: 10rpx;font-size: 30rpx;'></span>
|
||||
<view class="checkboxs">
|
||||
<view class="uppicture" @tap='signatureshow=true'>
|
||||
<image v-if="!userSignaturePictureUrl" style="width: 36rpx;height: 36rpx;margin:8% 0 0 35%"
|
||||
src="@/static/autograph.png" mode="">
|
||||
</image>
|
||||
<span v-if="!userSignaturePictureUrl">点此签名</span>
|
||||
<image v-else :src="userSignaturePictureUrl" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="item">
|
||||
<span>日期:</span>
|
||||
<span class='addition'>
|
||||
{{personInfo.regTime}}
|
||||
</span>
|
||||
</view>
|
||||
</view>
|
||||
<view class="priceback">
|
||||
<view class="queren" @tap='updata'>保存</view>
|
||||
</view>
|
||||
<u-toast ref="uToast" />
|
||||
<u-mask :show="signatureshow" @click="signatureshow = false">
|
||||
<view style="position:absolute;bottom:0;height:900rpx;width:100%;background-color: #fff;"
|
||||
v-if='signatureshow'>
|
||||
<signature @userSignaturePictureUrl='userSignaturePicture' @click.native.stop
|
||||
style='background-color: #F4F5F7;width: 100%;height: 900rpx;'></signature>
|
||||
</view>
|
||||
</u-mask>
|
||||
<u-select v-model="examshow" :list="examlist" @confirm="examconfirm" value-name="id"
|
||||
label-name="title"></u-select>
|
||||
<u-calendar v-model="trainDateshow" mode="range" @change="trainDatechange"></u-calendar>
|
||||
<u-toast ref="uToast" />
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
info
|
||||
} from '@/api/user/index.js'
|
||||
import {
|
||||
getExamList,
|
||||
save
|
||||
} from '@/api/addexam/index.js'
|
||||
import baseurl from '@/api/baseurl.js'
|
||||
import signature from '@/components/signature/signature.vue'
|
||||
export default {
|
||||
components: {
|
||||
signature
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
examshow: false,
|
||||
trainDateshow: false,
|
||||
signatureshow: false,
|
||||
userSignaturePictureUrl: null,
|
||||
examlist: [],
|
||||
educationlist: [{
|
||||
name: '初中',
|
||||
label: 1,
|
||||
checked: false,
|
||||
},
|
||||
{
|
||||
name: '高中/中专',
|
||||
label: 2,
|
||||
checked: false,
|
||||
},
|
||||
{
|
||||
name: '大专及以上',
|
||||
label: 3,
|
||||
checked: false,
|
||||
}
|
||||
],
|
||||
regTypelist: [{
|
||||
name: '普通医疗护理员',
|
||||
label: 1,
|
||||
checked: false,
|
||||
},
|
||||
{
|
||||
name: '老年医疗护理员',
|
||||
label: 2,
|
||||
checked: false,
|
||||
},
|
||||
{
|
||||
name: '孕产妇和新生儿医疗护理员',
|
||||
label: 3,
|
||||
checked: false,
|
||||
}
|
||||
],
|
||||
action: baseurl + '/exam/api/file/upload',
|
||||
header: {
|
||||
token: uni.getStorageSync('examh5token')
|
||||
},
|
||||
fileList: [],
|
||||
personInfo: {
|
||||
"address": "",
|
||||
"cardBack": "",
|
||||
"cardCopy": "", // 身份证正反面复印件
|
||||
"cardFront": "",
|
||||
"certificate": "",
|
||||
"education": 0,
|
||||
"email": "",
|
||||
"examId": "",
|
||||
startTime: undefined,
|
||||
endTime: undefined,
|
||||
startDate: undefined,
|
||||
endDate: undefined,
|
||||
"graduateSchool": "",
|
||||
"major": "",
|
||||
"phone": "",
|
||||
"photo": "",
|
||||
"physicalReport": "", //健康体检报告
|
||||
"realName": "",
|
||||
"regTime": "",
|
||||
"regType": 0,
|
||||
"signPicture": "",
|
||||
"title": "",
|
||||
"trainEndDate": "",
|
||||
"trainInstitution": "",
|
||||
"trainStartDate": "",
|
||||
"userId": "",
|
||||
"userName": "",
|
||||
examFee: undefined,
|
||||
},
|
||||
}
|
||||
},
|
||||
onShow() {},
|
||||
onLoad() {
|
||||
this.getTodayDate()
|
||||
this.myInfo()
|
||||
},
|
||||
methods: {
|
||||
uploadedcertificate(res) {
|
||||
this.personInfo.certificate = res[0].response.data.url
|
||||
},
|
||||
uploadedphoto(res) {
|
||||
this.personInfo.photo = res[0].response.data.url
|
||||
},
|
||||
uploadedcardBack(res) {
|
||||
this.personInfo.cardBack = res[0].response.data.url
|
||||
},
|
||||
uploadedcardFront(res) {
|
||||
this.personInfo.cardFront = res[0].response.data.url
|
||||
},
|
||||
examconfirm(e) {
|
||||
let obj = this.examlist.filter(el => el.id == e[0].value)
|
||||
this.personInfo.title = e[0].label
|
||||
this.personInfo.examId = e[0].value
|
||||
this.personInfo.startTime = obj[0].startTime
|
||||
this.personInfo.endTime = obj[0].endTime
|
||||
this.personInfo.startDate = obj[0].startDate
|
||||
this.personInfo.endDate = obj[0].endDate
|
||||
this.personInfo.examFee = obj[0].examFee
|
||||
},
|
||||
trainDatechange(e) {
|
||||
this.personInfo.trainEndDate = e.endDate
|
||||
this.personInfo.trainStartDate = e.startDate
|
||||
},
|
||||
//签名
|
||||
userSignaturePicture(data) {
|
||||
let that = this
|
||||
this.userSignaturePictureUrl = data
|
||||
this.signatureshow = false
|
||||
uni.uploadFile({
|
||||
url: baseurl + '/exam/api/file/upload',
|
||||
filePath: this.userSignaturePictureUrl,
|
||||
name: 'file',
|
||||
header: this.header,
|
||||
formData: {
|
||||
type: 'signPictureUrl'
|
||||
},
|
||||
timeout: 5000,
|
||||
success(res) {
|
||||
that.personInfo.signPicture = JSON.parse(res.data).data.url
|
||||
}
|
||||
})
|
||||
},
|
||||
//确认
|
||||
updata() {
|
||||
save(this.personInfo).then(res => {
|
||||
if (res.code == 0) {
|
||||
this.$refs.uToast.show({
|
||||
title: '报名考试成功!',
|
||||
type: 'success',
|
||||
duration: '1500',
|
||||
back: true
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
myInfo() {
|
||||
info({
|
||||
token: uni.getStorageSync('examh5token')
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
uni.setStorageSync("examh5token", res.data.token)
|
||||
uni.setStorageSync("examh5user", {
|
||||
id: res.data.id,
|
||||
phone: res.data.phone,
|
||||
name: res.data.realName,
|
||||
cardNo: res.data.userName
|
||||
})
|
||||
this.personInfo.realName = res.data.realName
|
||||
this.personInfo.userId = res.data.id
|
||||
this.personInfo.phone = res.data.phone
|
||||
this.personInfo.userName = res.data.userName
|
||||
this.personInfo.sex = this.getsex(res.data.userName)
|
||||
this.personInfo.birthday = this.getbirthday(res.data.userName)
|
||||
}
|
||||
})
|
||||
getExamList().then(res => {
|
||||
this.examlist = res.data
|
||||
})
|
||||
},
|
||||
getTodayDate() {
|
||||
const today = new Date();
|
||||
this.personInfo.regTime = today.toISOString().split('T')[0];
|
||||
},
|
||||
getsex(idCard) {
|
||||
// 在Vue组件的方法中
|
||||
if (!idCard || idCard.length !== 18) {
|
||||
return '身份证号码不合法';
|
||||
}
|
||||
// 获取第17位字符
|
||||
const genderChar = idCard.charAt(16);
|
||||
// 判断是否为数字
|
||||
if (isNaN(genderChar)) {
|
||||
return '身份证号码不合法';
|
||||
}
|
||||
// 转换为数字并判断奇偶
|
||||
const genderNum = parseInt(genderChar, 10);
|
||||
return genderNum % 2 === 1 ? '男' : '女';
|
||||
},
|
||||
getbirthday(idCard) {
|
||||
// 在Vue组件的方法中
|
||||
if (!idCard) {
|
||||
return '身份证号码不能为空';
|
||||
}
|
||||
// 处理18位身份证
|
||||
if (idCard.length === 18) {
|
||||
if (!/^\d{17}[\dXx]$/.test(idCard)) {
|
||||
return '身份证号码格式不正确';
|
||||
}
|
||||
// 提取出生年月日 YYYYMMDD
|
||||
const birthdayStr = idCard.substr(6, 8);
|
||||
// 格式化为 YYYY-MM-DD
|
||||
return `${birthdayStr.substr(0, 4)}-${birthdayStr.substr(4, 2)}-${birthdayStr.substr(6, 2)}`;
|
||||
}
|
||||
// 处理15位身份证
|
||||
if (idCard.length === 15) {
|
||||
if (!/^\d{15}$/.test(idCard)) {
|
||||
return '身份证号码格式不正确';
|
||||
}
|
||||
// 提取出生年月日 YYMMDD
|
||||
const birthdayStr = idCard.substr(6, 6);
|
||||
// 格式化为 19YY-MM-DD (15位身份证都是19XX年出生的)
|
||||
return `19${birthdayStr.substr(0, 2)}-${birthdayStr.substr(2, 2)}-${birthdayStr.substr(4, 2)}`;
|
||||
}
|
||||
return '身份证号码长度不正确';
|
||||
},
|
||||
argAdd(arg1, arg2) {
|
||||
// 加法函数
|
||||
var _this = this,
|
||||
r1 = 0,
|
||||
r2 = 0,
|
||||
m = 0;
|
||||
try {
|
||||
r1 = arg1.toString().split(".")[1].length
|
||||
} catch (e) {}
|
||||
try {
|
||||
r2 = arg2.toString().split(".")[1].length
|
||||
} catch (e) {}
|
||||
m = Math.pow(10, Math.max(r1, r2))
|
||||
return _this.argDiv((_this.argMul(arg1, m) + _this.argMul(arg2, m)), m)
|
||||
},
|
||||
argSubtr(arg1, arg2) {
|
||||
// 减法函数
|
||||
var _this = this,
|
||||
r1 = 0,
|
||||
r2 = 0,
|
||||
m = 0;
|
||||
try {
|
||||
r1 = arg1.toString().split(".")[1].length
|
||||
} catch (e) {}
|
||||
try {
|
||||
r2 = arg2.toString().split(".")[1].length
|
||||
} catch (e) {}
|
||||
m = Math.pow(10, Math.max(r1, r2));
|
||||
return _this.argDiv((_this.argMul(arg1, m) - _this.argMul(arg2, m)), m)
|
||||
},
|
||||
argMul(arg1, arg2) {
|
||||
// 乘法函数
|
||||
var _this = this,
|
||||
m = 0,
|
||||
s1 = arg1.toString(),
|
||||
s2 = arg2.toString();
|
||||
try {
|
||||
m += s1.split(".")[1].length
|
||||
} catch (e) {}
|
||||
try {
|
||||
m += s2.split(".")[1].length
|
||||
} catch (e) {}
|
||||
return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
|
||||
},
|
||||
argDiv(arg1, arg2) {
|
||||
// 除法函数
|
||||
var _this = this,
|
||||
t1 = 0,
|
||||
t2 = 0,
|
||||
r1, r2;
|
||||
try {
|
||||
t1 = arg1.toString().split(".")[1].length
|
||||
} catch (e) {}
|
||||
try {
|
||||
t2 = arg2.toString().split(".")[1].length
|
||||
} catch (e) {}
|
||||
r1 = Number(arg1.toString().replace(".", ""))
|
||||
r2 = Number(arg2.toString().replace(".", ""))
|
||||
return _this.argMul((r1 / r2), Math.pow(10, t2 - t1));
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import './addexam.scss'
|
||||
</style>
|
||||
175
pages/examlist/examlist.vue
Normal file
@ -0,0 +1,175 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<u-navbar :is-back="false" title="考试列表" :background="background" title-color="white">
|
||||
<view class="navbar-right" slot="right" @click="signup">
|
||||
新增考试
|
||||
</view>
|
||||
</u-navbar>
|
||||
<view class="app">
|
||||
<view class="items" v-if="list.length>0">
|
||||
<view class="item" v-for="(item,index) in list">
|
||||
<view class="title">
|
||||
<view class="text">
|
||||
{{item.title}}
|
||||
</view>
|
||||
<view class="image">
|
||||
<image src="../../static/jinbi.png" mode=""></image>
|
||||
<span v-if="item.examFee&&item.examFee>=0">
|
||||
{{item.examFee}}
|
||||
</span>
|
||||
<span v-else>
|
||||
0
|
||||
</span>
|
||||
</view>
|
||||
</view>
|
||||
<view class="time" style="margin-top: 20rpx;color: #EA706A;font-weight:600">
|
||||
考试费用:{{item.examFee}}
|
||||
</view>
|
||||
<view class="time">
|
||||
考试日期:{{item.startDate}}至{{item.endDate}}
|
||||
</view>
|
||||
<view class="time">
|
||||
考试时间:{{item.startTime}}至{{item.endTime}}
|
||||
</view>
|
||||
<view class="time">
|
||||
考试时长:{{item.totalTime}}分钟
|
||||
</view>
|
||||
<view class="time">
|
||||
试卷总分:{{item.totalScore}}
|
||||
</view>
|
||||
<view class="time">
|
||||
考试人员:{{user.name}}
|
||||
</view>
|
||||
<view class="time">
|
||||
身份证:{{user.cardNo}}
|
||||
</view>
|
||||
<view class="time">
|
||||
手机号:{{user.phone}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="" style="margin-top: 100rpx;">
|
||||
<u-empty text="暂无工单" mode="list" icon-size='240' font-size='32'></u-empty>
|
||||
</view>
|
||||
<u-toast ref="uToast" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getRegExamList
|
||||
} from '@/api/examlist/index.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
user: uni.getStorageSync('examh5user'),
|
||||
background: {
|
||||
backgroundColor: "#4C7BC9",
|
||||
},
|
||||
list: [], //项目list
|
||||
total: 0,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
//考试报名
|
||||
signup() {
|
||||
uni.navigateTo({
|
||||
url: "/pages/addexam/addexam"
|
||||
})
|
||||
},
|
||||
//list请求
|
||||
info() {
|
||||
getRegExamList().then(res => {
|
||||
this.list = res.data
|
||||
})
|
||||
},
|
||||
},
|
||||
onLoad() {},
|
||||
onShow() {
|
||||
this.info();
|
||||
},
|
||||
onReachBottom() { //下滑加载
|
||||
if (this.list.length >= this.total) {} else {}
|
||||
},
|
||||
onPullDownRefresh() { //下拉刷新
|
||||
this.info();
|
||||
setTimeout(() => {
|
||||
uni.stopPullDownRefresh();
|
||||
}, 1000);
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.navbar-right {
|
||||
color: #fff;
|
||||
padding-right: 20rpx;
|
||||
}
|
||||
|
||||
.app {
|
||||
padding: 0;
|
||||
|
||||
.items {
|
||||
width: 96%;
|
||||
margin: 20rpx auto;
|
||||
|
||||
.item {
|
||||
margin: 10rpx auto;
|
||||
background-color: #fff;
|
||||
box-shadow: 0rpx 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
|
||||
border-radius: 5rpx;
|
||||
padding: 10rpx;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
color: #333333;
|
||||
font-size: 30rpx;
|
||||
padding-bottom: 60rpx;
|
||||
|
||||
.time {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.title {
|
||||
line-height: 100rpx;
|
||||
border-bottom: 1rpx solid #E6E6E6;
|
||||
font-size: 38rpx;
|
||||
color: #333333;
|
||||
position: relative;
|
||||
height: 100rpx;
|
||||
|
||||
.text {
|
||||
height: 100%;
|
||||
overflow: hidden; //超出的文本隐藏
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1; // 超出多少行
|
||||
-webkit-box-orient: vertical;
|
||||
width: calc(100% - 170rpx);
|
||||
}
|
||||
|
||||
.image {
|
||||
position: absolute;
|
||||
right: 0%;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: inline-block;
|
||||
font-size: 30rpx;
|
||||
color: #EA706A;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
width: 100rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
transform: translateY(20%);
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
padding-right: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
74
pages/forgotPassword/forgotPassword.scss
Normal file
@ -0,0 +1,74 @@
|
||||
.app {
|
||||
height: calc(100vh - 44px);
|
||||
padding: 20rpx 0;
|
||||
|
||||
.item {
|
||||
font-size: 34rpx;
|
||||
margin: 0 auto 20rpx;
|
||||
width: 94%;
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
background-color: #fff;
|
||||
box-shadow: 0px 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
|
||||
border-radius: 20rpx;
|
||||
position: relative;
|
||||
|
||||
.lefttext {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 3%;
|
||||
}
|
||||
|
||||
.righttext {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 18%;
|
||||
height: 100rpx;
|
||||
}
|
||||
|
||||
.lefttext,
|
||||
.righttext {
|
||||
::v-deep .uni-input-input {
|
||||
font-size: 34rpx;
|
||||
}
|
||||
|
||||
::v-deep .uni-input-wrapper {
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
}
|
||||
|
||||
::v-deep .uni-input-placeholder {
|
||||
line-height: 100rpx;
|
||||
font-size: 34rpx;
|
||||
font-weight: 400;
|
||||
color: #C3C1C1;
|
||||
}
|
||||
}
|
||||
|
||||
.obtaincode {
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
color: #4C7BC9;
|
||||
line-height: 100rpx;
|
||||
position: absolute;
|
||||
right: 5%;
|
||||
top: 0%;
|
||||
}
|
||||
}
|
||||
|
||||
.loginbtn {
|
||||
width: 80%;
|
||||
height: 100rpx;
|
||||
text-align: center;
|
||||
line-height: 100rpx;
|
||||
background: #4C7BC9;
|
||||
border-radius: 51rpx;
|
||||
font-size: 41rpx;
|
||||
color: #FFFFFF;
|
||||
position: absolute;
|
||||
top: 60%;
|
||||
left: 10%;
|
||||
}
|
||||
}
|
||||
158
pages/forgotPassword/forgotPassword.vue
Normal file
@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<view class="app">
|
||||
<view class="item">
|
||||
<view class="lefttext">
|
||||
姓名
|
||||
</view>
|
||||
<u-input class="righttext" style='left:23%' type="text" placeholder="请输入" maxlength="11"
|
||||
v-model="phonenumber" />
|
||||
</view>
|
||||
<view class="item">
|
||||
<view class="lefttext">
|
||||
身份证号
|
||||
</view>
|
||||
<u-input class="righttext" style='left:30%' type="text" placeholder="请输入" maxlength="11"
|
||||
v-model="phonenumber" />
|
||||
</view>
|
||||
<view class="item">
|
||||
<view class="lefttext">
|
||||
手机号
|
||||
</view>
|
||||
<u-input class="righttext" style='left:23%' type="text" placeholder="请输入" maxlength="11"
|
||||
v-model="phonenumber" />
|
||||
</view>
|
||||
<view class="item">
|
||||
<view class="lefttext">
|
||||
输入新密码
|
||||
</view>
|
||||
<u-input class='righttext' style='left:30%' placeholder="请输入密码" maxlength="10" type="password"
|
||||
:border="false" :password-icon="true" v-model="newpassword" />
|
||||
</view>
|
||||
<view class="item">
|
||||
<view class="lefttext">
|
||||
重复新密码
|
||||
</view>
|
||||
<u-input class='righttext' style='left:30%' placeholder="请再次输入密码" maxlength="10" type="password"
|
||||
:border="false" :password-icon="true" v-model="password" />
|
||||
</view>
|
||||
<!-- <view class="item">
|
||||
<view class="lefttext">
|
||||
验证码
|
||||
</view>
|
||||
<input class="righttext" style='left:23%' type="text" placeholder="" maxlength="6" v-model="verification" />
|
||||
<view class="obtaincode" :style="{'color':getCodeBtnColor}" @click.stop="getCode()">
|
||||
{{getCodeText}}
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="loginbtn" @tap='pwdlogin'>
|
||||
确定
|
||||
</view>
|
||||
<u-toast ref="uToast" />
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
// import {
|
||||
// updatePassword
|
||||
// } from '@/api/forgotPassword/forgotPassword.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
phonenumber: '',
|
||||
password: '',
|
||||
newpassword: '',
|
||||
getCodeText: '获取验证码', //获取验证码的文字
|
||||
getCodeBtnColor: "#4C7BC9", //获取验证码的color
|
||||
timer: null,
|
||||
}
|
||||
},
|
||||
onLoad(options) {
|
||||
if (options.phonenumber) {
|
||||
this.phonenumber = options.phonenumber
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
pwdlogin() {
|
||||
var that = this
|
||||
if (this.password !== this.newpassword) {
|
||||
this.$refs.uToast.show({
|
||||
title: '密码输入不一致,请重新输入',
|
||||
type: 'error',
|
||||
duration: '1500'
|
||||
})
|
||||
} else {
|
||||
updatePassword(this.phonenumber, this.password, this.verification).then(res => {
|
||||
if (res.code == 200) {
|
||||
this.$refs.uToast.show({
|
||||
title: '密码修改成功',
|
||||
type: 'success',
|
||||
duration: '1500'
|
||||
})
|
||||
if (that.timer) {
|
||||
clearTimeout(that.timer)
|
||||
}
|
||||
that.timer = setTimeout(e => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/login/login?phonenumber=${this.phonenumber}&password=${this.password}`
|
||||
})
|
||||
}, 1500)
|
||||
} else {
|
||||
this.$refs.uToast.show({
|
||||
title: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
//点击获取验证码
|
||||
getCode() {
|
||||
uni.hideKeyboard() //隐藏已经显示的软键盘,如果软键盘没有显示则不做任何操作。
|
||||
if (this.getCodeisWaiting) { //是否在倒计时中
|
||||
return;
|
||||
}
|
||||
if (!(/^1(3|4|5|6|7|8|9)\d{9}$/.test(this.phonenumber))) { //校验手机号码是否有误
|
||||
uni.showToast({
|
||||
title: '请填写正确手机号码',
|
||||
icon: "none"
|
||||
});
|
||||
return false;
|
||||
}
|
||||
this.getCodeText = "发送中..." //发送验证码
|
||||
this.getCodeisWaiting = true;
|
||||
this.getCodeBtnColor = "rgba(138,139,133,1)" //追加样式,修改颜色
|
||||
//示例用定时器模拟请求效果
|
||||
//setTimeout(()用于在指定的毫秒数后调用函数或计算表达式
|
||||
setTimeout(() => {
|
||||
uni.showToast({
|
||||
title: '验证码已发送',
|
||||
icon: "none"
|
||||
}); //弹出提示框
|
||||
// this.code = '1234'; //发送验证码,进行填入 示例默认1234,生产中请删除这一句。
|
||||
this.setTimer(); //调用定时器方法
|
||||
}, 1000)
|
||||
},
|
||||
//获取验证码的倒计时 setTimer: 需要每隔一段时间执行一件事的的时候就需要使用SetTimer函数
|
||||
setTimer() {
|
||||
let holdTime = 60; //定义变量并赋值
|
||||
this.getCodeText = "重新获取(60)"
|
||||
//setInterval()是一个实现定时调用的函数,可按照指定的周期(以毫秒计)来调用函数或计算表达式。
|
||||
//setInterval方法会不停地调用函数,直到 clearInterval被调用或窗口被关闭。
|
||||
this.Timer = setInterval(() => {
|
||||
if (holdTime <= 0) {
|
||||
this.getCodeisWaiting = false;
|
||||
this.getCodeBtnColor = "#4C7BC9";
|
||||
this.getCodeText = "获取验证码"
|
||||
clearInterval(this.Timer); //清除该函数
|
||||
return; //返回前面
|
||||
}
|
||||
this.getCodeText = "重新获取(" + holdTime + ")"
|
||||
holdTime--;
|
||||
}, 1000)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./forgotPassword.scss";
|
||||
</style>
|
||||
89
pages/login/login.scss
Normal file
@ -0,0 +1,89 @@
|
||||
.app {
|
||||
font-family: DengXian;
|
||||
color: #C3C1C1;
|
||||
font-weight: 400;
|
||||
height:calc(100vh - 44px);
|
||||
|
||||
.switch {
|
||||
text-align: center;
|
||||
height: 100rpx;
|
||||
color: #46ABD7;
|
||||
position: absolute;
|
||||
top: 70%;
|
||||
}
|
||||
|
||||
.loginbtn {
|
||||
width: 80%;
|
||||
height: 100rpx;
|
||||
text-align: center;
|
||||
line-height: 100rpx;
|
||||
background: #4C7BC9;
|
||||
border-radius: 51rpx;
|
||||
font-size: 41rpx;
|
||||
color: #FFFFFF;
|
||||
position: absolute;
|
||||
top: 57%;
|
||||
left: 10%;
|
||||
}
|
||||
|
||||
.loginphone {
|
||||
background-color: #fff;
|
||||
width: 80%;
|
||||
height: 120rpx;
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
top: 23%;
|
||||
|
||||
input {
|
||||
font-size: 45rpx;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
::v-deep .uni-input-placeholder {
|
||||
padding-left: 40rpx;
|
||||
font-size: 41rpx;
|
||||
font-weight: 400;
|
||||
color: #C3C1C1;
|
||||
}
|
||||
|
||||
.phone {
|
||||
padding-left: 40rpx;
|
||||
height: 100%;
|
||||
box-shadow: 0px 9px 31px 9px rgba(0, 0, 0, 0.03);
|
||||
}
|
||||
}
|
||||
|
||||
.logincode {
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
|
||||
.obtaincode {
|
||||
text-align: center;
|
||||
font-size: 37rpx;
|
||||
color: #4C7BC9;
|
||||
line-height: 162rpx;
|
||||
position: absolute;
|
||||
left: 65%;
|
||||
top: 0%;
|
||||
}
|
||||
|
||||
::v-deep .u-input__input {
|
||||
padding-left: 20rpx;
|
||||
color: #000000;
|
||||
font-size: 42rpx;
|
||||
font-weight: 400;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
height: 50rpx;
|
||||
font-size: 52rpx;
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
line-height: 44rpx;
|
||||
position: absolute;
|
||||
top: 13%;
|
||||
left: 13%;
|
||||
}
|
||||
}
|
||||
116
pages/login/login.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<view class="app">
|
||||
<view class="title">
|
||||
账号登录
|
||||
</view>
|
||||
<view class="loginphone logincode">
|
||||
<u-input class="code phone" type="text" placeholder="身份证号" maxlength="18" v-model="phone" />
|
||||
</view>
|
||||
<view class="logincode loginphone" style="top: 40%;">
|
||||
<u-input class='code phone' placeholder="密码" maxlength="20" v-model="password" type="password"
|
||||
:password-icon="true" />
|
||||
</view>
|
||||
<view class="loginbtn" @tap='pwdlogin'>
|
||||
登录
|
||||
</view>
|
||||
<!-- <view class="switch" @tap='goforgotPassword' style="left:10%">
|
||||
忘记密码
|
||||
</view> -->
|
||||
<view class="switch" @tap='goregister' style="right:10%">
|
||||
没有账号,请先注册
|
||||
</view>
|
||||
<u-toast ref="uToast" />
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
info
|
||||
} from '@/api/user/index.js'
|
||||
import {
|
||||
login
|
||||
} from '../../api/login/index.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
phone: '',
|
||||
password: '',
|
||||
};
|
||||
},
|
||||
//获取到传值
|
||||
onLoad(options) {
|
||||
if (options.phone && options.password) {
|
||||
this.phone = options.phone
|
||||
this.password = options.password
|
||||
}
|
||||
},
|
||||
onShow() {
|
||||
if (uni.getStorageSync('examh5token')) {
|
||||
uni.switchTab({
|
||||
url: "/pages/examlist/examlist"
|
||||
})
|
||||
// info({
|
||||
// token: uni.getStorageSync('examh5token')
|
||||
// }).then(res => {
|
||||
// if (res.code == 0) {
|
||||
// uni.setStorageSync("examh5token", res.data.token)
|
||||
// uni.setStorageSync("examh5user", {
|
||||
// id: res.data.id,
|
||||
// phone: res.data.phone,
|
||||
// name: res.data.realName,
|
||||
// cardNo: res.data.userName
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
pwdlogin() {
|
||||
login({
|
||||
username: this.phone,
|
||||
password: this.password
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
uni.setStorageSync("examh5token", res.data.token)
|
||||
uni.setStorageSync("examh5user", {
|
||||
id: res.data.id,
|
||||
phone: res.data.phone,
|
||||
name: res.data.realName,
|
||||
cardNo: res.data.userName
|
||||
})
|
||||
this.$refs.uToast.show({
|
||||
title: "登录成功!",
|
||||
type: 'success',
|
||||
duration: '1500'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/examlist/examlist',
|
||||
})
|
||||
}, 1500);
|
||||
} else {
|
||||
this.$refs.uToast.show({
|
||||
title: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
//跳转注册页
|
||||
goregister() {
|
||||
uni.navigateTo({
|
||||
url: '/pages/register/register'
|
||||
})
|
||||
},
|
||||
//跳转忘记密码页面
|
||||
goforgotPassword() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/forgotPassword/forgotPassword?phone=${this.phone}`
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./login.scss";
|
||||
</style>
|
||||
162
pages/register/register.scss
Normal file
@ -0,0 +1,162 @@
|
||||
.app {
|
||||
height:calc(100vh - 44px);
|
||||
padding:20rpx 0;
|
||||
|
||||
.Agreement{
|
||||
width: 100%;
|
||||
background-color: #F4F5F7;
|
||||
text-align: center;
|
||||
height: 1000rpx;
|
||||
position: absolute;
|
||||
top:5%;
|
||||
font-size: 30rpx;
|
||||
.title{
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
border-bottom: 1px solid #eeeeee;
|
||||
font-size: 34rpx;
|
||||
margin: 0px auto;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
.scroll-Y{
|
||||
height:830rpx ;
|
||||
overflow-y:scroll;
|
||||
text-align: left;
|
||||
text-indent: 2em;
|
||||
}
|
||||
.cancel {
|
||||
height:70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: 32rpx;
|
||||
background-color: #F4F5F7;
|
||||
position: absolute;
|
||||
border-top: 1rpx solid #000000;
|
||||
bottom:0;
|
||||
right:0;
|
||||
width: 50%;
|
||||
color: #000000;
|
||||
}
|
||||
.determine {
|
||||
height:70rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: 32rpx;
|
||||
width: 50%;
|
||||
color: #F4F5F7;
|
||||
background: #4C7BC9;
|
||||
position: absolute;
|
||||
bottom:0;
|
||||
left:0;
|
||||
}
|
||||
}
|
||||
.item{
|
||||
font-size: 34rpx;
|
||||
margin: 0 auto 20rpx;
|
||||
width: 94%;
|
||||
height:100rpx;
|
||||
line-height: 100rpx;
|
||||
background-color: #fff;
|
||||
box-shadow: 0px 9rpx 31rpx 9rpx rgba(0,0,0,0.03);
|
||||
border-radius: 20rpx;
|
||||
position: relative;
|
||||
.lefttext{
|
||||
position: absolute;
|
||||
top:50%;
|
||||
transform: translateY(-50%);
|
||||
left:3%;
|
||||
}
|
||||
.righttext{
|
||||
position: absolute;
|
||||
top:50%;
|
||||
transform: translateY(-50%);
|
||||
width: 68%;
|
||||
left:18%;
|
||||
height:100rpx;
|
||||
}
|
||||
.lefttext,.righttext{
|
||||
::v-deep .uni-input-input{
|
||||
font-size: 34rpx;
|
||||
}
|
||||
::v-deep .uni-input-wrapper{
|
||||
height:100rpx;
|
||||
line-height: 100rpx;
|
||||
}
|
||||
::v-deep .uni-input-placeholder {
|
||||
line-height: 100rpx;
|
||||
font-size: 34rpx;
|
||||
font-weight: 400;
|
||||
color: #C3C1C1;
|
||||
}
|
||||
}
|
||||
.obtaincode {
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
color: #4C7BC9;
|
||||
line-height: 100rpx;
|
||||
position: absolute;
|
||||
right:5%;
|
||||
top: 0%;
|
||||
}
|
||||
}
|
||||
.radio-content {
|
||||
margin: 50rpx auto;
|
||||
width: 70%;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
position: relative;
|
||||
.agreement {
|
||||
position: absolute;
|
||||
top:50%;
|
||||
left:20%;
|
||||
transform: translateY(-50%);
|
||||
color: #878987;
|
||||
}
|
||||
.radio-right {
|
||||
height: 100rpx;
|
||||
|
||||
.radio {
|
||||
display: inline-block;
|
||||
width: 35rpx;
|
||||
height: 35rpx;
|
||||
border-radius: 70%;
|
||||
border: 2rpx solid #178ffb;
|
||||
position: absolute;
|
||||
top:50%;
|
||||
left:5%;
|
||||
transform: translateY(-50%);
|
||||
.radio-active {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
background-color: #178ffb;
|
||||
position: absolute;
|
||||
top:50%;
|
||||
left:50%;
|
||||
transform: translate(-50%,-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.switch {
|
||||
text-align: center;
|
||||
line-height: 60rpx;
|
||||
color: #46ABD7;
|
||||
position: absolute;
|
||||
top: 73%;
|
||||
}
|
||||
|
||||
.loginbtn {
|
||||
width: 70%;
|
||||
height: 100rpx;
|
||||
text-align: center;
|
||||
line-height: 100rpx;
|
||||
background: #4C7BC9;
|
||||
border-radius: 51rpx;
|
||||
font-size: 41rpx;
|
||||
color: #FFFFFF;
|
||||
position: absolute;
|
||||
top: 62%;
|
||||
left: 15%;
|
||||
}
|
||||
|
||||
}
|
||||
247
pages/register/register.vue
Normal file
@ -0,0 +1,247 @@
|
||||
<template>
|
||||
<view class="app">
|
||||
<view class="item">
|
||||
<view class="lefttext">
|
||||
姓名
|
||||
</view>
|
||||
<u-input class="righttext" style="width: 80%;" type="text" placeholder="请输入" maxlength="10"
|
||||
v-model="realName" />
|
||||
</view>
|
||||
<view class="item">
|
||||
<view class="lefttext">
|
||||
身份证号
|
||||
</view>
|
||||
<u-input class="righttext" style='left:30%' type="text" placeholder="请输入" maxlength="18"
|
||||
v-model="patientName" />
|
||||
</view>
|
||||
<view class="item">
|
||||
<view class="lefttext">
|
||||
手机号
|
||||
</view>
|
||||
<u-input class="righttext" style='left:23%;width: 77%;' type="text" placeholder="请输入" maxlength="11"
|
||||
v-model="phone" />
|
||||
</view>
|
||||
<view class="item">
|
||||
<view class="lefttext">
|
||||
输入密码
|
||||
</view>
|
||||
<u-input class='righttext' style='left:30%' placeholder="请输入密码" maxlength="20" v-model="password"
|
||||
type="password" :border="false" :password-icon="true" />
|
||||
</view>
|
||||
<view class="item">
|
||||
<view class="lefttext">
|
||||
重复密码
|
||||
</view>
|
||||
<u-input class='righttext' style='left:30%' placeholder="请再次输入密码" maxlength="20" v-model="newpassword"
|
||||
type="password" :border="false" :password-icon="true" />
|
||||
</view>
|
||||
<!-- <view class="item">
|
||||
<view class="lefttext">
|
||||
验证码
|
||||
</view>
|
||||
<input class="righttext" style='left:23%' type="text" placeholder="" maxlength="6" v-model="verification" />
|
||||
<view class="obtaincode" :style="{'color':getCodeBtnColor}" @click.stop="getCode()">
|
||||
{{getCodeText}}
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="loginbtn" @tap='register'>
|
||||
注册
|
||||
</view>
|
||||
<view class="switch" style="right:5%" @tap='gologin'>
|
||||
已有账号,去登录
|
||||
</view>
|
||||
<u-toast ref="uToast" />
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
reg
|
||||
} from '@/api/register/index.js'
|
||||
export default {
|
||||
components: {},
|
||||
data() {
|
||||
return {
|
||||
patientName: '',
|
||||
realName: "",
|
||||
phone: '',
|
||||
password: '',
|
||||
newpassword: '',
|
||||
verification: '',
|
||||
getCodeText: '获取验证码', //获取验证码的文字
|
||||
getCodeBtnColor: "#4C7BC9", //获取验证码的color
|
||||
getCodeisWaiting: false, //判断是否在倒计时中
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
//注册功能
|
||||
register() {
|
||||
if (this.password !== this.newpassword) {
|
||||
this.$refs.uToast.show({
|
||||
title: '密码输入不一致,请重新输入',
|
||||
type: 'error',
|
||||
duration: '1500'
|
||||
})
|
||||
} else {
|
||||
reg({
|
||||
password: this.password,
|
||||
realName: this.realName,
|
||||
userName: this.patientName,
|
||||
phone: this.phone
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
uni.setStorageSync("examh5token", res.data.token)
|
||||
uni.setStorageSync("examh5user", {
|
||||
id: res.data.id,
|
||||
phone: res.data.phone,
|
||||
name: res.data.realName,
|
||||
cardNo: res.data.userName
|
||||
})
|
||||
this.$refs.uToast.show({
|
||||
title: '注册成功,前往登录',
|
||||
type: 'success',
|
||||
duration: '1500'
|
||||
})
|
||||
setTimeout(e => {
|
||||
uni.reLaunch({
|
||||
url: `/pages/login/login?phone=${this.patientName}&password=${this.password}`
|
||||
})
|
||||
}, 1500)
|
||||
} else {
|
||||
this.$refs.uToast.show({
|
||||
title: res.msg,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
//跳转登录页
|
||||
gologin() {
|
||||
uni.reLaunch({
|
||||
url: `/pages/login/login`
|
||||
})
|
||||
},
|
||||
//点击获取验证码
|
||||
getCode() {
|
||||
uni.hideKeyboard() //隐藏已经显示的软键盘,如果软键盘没有显示则不做任何操作。
|
||||
if (this.getCodeisWaiting) { //是否在倒计时中
|
||||
return;
|
||||
}
|
||||
if (!(/^1(3|4|5|6|7|8|9)\d{9}$/.test(this.phone))) { //校验手机号码是否有误
|
||||
uni.showToast({
|
||||
title: '请填写正确手机号码',
|
||||
icon: "none"
|
||||
});
|
||||
return false;
|
||||
}
|
||||
this.getCodeText = "发送中..." //发送验证码
|
||||
this.getCodeisWaiting = true;
|
||||
this.getCodeBtnColor = "rgba(138,139,133,1)" //追加样式,修改颜色
|
||||
//示例用定时器模拟请求效果
|
||||
//setTimeout(()用于在指定的毫秒数后调用函数或计算表达式
|
||||
setTimeout(() => {
|
||||
uni.showToast({
|
||||
title: '验证码已发送',
|
||||
icon: "none"
|
||||
}); //弹出提示框
|
||||
// this.code = '1234'; //发送验证码,进行填入 示例默认1234,生产中请删除这一句。
|
||||
this.setTimer(); //调用定时器方法
|
||||
}, 1000)
|
||||
},
|
||||
//获取验证码的倒计时 setTimer: 需要每隔一段时间执行一件事的的时候就需要使用SetTimer函数
|
||||
setTimer() {
|
||||
let holdTime = 60; //定义变量并赋值
|
||||
this.getCodeText = "重新获取(60)"
|
||||
//setInterval()是一个实现定时调用的函数,可按照指定的周期(以毫秒计)来调用函数或计算表达式。
|
||||
//setInterval方法会不停地调用函数,直到 clearInterval被调用或窗口被关闭。
|
||||
this.Timer = setInterval(() => {
|
||||
if (holdTime <= 0) {
|
||||
this.getCodeisWaiting = false;
|
||||
this.getCodeBtnColor = "#4C7BC9";
|
||||
this.getCodeText = "获取验证码"
|
||||
clearInterval(this.Timer); //清除该函数
|
||||
return; //返回前面
|
||||
}
|
||||
this.getCodeText = "重新获取(" + holdTime + ")"
|
||||
holdTime--;
|
||||
}, 1000)
|
||||
},
|
||||
doReg() {
|
||||
// uni.hideKeyboard() //隐藏已经显示的软键盘,如果软键盘没有显示则不做任何操作。
|
||||
// //模板示例部分验证规则
|
||||
// if (!(/^1(3|4|5|6|7|8|9)\d{9}$/.test(this.phoneNumber))) { //校验手机号码
|
||||
// uni.showToast({
|
||||
// title: '请填写正确手机号码',
|
||||
// icon: "none"
|
||||
// });
|
||||
// return false;
|
||||
// }
|
||||
// //示例验证码,实际使用中应为请求服务器比对验证码是否正确。
|
||||
// if (this.code != 1234) {
|
||||
// uni.showToast({
|
||||
// title: '验证码不正确',
|
||||
// icon: "none"
|
||||
// });
|
||||
// return false;
|
||||
// }
|
||||
// uni.showLoading({
|
||||
// title: '提交中...'
|
||||
// })
|
||||
// //模板示例把用户注册信息储存在本地,实际使用中请替换为上传服务器。
|
||||
// setTimeout(() => {
|
||||
// uni.getStorage({
|
||||
// key: 'UserList',
|
||||
// success: (res) => {
|
||||
// //增加记录,密码md5
|
||||
// res.data.push({
|
||||
// username: this.phoneNumber,
|
||||
// passwd: md5(this.passwd)
|
||||
// })
|
||||
// uni.setStorage({
|
||||
// key: 'UserList',
|
||||
// data: res.data,
|
||||
// success: function() {
|
||||
// uni.hideLoading()
|
||||
// uni.showToast({
|
||||
// title: '注册成功',
|
||||
// icon: "success"
|
||||
// });
|
||||
// setTimeout(function() {
|
||||
// uni.navigateBack();
|
||||
// }, 1000)
|
||||
// }
|
||||
// });
|
||||
// },
|
||||
// fail: (e) => {
|
||||
// uni.hideLoading()
|
||||
// //新建UserList
|
||||
// uni.setStorage({
|
||||
// key: 'UserList',
|
||||
// data: [{
|
||||
// username: this.phoneNumber,
|
||||
// passwd: md5(this.passwd)
|
||||
// }],
|
||||
// success: function() {
|
||||
// uni.hideLoading()
|
||||
// uni.showToast({
|
||||
// title: '注册成功',
|
||||
// icon: "success"
|
||||
// });
|
||||
// setTimeout(function() {
|
||||
// uni.navigateBack();
|
||||
// }, 1000)
|
||||
// },
|
||||
// fail: function(e) {
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// });
|
||||
// }, 1000)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import "./register.scss";
|
||||
</style>
|
||||
240
pages/user/user.vue
Normal file
@ -0,0 +1,240 @@
|
||||
<template>
|
||||
<view class="app">
|
||||
<image class="circular" src="../../static/homepage.png" mode=""></image>
|
||||
<view class="user" v-if="Personallist">
|
||||
<image class="img" src="../../static/user2.png" mode=""></image>
|
||||
<view class="phone" v-if="Personallist.realName">
|
||||
{{Personallist.realName}}
|
||||
</view>
|
||||
<view class="nickname" v-if="Personallist.userName">
|
||||
{{Personallist.userName}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="user" v-else>
|
||||
<image class="img" src="../../static/user2.png" mode=""></image>
|
||||
<view class="login" @tap='gologin'>
|
||||
登录
|
||||
</view>
|
||||
</view>
|
||||
<view class="bottomitems">
|
||||
<view class="bottomitem" @tap='goremove'>
|
||||
<image src="../../static/shezhi.png" mode=""></image>
|
||||
<view class="">
|
||||
退出账号
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<u-toast ref="uToast" />
|
||||
</view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
info
|
||||
} from '@/api/user/index.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
Personallist: undefined,
|
||||
}
|
||||
},
|
||||
onLoad() {
|
||||
if (uni.getStorageSync('examh5token')) {
|
||||
this.myInfo()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
myInfo() {
|
||||
info({
|
||||
token: uni.getStorageSync('examh5token')
|
||||
}).then(res => {
|
||||
if (res.code == 0) {
|
||||
uni.setStorageSync("examh5token", res.data.token)
|
||||
uni.setStorageSync("examh5user", {
|
||||
id: res.data.id,
|
||||
phone: res.data.phone,
|
||||
name: res.data.realName,
|
||||
cardNo: res.data.userName
|
||||
})
|
||||
this.Personallist = res.data
|
||||
}
|
||||
})
|
||||
},
|
||||
//跳登录
|
||||
gologin() {
|
||||
uni.reLaunch({
|
||||
url: '/pages/login/login'
|
||||
})
|
||||
},
|
||||
//退出账号
|
||||
goremove() {
|
||||
let that = this
|
||||
const value = uni.getStorageSync('examh5token');
|
||||
if (value) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确认要退出此账号吗',
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
uni.clearStorageSync();
|
||||
that.Personallist = undefined
|
||||
that.$refs.uToast.show({
|
||||
title: '退出账号成功!',
|
||||
type: 'success',
|
||||
duration: '1000'
|
||||
})
|
||||
if (that.timer) {
|
||||
clearTimeout(that.timer)
|
||||
}
|
||||
that.timer = setTimeout(e => {
|
||||
that.gologin();
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
that.$refs.uToast.show({
|
||||
title: '您未登录',
|
||||
type: 'error',
|
||||
duration: '1000'
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
page {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.app {
|
||||
padding: 0;
|
||||
font-size: 32rpx;
|
||||
height: calc(100vh - 100rpx);
|
||||
|
||||
.bottomitems {
|
||||
position: absolute;
|
||||
bottom: 50rpx;
|
||||
width: 100%;
|
||||
|
||||
.bottomitem {
|
||||
width: 85%;
|
||||
margin: 0 auto;
|
||||
height: 120rpx;
|
||||
position: relative;
|
||||
border-bottom: 1rpx solid #F3F3F3;
|
||||
|
||||
view {
|
||||
display: inline-block;
|
||||
font-size: 35rpx;
|
||||
color: #333333;
|
||||
line-height: 120rpx;
|
||||
margin-left: 80rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: inline-block;
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.topitems {
|
||||
z-index: 999;
|
||||
padding: 45rpx 0 35rpx;
|
||||
width: 94%;
|
||||
margin: 0 auto;
|
||||
display: flex;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 3rpx 18rpx 0rpx rgba(79, 108, 254, 0.43);
|
||||
border-radius: 5rpx;
|
||||
justify-content: space-around;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
|
||||
.topitem {
|
||||
view {
|
||||
font-size: 32rpx;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
width: 100%;
|
||||
height: 500rpx;
|
||||
position: relative;
|
||||
color: #FFFFFF;
|
||||
font-size: 38rpx;
|
||||
z-index: 999;
|
||||
|
||||
.modify {
|
||||
position: absolute;
|
||||
right: 3%;
|
||||
top: 250rpx;
|
||||
font-size: 28rpx;
|
||||
|
||||
image {
|
||||
width: 23rpx;
|
||||
height: 23rpx;
|
||||
padding-left: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.login {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
top: 220rpx;
|
||||
left: 35%;
|
||||
font-size: 36rpx;
|
||||
width: 180rpx;
|
||||
line-height: 70rpx;
|
||||
border: 1rpx solid #fff;
|
||||
height: 70rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.nickname {
|
||||
position: absolute;
|
||||
top: 260rpx;
|
||||
left: 35%;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.phone {
|
||||
position: absolute;
|
||||
top: 180rpx;
|
||||
left: 35%;
|
||||
}
|
||||
|
||||
.img {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 50%;
|
||||
background: #F6F6F6;
|
||||
position: absolute;
|
||||
top: 170rpx;
|
||||
left: 8%;
|
||||
// border: 4rpx solid #6DD8FC;
|
||||
}
|
||||
}
|
||||
|
||||
.circular {
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
height: 500rpx;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
BIN
static/autograph.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
static/homepage.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
BIN
static/homepagew.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
static/homepagews.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
static/jinbi.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
static/shezhi.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
static/user2.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
static/users.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
static/userw.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
13
uni.promisify.adaptor.js
Normal file
@ -0,0 +1,13 @@
|
||||
uni.addInterceptor({
|
||||
returnValue (res) {
|
||||
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) {
|
||||
return res;
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
res.then((res) => {
|
||||
if (!res) return resolve(res)
|
||||
return res[0] ? reject(res[0]) : resolve(res[1])
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
77
uni.scss
Normal file
@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 这里是uni-app内置的常用样式变量
|
||||
*
|
||||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
|
||||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
|
||||
*
|
||||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
|
||||
*/
|
||||
/* uni.scss */
|
||||
@import 'uview-ui/theme.scss';
|
||||
/* 颜色变量 */
|
||||
|
||||
/* 行为相关颜色 */
|
||||
$uni-color-primary: #007aff;
|
||||
$uni-color-success: #4cd964;
|
||||
$uni-color-warning: #f0ad4e;
|
||||
$uni-color-error: #dd524d;
|
||||
|
||||
/* 文字基本颜色 */
|
||||
$uni-text-color:#333;//基本色
|
||||
$uni-text-color-inverse:#fff;//反色
|
||||
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
|
||||
$uni-text-color-placeholder: #808080;
|
||||
$uni-text-color-disable:#c0c0c0;
|
||||
|
||||
/* 背景颜色 */
|
||||
$uni-bg-color:#ffffff;
|
||||
$uni-bg-color-grey:#f8f8f8;
|
||||
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
|
||||
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
|
||||
|
||||
/* 边框颜色 */
|
||||
$uni-border-color:#c8c7cc;
|
||||
|
||||
/* 尺寸变量 */
|
||||
|
||||
/* 文字尺寸 */
|
||||
$uni-font-size-sm:12px;
|
||||
$uni-font-size-base:14px;
|
||||
$uni-font-size-lg:16px;
|
||||
|
||||
/* 图片尺寸 */
|
||||
$uni-img-size-sm:20px;
|
||||
$uni-img-size-base:26px;
|
||||
$uni-img-size-lg:40px;
|
||||
|
||||
/* Border Radius */
|
||||
$uni-border-radius-sm: 2px;
|
||||
$uni-border-radius-base: 3px;
|
||||
$uni-border-radius-lg: 6px;
|
||||
$uni-border-radius-circle: 50%;
|
||||
|
||||
/* 水平间距 */
|
||||
$uni-spacing-row-sm: 5px;
|
||||
$uni-spacing-row-base: 10px;
|
||||
$uni-spacing-row-lg: 15px;
|
||||
|
||||
/* 垂直间距 */
|
||||
$uni-spacing-col-sm: 4px;
|
||||
$uni-spacing-col-base: 8px;
|
||||
$uni-spacing-col-lg: 12px;
|
||||
|
||||
/* 透明度 */
|
||||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
|
||||
|
||||
/* 文章场景相关 */
|
||||
$uni-color-title: #2C405A; // 文章标题颜色
|
||||
$uni-font-size-title:20px;
|
||||
$uni-color-subtitle: #555555; // 二级标题颜色
|
||||
$uni-font-size-subtitle:26px;
|
||||
$uni-color-paragraph: #3F536E; // 文章段落颜色
|
||||
$uni-font-size-paragraph:15px;
|
||||