初次提交

This commit is contained in:
曹辉 2023-03-28 10:02:47 +08:00
commit ba2249188b
70 changed files with 4104 additions and 0 deletions

63
App.vue Normal file
View File

@ -0,0 +1,63 @@
<script>
export default {
onLaunch: function() {},
onShow: function() {},
onHide: function() {}
}
</script>
<style lang="scss">
/*每个页面公共css */
@import "uview-ui/index.scss";
page {
background-color: #F4F5F7;
}
.app {
width: 100%;
height: 100%;
color: #000000;
padding: 30rpx 0 150rpx 0;
.cards {
width: 94%;
margin: 0 auto;
box-shadow: 0px 0px 30rpx 0px rgba(108, 99, 255, 0.16);
background-color: #fff;
display: flex;
justify-content: space-evenly;
flex-wrap: wrap;
padding: 40rpx 0 200rpx 0;
border-radius: 25rpx;
.item {
width: 43%;
height: 300rpx;
margin-bottom: 40rpx;
border-radius: 25rpx;
position: relative;
.title {
width: 70%;
text-align: center;
font-size: 46rpx;
color: #FCFCFC;
position: absolute;
top: 58%;
left: 50%;
transform: translateX(-50%);
}
image {
width: 100rpx;
height: 100rpx;
position: absolute;
top: 20%;
left: 50%;
transform: translateX(-50%);
}
}
}
}
</style>

View File

@ -0,0 +1,22 @@
import request from "../request.js"
export function userPassWord(data) {
return request({
url: `/nurseApp/personLogin/userPassWord`,
method: 'POST',
data,
})
}
export function updateHeadAvatarHead(userId, File) {
return request({
url: `/nurseApp/personLogin/updateHeadAvatarHead?userId=${userId}&File=${File}`,
method: 'POST',
data,
})
}
export function nursePerson(phonenumber, password) {
return request({
url: `/nurseApp/personLogin/nursePerson?phonenumber=${phonenumber}&stationPersonPassword=${password}`,
method: 'GET'
})
}

9
api/Mymission.js Normal file
View File

@ -0,0 +1,9 @@
import request from "./request.js"
export function selectMission(nursePersonId, orderStatus, pageNum, pageSize,nurseItemName) {
return request({
url: `/nurseApp/personLogin/selectMission?nursePersonId=${nursePersonId}&orderStatus=${orderStatus}&pageNum=${pageNum}&pageSize=${pageSize}&nurseItemName=${nurseItemName}`,
method: 'GET'
})
}

6
api/baseurl.js Normal file
View File

@ -0,0 +1,6 @@
// var baseurl = "https://quanyidaojia.xinelu.cn";
var baseurl = "http://192.168.16.49:8080";
export default baseurl

View File

@ -0,0 +1,9 @@
import request from "../request.js"
export function orderConfirm(data) {
return request({
url: `/nurseApp/personLogin/orderConfirm`,
method: 'POST',
data
})
}

View File

@ -0,0 +1,9 @@
import request from "../request.js"
export function updatePassword(phonenumber, password) {
return request({
url: `/nurseApp/personLogin/updatePassword?phonenumber=${phonenumber}&stationPersonPassword=${password}`,
method: 'POST'
})
}

16
api/login/index.js Normal file
View File

@ -0,0 +1,16 @@
import request from "../request.js"
//密码
export function appLogin(phonenumber, stationPersonPassword) {
return request({
url: `/nurseApp/personLogin/appLogin?phonenumber=${phonenumber}&stationPersonPassword=${stationPersonPassword}`,
method: 'POST'
})
}
export function createMobileToken() {
return request({
url: `/nurseApplet/authorization/createMobileToken`,
method: 'GET'
})
}

View File

@ -0,0 +1,7 @@
import request from "../request.js"
export function nursePerson(phonenumber,password) {
return request({
url: `/nurseApp/personLogin/nursePerson?phonenumber=${phonenumber}&stationPersonPassword=${password}`,
method: 'GET'
})
}

16
api/register/index.js Normal file
View File

@ -0,0 +1,16 @@
import request from "../request.js"
export function nurseAppLoginSysUser(data) {
return request({
url: `/nurseApp/personLogin/nurseAppLoginSysUser`,
method: 'POST',
data,
})
}
export function personNurseStationLists(pageNum,pageSize) {
return request({
url: `/nurseApp/personLogin/personNurseStationLists?pageNum=${pageNum}&pageSize=${pageSize}`,
method: 'get'
})
}

54
api/request.js Normal file
View File

@ -0,0 +1,54 @@
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: {
Authorization: 'Bearer' + ' ' + uni.getStorageSync('token')
},
success(res) {
if (res.data.code == 9999) {
uni.removeStorageSync('token');
// uni.reLaunch({
// url: '/pages/login/login'
// })
uni.showModal({
title: "登录提示",
content: '登录失效,请重新登录',
success(res1) {
if (res1.confirm) {
uni.navigateTo({
url: '/pages/login/login'
})
} else if (res1.cancel) {
uni.reLaunch({
url: '/pages/homepage/homepage'
})
}
},
fail(err1) {
uni.reLaunch({
url: '/pages/homepage/homepage'
})
}
})
}
uni.hideLoading();
resolve(res.data)
},
fail(err) {
uni.hideLoading();
rejected(err)
}
})
})
}
export default request

9
api/startup.js Normal file
View File

@ -0,0 +1,9 @@
import request from "./request.js"
export function appFileInfoByOneId() {
return request({
url: `/nurseApplet/uploadFile/appFileInfoByOneId`,
method: 'GET'
})
}

11
api/taskDetails.js Normal file
View File

@ -0,0 +1,11 @@
import request from "./request.js"
// 任务详情
export function taskDetails(orderDetailsId) {
return request({
url: `/nurseApp/personLogin/taskDetails?&orderDetailsId=${orderDetailsId}`,
method: 'GET'
})
}

9
api/taskReturn/index.js Normal file
View File

@ -0,0 +1,9 @@
import request from "../request.js"
export function orderFallback(orderNo, taskReturnReason) {
return request({
url: `/nurseApp/personLogin/orderFallback?orderNo=${orderNo}&taskReturnReason=${taskReturnReason}`,
method: 'POST'
})
}

View 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
}

View 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>

View 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>

View 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 + *x2
* y = (1-t)²*y0 + 2t(1-t)*y1 + *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>

20
index.html Normal file
View 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>

23
main.js Normal file
View File

@ -0,0 +1,23 @@
import App from './App'
// #ifndef VUE3
import Vue from 'vue'
import uView from "uview-ui";
Vue.use(uView);
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

128
manifest.json Normal file
View File

@ -0,0 +1,128 @@
{
"name" : "泉医到家护理员",
"appid" : "__UNI__9FA8ADB",
"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" : {
"Geolocation" : {},
"Maps" : {},
"Camera" : {}
},
/* */
"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" : {
"dSYMs" : false
},
/* SDK */
"sdkConfigs" : {
"ad" : {},
"geolocation" : {
"amap" : {
"__platform__" : [ "ios", "android" ],
"appkey_ios" : "fa38860a5159a551b6819ea3092a68f3",
"appkey_android" : "fa38860a5159a551b6819ea3092a68f3"
}
},
"maps" : {
"amap" : {
"appkey_ios" : "fa38860a5159a551b6819ea3092a68f3",
"appkey_android" : "fa38860a5159a551b6819ea3092a68f3"
}
}
},
"icons" : {
"android" : {
"hdpi" : "",
"xhdpi" : "",
"xxhdpi" : "",
"xxxhdpi" : ""
},
"ios" : {
"appstore" : "",
"ipad" : {
"app" : "",
"app@2x" : "",
"notification" : "",
"notification@2x" : "",
"proapp@2x" : "",
"settings" : "",
"settings@2x" : "",
"spotlight" : "",
"spotlight@2x" : ""
},
"iphone" : {
"app@2x" : "",
"app@3x" : "",
"notification@2x" : "",
"notification@3x" : "",
"settings@2x" : "",
"settings@3x" : "",
"spotlight@2x" : "",
"spotlight@3x" : ""
}
}
}
}
},
/* */
"quickapp" : {},
/* */
"mp-weixin" : {
"appid" : "",
"setting" : {
"urlCheck" : false
},
"usingComponents" : true,
"permission" : {}
},
"mp-alipay" : {
"usingComponents" : true
},
"mp-baidu" : {
"usingComponents" : true
},
"mp-toutiao" : {
"usingComponents" : true
},
"uniStatistics" : {
"enable" : false
},
"vueVersion" : "2",
"locale" : "zh-Hans",
"fallbackLocale" : "zh-Hans"
}

27
package-lock.json generated Normal file
View File

@ -0,0 +1,27 @@
{
"name": "签名组件-兼容H5、小程序、APP",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "签名组件-兼容H5、小程序、APP",
"version": "1.0.0",
"dependencies": {
"uview-ui": "^1.8.4"
}
},
"node_modules/uview-ui": {
"version": "1.8.4",
"resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.8.4.tgz",
"integrity": "sha512-Zr+D5dFdNy6CdHQLBEXeGq/w0LkjxzBtsgaaDwLl0P58g67H7fBBDvy6AzWK/k0c7dwPYMBiK7I4Tr9p92+0DA=="
}
},
"dependencies": {
"uview-ui": {
"version": "1.8.4",
"resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.8.4.tgz",
"integrity": "sha512-Zr+D5dFdNy6CdHQLBEXeGq/w0LkjxzBtsgaaDwLl0P58g67H7fBBDvy6AzWK/k0c7dwPYMBiK7I4Tr9p92+0DA=="
}
}
}

12
package.json Normal file
View File

@ -0,0 +1,12 @@
{
"id": "sin-signature",
"name": "签名组件-兼容H5、小程序、APP",
"version": "1.0.0",
"description": "用于uni-app的签名组件支持H5、小程序、APP可导出svg矢量图片。",
"keywords": [
"签名,签字,svg,canvas"
],
"dependencies": {
"uview-ui": "^1.8.4"
}
}

123
pages.json Normal file
View File

@ -0,0 +1,123 @@
{
"easycom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
},
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/startup/startup",
"style": {
"navigationBarTitleText": "启动页",
"navigationStyle": "custom"
}
}, {
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录",
"navigationBarBackgroundColor": "#ffffff", //
"navigationStyle": "custom"
}
},
{
"path": "pages/confirmCompletion/confirmCompletion",
"style": {
"navigationBarTitleText": "完成确认",
"navigationBarBackgroundColor": "#ffffff" //
}
}, {
"path": "pages/personal/personal",
"style": {
"navigationBarTitleText": "个人信息",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#4C7BC9",
"navigationBarTextStyle": "white"
}
}, {
"path": "pages/forgotPassword/forgotPassword",
"style": {
"navigationBarTitleText": "忘记密码",
"navigationBarBackgroundColor": "#ffffff" //
}
}, {
"path": "pages/register/register",
"style": {
"navigationBarTitleText": "注册账号",
"navigationBarBackgroundColor": "#ffffff" //
}
}, {
"path": "pages/homepage/homepage",
"style": {
"navigationBarTitleText": "",
"navigationBarBackgroundColor": "#ffffff", //
"navigationStyle": "custom"
}
},
{
"path": "pages/taskReturn/taskReturn",
"style": {
"navigationBarTitleText": "任务退回",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#ffffff" //
}
}, {
"path": "pages/Mymission/Mymission",
"style": {
"navigationBarTitleText": "我的任务",
"navigationBarBackgroundColor": "#ffffff", //
"onReachBottomDistance": 20, // px
"enablePullDownRefresh": true //true
}
}, {
"path": "pages/taskDetails/taskDetails",
"style": {
"navigationBarTitleText": "任务详情",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#ffffff" //
}
},
{
"path": "pages/Modifyinformation/Modifyinformation",
"style": {
"navigationBarTitleText": "修改信息",
"enablePullDownRefresh": false,
"navigationBarBackgroundColor": "#ffffff" //
// "navigationBarTextStyle": "white"
}
}, {
"path": "pages/signature/signature",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {},
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#435950",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/homepage/homepage",
"iconPath": "static/homepagew.png",
"selectedIconPath": "static/homepagews.png",
"text": "首页"
},
{
"pagePath": "pages/personal/personal",
"iconPath": "static/userw.png",
"selectedIconPath": "static/users.png",
"text": "我的"
}
]
}
}

View File

@ -0,0 +1,96 @@
.app {
background-color: #F4F5F7;
width: 100%;
height: 100vh;
color: #000000;
padding: 3%;
font-size: 34rpx;
.title{
font-size: 28rpx;
margin: 20rpx 20rpx 0;
}
.finish {
width: 217rpx;
color: #FFFFFF;
height: 68rpx;
line-height: 68rpx;
text-align: center;
position: absolute;
top: 70%;
left: 70%;
background: #4C7BC9;
border-radius: 26rpx;
}
.centercontent {
width: 99%;
background: #FFFFFF;
box-shadow: 0rpx 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20rpx;
margin: 0 auto;
padding-bottom: 10rpx;
.content {
line-height: 100rpx;
.name {
margin-left: 20rpx;
height: 100rpx;
line-height: 100rpx;
border-bottom: 1rpx solid #D8D4D4;
position: relative;
span {
display: inline-block;
width: 20%;
}
input {
position: absolute;
top: 50%;
transform: translateY(-50%);
line-height: 100rpx;
display: inline-block;
width: 80%;
font-size: 34rpx;
}
}
.nursetype {
padding-bottom: 20rpx;
border: none;line-height: 50rpx;margin: 20rpx 20rpx;
}
}
.Commodity {
line-height: 130rpx;
margin-left: 20rpx;
border-bottom: 1rpx solid #D8D4D4;
position: relative;
.picture {
position: absolute;
right: 10%;
top: 50%;
transform: translateY(-50%);
width: 110rpx;
height: 110rpx;
border-radius: 50%;
}
.pictureA {
position: absolute;
right: 2%;
top: 50%;
transform: translateY(-50%);
width: 18rpx;
height: 27rpx;
}
.head {
line-height: 140rpx;
margin-left: 5%;
display: inline-block;
}
}
}
}

View File

@ -0,0 +1,196 @@
<template>
<view class="app">
<view class="centercontent">
<view class="Commodity" @tap="uploadImag()">
头像
<image class="picture" :src="img" mode=""></image>
<image class="pictureA" src="../../static/jiantou.png" mode=""></image>
</view>
<view class="content">
<view class="name">
<span>姓名:</span>
<input type="text" maxlength="10" placeholder="请输入" v-model="appPersonallist.nickName" />
</view>
<view class="name">
<span class="">
账号
</span>
<input type="text" disabled maxlength="10" placeholder="请填写" v-model="appPersonallist.userName" />
</view>
<view class="name">
<span>电话</span>
<input disabled type="text" maxlength="11" placeholder="请输入"
v-model="appPersonallist.phonenumber" />
</view>
<view class="nursetype " style="">
护理站
<text v-for='(uitem,index) in appPersonallist.nurseStationSysUserVOList'> {{uitem.nurseStationName}}
<text v-if="index!=appPersonallist.nurseStationSysUserVOList.length-1"></text>
</text>
<!-- {{getNurseStationName(appPersonallist)}} -->
</view>
</view>
</view>
<view class="title">
:只可修改姓名和头像
</view>
<view class="finish" @tap="gofinish()">完成
</view>
<u-select v-model="show" mode="single-column" :list="NurseStationList" @confirm="confirm"></u-select>
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
personNurseStationLists
} from '@/api/register/index.js'
import {
userPassWord,
nursePerson
} from '@/api/Modifyinformation/Modifyinformation.js';
import baseurl from '@/api/baseurl.js'
export default {
data() {
return {
show: false,
baseurl: '', //url
img: null,
image: null,
NurseStationList: [], //list
appPersonallist: {
userId: '',
userName: '',
nickName: '',
phonenumber: '',
avatar: '',
File: '',
},
timer: null,
}
},
computed: {
// getNurseStationName() {
// return data => data?.nurseStationSysUserVOList?. [0]?.nurseStationName || ''
// },
},
onShow() {
this.info();
this.baseurl = baseurl;
},
onLoad(options) {
let that = this
try {
const value = uni.getStorageSync('phonenumber');
const value2 = uni.getStorageSync('password');
if (value && value2) {
that.phonenumber = value
that.password = value2
that.myInfo()
}
} catch (e) {}
},
methods: {
//
uploadImag() {
var that = this;
uni.chooseImage({
count: 1,
sourceType: ['album'],
success(res) {
that.appPersonallist.avatar = res.tempFilePaths[0]
that.img = res.tempFilePaths[0]
that.image = true
}
})
},
myInfo() {
nursePerson(this.phonenumber, this.password).then(res => {
this.img = baseurl + res.data.avatar
this.appPersonallist = res.data
})
},
gofinish() {
var that = this
if (this.image) {
uni.uploadFile({
url: baseurl + '/nurseApp/personLogin/updateHeadAvatarHead',
filePath: that.img, //file: (filePath)
name: 'file',
formData: { //
'userId': that.appPersonallist.userId,
},
timeout: 5000,
success(res) {
that.appPersonallist.avatar = JSON.parse(res.data).imgUrl
userPassWord(that.appPersonallist).then(res => {
if (res.code == 200) {
that.$refs.uToast.show({
title: '修改成功',
type: 'success',
duration: '1500',
})
if (that.timer) {
clearTimeout(that.timer)
}
that.timer = setTimeout(e => {
uni.navigateBack({
delta: 1
})
}, 1500)
} else {
that.$refs.uToast.show({
title: res.msg,
type: 'error'
})
}
})
}
})
} else {
userPassWord(that.appPersonallist).then(res => {
console.log(res)
if (res.code == 200) {
that.$refs.uToast.show({
title: '修改成功',
type: 'success',
duration: '1500',
})
if (that.timer) {
clearTimeout(that.timer)
}
that.timer = setTimeout(e => {
uni.navigateBack({
delta: 1
})
}, 1500)
} else {
that.$refs.uToast.show({
title: res.msg,
type: 'error'
})
}
})
}
},
confirm(e) {
this.appPersonallist.nurseStationSysUserVOList[0].nurseStationId = e[0].value
this.appPersonallist.nurseStationSysUserVOList[0].nurseStationName = e[0]['label']
},
//
info() {
personNurseStationLists(this.pageNum, this.pageSize).then(res => {
this.NurseStationList = res.rows.map((e) => {
return {
value: e.id,
label: e.nurseStationName,
}
})
})
},
},
}
</script>
<style lang="scss">
@import './Modifyinformation.scss';
</style>

View File

@ -0,0 +1,356 @@
<template>
<view class="app">
<view class="inputs">
<i class="icon"></i>
<input type="text" name="" v-model='nurseItemName' id="" class="input" placeholder="请输入搜索内容">
</view>
<view class="tab">
<view class="tab-item" @tap="testTabClick(index)" v-for="(item,index) in tabList"
:class="tabIndex == index?'active':''">
{{item.name}}
</view>
<view class="" v-if="list.length>0">
<view class="Apayment" v-if='choicetab==0' v-for="(item,index) in list" :key="item.id">
<view class="names">{{item.serviceDate}} {{item.serviceStartTime}}-{{item.serviceEndTime}}
<span>待完成</span>
</view>
<image @tap='gotask(item)' :src="baseurl+item.itemPictureUrl" mode=""></image>
<view class="detailsinfo" @tap='gotask(item)'>
<view class="change">
{{item.nurseItemName}}
</view>
<view class="time">
服务时长{{item.itemServeDurationUnit}}
</view>
<view class="price">
{{item.totalPrice}}
</view>
</view>
<view class="anniu">
<view class="logistics" @tap='gotask(item)'>详情</view>
<view class="logistics harvest" @tap='goconfirmCompletion(item)'>去完成</view>
</view>
</view>
<view class="Apayment" @tap='gotask(item)' v-if='choicetab==1' v-for="(item,uindex) in list"
:key="uindex">
<view class="names">{{item.serviceDate}} {{item.serviceStartTime}}-{{item.serviceEndTime}}
<span>已完成</span>
</view>
<image :src="baseurl+item.itemPictureUrl" mode=""></image>
<view class="detailsinfo">
<view class="change">
{{item.nurseItemName}}
</view>
<view class="time">
服务时长{{item.itemServeDurationUnit}}
</view>
<view class="price">
{{item.totalPrice}}
</view>
</view>
<!-- <view class="anniu">
<view class="evaluate">查看评价</view>
</view> -->
</view>
</view>
<view class="">
<!-- // -->
<view class="noorder" v-if="list.length==0&&choicetab==0">
<image src="../../static/noorder.png" mode=""></image>
<view class="">
暂无待完成服务
</view>
</view>
<!-- // -->
<view class="noorder" v-if="list.length==0&&choicetab==1">
<image src="../../static/noorder.png" mode=""></image>
<view class="">
暂无已完成服务
</view>
</view>
</view>
</view>
</view>
</template>
<script>
import {
selectMission
} from '@/api/Mymission.js'
import baseurl from '@/api/baseurl.js'
export default {
data() {
return {
baseurl: '',
choicetab: 0, //
tabIndex: 0, //
tabList: [{
name: "待完成"
}, {
name: "已完成"
}, ],
nursePersonId: '', //id
orderStatus: 'NOT_FINISH', // orderStatus: NOT_FINISHCOMPLETE
pageNum: 1,
pageSize: 10,
//
list: [],
total: 0,
nurseItemName: '',
}
},
watch: {
nurseItemName() {
this.selectMissioninfo()
}
},
methods: {
//
goconfirmCompletion(item) {
uni.navigateTo({
url: `/pages/confirmCompletion/confirmCompletion?orderDetailsId=${item.id}&orderNo=${item.orderNo}`
})
},
//list
selectMissioninfo() {
selectMission(this.nursePersonId, this.orderStatus, this.pageNum, this.pageSize, this.nurseItemName).then(
res => {
this.list = res.rows
this.total = res.total
})
},
//
gotask(item) {
uni.navigateTo({
url: `/pages/taskDetails/taskDetails?orderDetailsId=${item.id}`
})
},
//
testTabClick(index) {
this.list = []
this.tabIndex = index
this.choicetab = index
this.pageNum == 1
if (this.choicetab == 0) {
this.orderStatus = 'NOT_FINISH'
} else {
this.orderStatus = 'COMPLETE'
}
selectMission(this.nursePersonId, this.orderStatus, this.pageNum, this.pageSize, this.nurseItemName).then(
res => {
this.list = res.rows
this.total = res.total
})
},
// goorderdetails() {
// uni.navigateTo({
// url: '/pages/orderDetails/orderDetails'
// })
// },
},
onShow() { //
this.baseurl = baseurl
var that = this
try {
const value = uni.getStorageSync('nursePersonId');
if (value) {
that.nursePersonId = value
this.selectMissioninfo();
}
} catch (e) {}
},
onReachBottom() { //
if (this.list.length >= this.total) {} else {
this.pageNum++
selectMission(this.nursePersonId, this.orderStatus, this.pageNum, this.pageSize, this.nurseItemName).then(
res => {
res.rows.forEach(e => {
this.list.push(e)
})
})
}
},
onPullDownRefresh() { //
this.pageNum = 1;
selectMission(this.nursePersonId, this.orderStatus, this.PageNum, this.PageSize, this.nurseItemName).then(
res => {
this.list = res.rows
this.total = res.total
})
setTimeout(function() {
uni.stopPullDownRefresh();
}, 1000);
},
}
</script>
<style lang="scss">
.app {
background-color: #F4F5F7;
width: 100%;
height: 100vh;
padding: 1rpx 3%;
.noorder {
margin-top: 20%;
image {
display: block;
margin: 0 auto;
width: 200rpx;
height: 240rpx;
}
view {
margin-top: 100rpx;
text-align: center;
font-size: 36rpx;
color: #BFBFBF;
}
}
.tab .active {
background: #4C7BC9;
}
//
.tab-item {
width: 50%;
text-align: center;
line-height: 70rpx;
color: #ffffff;
background: #BAB7B8;
display: inline-block;
box-shadow: 0rpx 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20rpx;
font-size: 34rpx;
}
.Apayment {
width: 100%;
height: 391rpx;
background: #FFFFFF;
box-shadow: 0rpx 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20rpx;
line-height: 70rpx;
padding: 1%;
font-size: 30rpx;
color: #969394;
margin-top: 20rpx;
position: relative;
image {
display: block;
width: 170rpx;
height: 170rpx;
border-radius: 10rpx;
margin: 30rpx 0 0 20rpx;
}
.anniu {
// width: 375rpx;
float: right;
margin: 30rpx 20rpx 0 0;
.evaluate {
background: #4C7BC9;
width: 216rpx;
height: 68rpx;
text-align: center;
color: #ffffff;
border-radius: 26rpx;
}
.logistics {
width: 175rpx;
height: 68rpx;
text-align: center;
color: #ffffff;
background: #E1AE3C;
border-radius: 26rpx;
display: inline-block;
}
.harvest {
background: #4C7BC9;
margin: 0 0 0 15rpx;
}
}
.detailsinfo {
width: 60%;
height: 200rpx;
border-radius: 10rpx;
position: absolute;
top: 25%;
left: 35%;
.change {
width: 100%;
color: #000000;
font-size: 34rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.time {
width: 100%;
font-size: 32rpx;
color: #999999;
position: absolute;
top: 32%;
}
.price {
width: 100%;
font-size: 30rpx;
color: #D43953;
position: absolute;
top: 65%;
}
}
.names {
width: 95%;
margin-left: 20rpx;
border-bottom: 1rpx solid #D8D4D4;
span {
color: #4C7BC9;
float: right;
}
}
}
.inputs {
box-shadow: 0rpx 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border: 1rpx solid #f0f0f0;
width: 99%;
height: 65rpx;
margin: 20rpx auto;
border-radius: 20rpx;
background-color: #Ffffff;
position: relative;
.input {
position: absolute;
height: 65rpx;
left: 10%;
line-height: 65rpx;
font-size: 26rpx;
color: #BEBEC0;
}
.icon {
background: url(@/static/sousuo.png) no-repeat;
width: 30rpx;
height: 28rpx;
background-size: cover;
position: absolute;
top: 30%;
left: 5%;
}
}
}
</style>

View File

@ -0,0 +1,329 @@
<template>
<view class="app">
<view class="picture">
<view class="attendantImg">
护理员到岗照片
</view>
<view class="uppicture" @tap='uploadonDutyPictureUrl'>
<view class="choice" v-if="!onDutyPictureUrl">
拍摄照片
</view>
<image v-else :src="onDutyPictureUrl" mode=""></image>
<!-- <u-upload class="slot-btn" width="530" height="130" ></u-upload> -->
</view>
</view>
<!-- <view class="picture" style="height: 330rpx;">
<view class="attendantImg">
服务进行中视频不少于1min<span>*选填</span>
</view>
<view class="uppicture">
<u-upload class="slot-btn" width="530" height="130"></u-upload>
</view>
<view class="user">
<image src="../../static/radio.png" mode=""></image>
用户不同意拍摄
</view>
</view> -->
<view class="picture">
<view class="attendantImg">
服务结束照片
</view>
<view class="uppicture" @tap='uploadserviceEndPictureUrl'>
<view class="choice" v-if="!serviceEndPictureUrl">
拍摄照片
</view>
<image v-else :src="serviceEndPictureUrl" mode=""></image>
<!-- <u-upload class="slot-btn" width="530" height="130" ></u-upload> -->
</view>
</view>
<view class="picture" style="height: 730rpx;">
<view class="attendantImg" style="border-bottom: 1rpx solid #BAB7B8;">
用户签名确认
</view>
<view class="receive">
我确认已接受服务
</view>
<view class="uppicture" @tap='show=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>
<!-- <u-upload class="slot-btn" :action="action" :file-list="fileList" width="620" height="130"></u-upload> -->
</view>
</view>
<view class="submit">
<view class="finish" @tap='buyfinish'>
去完成
</view>
</view>
<u-mask :show="show" @click="show = false">
<signature @userSignaturePictureUrl='userSignaturePicture' @click.native.stop
style='position:absolute;bottom:0%;width: 100%;height: 800rpx;'></signature>
</u-mask>
<u-toast ref="uToast" />
</view>
</template>
<script>
import signature from '../signature/signature.vue'
import {
orderConfirm
} from '@/api/confirmCompletion/index.js'
import baseurl from '@/api/baseurl.js'
export default {
components: {
signature
},
data() {
return {
show: false,
orderNo: null,
onDutyPictureUrl: null,
serviceEndPictureUrl: null,
userSignaturePictureUrl: null,
list: {
res: {},
id: null,
serviceLocationName: null,
onDutyPictureUrl: null,
serviceEndPictureUrl: null,
userSignaturePictureUrl: null,
serveLocationLatitude: null,
serveLocationLongitude: null,
},
}
},
methods: {
//
userSignaturePicture(data) {
this.userSignaturePictureUrl = data
this.show = false
},
// /base64
dataURLtoBlob(dataurl) {
var arr = dataurl.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {
type: mime,
});
},
//
uploadserviceEndPictureUrl() { //
var that = this;
uni.chooseImage({
count: 1,
sourceType: ['camera'],
success(res) {
that.serviceEndPictureUrl = res.tempFilePaths[0]
}
})
},
uploadonDutyPictureUrl() { //
var that = this;
uni.chooseImage({
count: 1,
sourceType: ['camera'],
success(res) {
that.onDutyPictureUrl = res.tempFilePaths[0]
}
})
},
//
buyfinish() {
if (this.serviceEndPictureUrl && this.userSignaturePictureUrl && this.onDutyPictureUrl) {
let that = this
uni.uploadFile({
url: baseurl + '/nurseApplet/uploadFile/uploadPictureUrl',
filePath: that.serviceEndPictureUrl,
name: 'file',
formData: {
'orderNo': that.orderNo
},
timeout: 5000,
success(res) {
that.list.serviceEndPictureUrl = JSON.parse(res.data).imgUrl
uni.uploadFile({
url: baseurl + '/nurseApplet/uploadFile/uploadPictureUrl',
filePath: that.userSignaturePictureUrl,
name: 'file',
formData: {
'orderNo': that.orderNo
},
timeout: 5000,
success(res) {
that.list.userSignaturePictureUrl = JSON.parse(res.data).imgUrl
uni.uploadFile({
url: baseurl + '/nurseApplet/uploadFile/uploadPictureUrl',
filePath: that.onDutyPictureUrl,
name: 'file',
formData: {
'orderNo': that.orderNo
},
timeout: 5000,
success(res) {
that.list.onDutyPictureUrl = JSON.parse(res.data)
.imgUrl
orderConfirm(that.list).then(res => {
if (res.code == 200) {
that.$refs.uToast.show({
title: '服务完成',
type: 'success',
duration: '1500',
})
if (that.timer) {
clearTimeout(that.timer)
}
that.timer = setTimeout(e => {
uni.navigateBack({
delta: 1
})
}, 1500)
} else {
that.$refs.uToast.show({
title: res.msg,
type: 'error'
})
}
})
}
})
}
})
}
})
} else {
this.$refs.uToast.show({
title: '请上传全部照片并用户签名确认',
type: 'error'
})
}
},
},
onLoad(options) {
this.list.id = options.orderDetailsId
this.orderNo = options.orderNo
var that = this
uni.getLocation({
type: 'gcj02',
geocode: true,
success: function(res) {
that.list.serviceLocationName = res.address.poiName
that.list.serveLocationLatitude = res.latitude
that.list.serveLocationLongitude = res.longitude
},
fail: error => {
uni.showModal({
title: '提示',
content: '获取定位失败,是否授权打开定位',
success: (res) => {
if (res.confirm) {}
}
})
}
});
},
}
</script>
<style lang="scss">
.app {
padding: 3%;
font-size: 36rpx;
.picture {
width: 95%;
height: 630rpx;
background: #FFFFFF;
box-shadow: 0px 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20px;
margin: 20rpx auto 0;
.attendantImg {
color: #000000;
height: 88rpx;
line-height: 88rpx;
margin-left: 30rpx;
span {
color: #BAB7B8;
}
}
.uppicture {
border: 1rpx dashed #818181;
width: 90%;
height: 500rpx;
margin: 0 auto;
position: relative;
image {
width: 100%;
height: 100%;
}
.choice {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
::v-deep .u-list-item[data-v-49deb6f2] {
background: #FFFFFF;
}
span {
font-size: 35rpx;
color: #969394;
}
}
.user {
height: 88rpx;
line-height: 88rpx;
color: #969394;
margin-left: 30rpx;
image {
width: 34rpx;
height: 34rpx;
}
}
.receive {
height: 88rpx;
line-height: 88rpx;
color: #969394;
margin-left: 30rpx;
}
}
.submit {
width: 32%;
height: 68rpx;
font-size: 32rpx;
color: #FFFFFF;
text-align: center;
margin-left: 60%;
.finish {
width: 100%;
height: 68rpx;
line-height: 68rpx;
background: #4C7BC9;
border-radius: 26rpx;
margin-top: 100rpx;
}
}
}
</style>

View File

@ -0,0 +1,74 @@
.app {
height: 100vh;
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: 40%;
left: 10%;
}
}

View File

@ -0,0 +1,144 @@
<template>
<view class="app">
<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="11"
v-model="phonenumber" />
</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>

View File

@ -0,0 +1,91 @@
<template>
<view class="app">
<view class="cards">
<view class="item" style="background: #D43953;" @tap='gomymission'>
<image src="../../static/dingdan.png" mode=""></image>
<view class="title">
我的任务
</view>
</view>
<view class=" item" style="background: #4C7BC9; " @tap='gopersonal'>
<image src="../../static/user.png" mode=""></image>
<view class="title">
个人信息
</view>
</view>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
nursePerson,
} from '@/api/personnal/personal.js';
export default {
data() {
return {
phonenumber: null,
password: null,
};
},
onShow() {
let that = this
try {
const value = uni.getStorageSync('phonenumber');
const value2 = uni.getStorageSync('password');
if (value && value2) {
that.phonenumber = value
that.password = value2
}
} catch (e) {}
},
methods: {
gomymission() {
nursePerson(this.phonenumber, this.password).then(res => {
if (res.code == 200) {
uni.navigateTo({
url: '/pages/Mymission/Mymission'
})
} else if (res.code == 9999) {} else {
this.$refs.uToast.show({
title: '账号异常,请重新登录',
type: 'error',
duration: '1000'
})
setTimeout(e => {
uni.reLaunch({
url: '/pages/login/login'
})
}, 1000)
}
})
},
gopersonal() {
nursePerson(this.phonenumber, this.password).then(res => {
if (res.code == 200) {
uni.navigateTo({
url: '/pages/personal/personal'
})
} else if (res.code == 9999) {} else {
this.$refs.uToast.show({
title: '账号异常,请重新登录',
type: 'error',
duration: '1000'
})
setTimeout(e => {
uni.reLaunch({
url: '/pages/login/login'
})
}, 1000)
}
})
},
},
}
</script>
<style lang="scss">
.app{
padding-top: 160rpx;
}
</style>

33
pages/login/login.scss Normal file
View File

@ -0,0 +1,33 @@
.app {
font-family: DengXian;
color: #C3C1C1;
font-weight: 400;
height:100vh;
background-color: #ffffff;
.title{
position: absolute;
top:20%;
left:50%;
transform: translateX(-50%);
.text{
text-align: center;
padding-top: 30rpx;
font-size: 32rpx;
color: #000000;
font-weight: 600;
}
image{
width: 200rpx;
height: 200rpx;
}
}
.loginbtn{
width: 90%;
position: absolute;
top:55%;
left:5%;
background-color: #46ABD7;
color: #ffffff;
}
}

86
pages/login/login.vue Normal file
View File

@ -0,0 +1,86 @@
<template>
<view class="app">
<view class="title">
<image src="../../static/logo.png" mode=""></image>
<view class="text">
泉医到家
</view>
</view>
<button class="loginbtn" open-type="getPhoneNumber" @getphonenumber="getPhoneNumberp">微信一键登录</button>
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
appLogin,
createMobileToken
} from '@/api/login/index.js'
export default {
data() {
return {
checked: false,
phonenumber: '',
password: '',
userId: '',
};
},
//
onLoad(options) {
if (options.phonenumber && options.password) {
this.phonenumber = options.phonenumber
this.password = options.password
}
},
methods: {
login() {
var that = this
appLogin(this.phonenumber, this.password).then(res => {
console.log(res)
if (res.code == 200) {
uni.setStorageSync("phonenumber", that.phonenumber)
uni.setStorageSync("password", that.password)
uni.setStorageSync("nursePersonId", res.data.nursePersonId)
that.$refs.uToast.show({
title: '登录成功',
type: 'success',
duration: '1500'
})
setTimeout(() => {
uni.reLaunch({
url: '/pages/homepage/homepage',
})
}, 1500);
} else {
that.$refs.uToast.show({
title: res.msg,
type: 'error'
})
}
})
},
//
pwdlogin() {
var that = this
createMobileToken().then(res => {
uni.setStorageSync("token", res.data.token)
that.login();
})
},
//
goregister() {
uni.navigateTo({
url: '/pages/register/register'
})
},
forgetpassword() {
uni.navigateTo({
url: `/pages/forgotPassword/forgotPassword?phonenumber=${this.phonenumber}`
})
},
},
}
</script>
<style lang="scss">
@import './login.scss';
</style>

264
pages/personal/personal.vue Normal file
View File

@ -0,0 +1,264 @@
<template>
<view class="app">
<view class="user">
<view class="img" v-if="appPersonallist.avatar==''||!appPersonallist.avatar">
<image style="height: 110rpx;" src="../../static/person.png" mode=""></image>
</view>
<view class="img" v-else>
<image :src="baseurl+appPersonallist.avatar" mode=""></image>
</view>
<!-- <view class="phone">
{{appPersonallist.phonenumber}}
</view> -->
<view class="nickname">
{{appPersonallist.userName}}
</view>
<view class="modify" @tap='updatainfo()'>
修改信息
<u-icon name="arrow-right" color="#ffffff" size="32"></u-icon>
</view>
</view>
<view class="information">
<view class="item">
姓名{{appPersonallist.nickName}}
</view>
<view class="item">
电话{{appPersonallist.phonenumber }}
</view>
<view class="item" style="border:none;border-radius:0 0 20rpx 20rpx;line-height:50rpx;padding: 20rpx 3%;"
v-if="appPersonallist.nurseStationSysUserVOList">
护理站
<text v-for='(uitem,index) in appPersonallist.nurseStationSysUserVOList'> {{uitem.nurseStationName}}
<text v-if="index!=appPersonallist.nurseStationSysUserVOList.length-1"></text>
</text>
</view>
<view class="signout" @tap='remove'>
退出账号
</view>
</view>
<!-- <view class="External" style="margin: 100rpx auto 0;">
<view class="lefttext">
我的设备
</view>
<image src="../../static/jiantou.png" mode=""></image>
</view> -->
<!-- <view class="External">
<view class="lefttext">
修改密码
</view>
<image src="../../static/jiantou.png" mode=""></image>
</view> -->
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
nursePerson,
} from '@/api/personnal/personal.js';
import baseurl from '@/api/baseurl.js'
export default {
data() {
return {
baseurl: '', //url
phonenumber: '',
avatar: '',
password: '',
userId: '',
appPersonallist: [], //
nurseStationSysUserVOList: [],
}
},
onShow() {
this.baseurl = baseurl;
let that = this
try {
const value = uni.getStorageSync('phonenumber');
const value2 = uni.getStorageSync('password');
if (value && value2) {
that.phonenumber = value
that.password = value2
that.myInfo()
}
} catch (e) {}
},
onLoad(options) {},
methods: {
//退
remove() {
let that = this
uni.showModal({
title: '提示',
content: '确认要退出此账号吗',
success: function(res) {
if (res.confirm) {
uni.removeStorageSync("phonenumber")
uni.removeStorageSync("password")
uni.removeStorageSync("nursePersonId")
that.$refs.uToast.show({
title: '退出账号成功',
type: 'success',
duration: '1000'
})
setTimeout(e => {
uni.reLaunch({
url: '/pages/login/login'
})
}, 1000)
} else if (res.cancel) {
that.$refs.uToast.show({
title: '退出账号失败',
type: 'error',
duration: '1000'
})
}
}
});
},
myInfo() {
nursePerson(this.phonenumber, this.password).then(res => {
if (res.code == 200) {
this.appPersonallist = res.data
} else {
this.$refs.uToast.show({
title: '账号异常,请重新登录',
type: 'error',
duration: '1500'
})
setTimeout(e => {
uni.reLaunch({
url: '/pages/login/login'
})
}, 1500)
}
})
},
updatainfo() {
uni.navigateTo({
url: `/pages/Modifyinformation/Modifyinformation`
})
}
}
}
</script>
<style lang="scss">
.app {
padding: 0;
font-size: 32rpx;
height: 100vh;
.signout {
// position: absolute;
// bottom: 60rpx;
// width: 94%;
background: #FFFFFF;
margin-top: 50rpx;
height: 80rpx;
line-height: 80rpx;
// left:3%;
border-radius: 20rpx;
text-align: center;
}
.External {
width: 94%;
height: 100rpx;
line-height: 100rpx;
margin: 20rpx auto;
padding-left: 5%;
background: #FFFFFF;
box-shadow: 0px 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20rpx;
position: relative;
image {
width: 18rpx;
height: 27rpx;
position: absolute;
right: 5%;
top: 50%;
transform: translateY(-50%);
}
.lefttext {
display: inline-block;
}
}
.information {
width: 98%;
border-radius: 20rpx;
position: absolute;
top: 20%;
left: 1%;
color: #000000;
overflow: hidden;
font-size: 35rpx;
.item {
// height: 110rpx;
line-height: 110rpx;
background: #FFFFFF;
padding-left: 3%;
box-shadow: 0px 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-bottom: 1rpx solid #D8D4D4;
.address {
height: 40rpx;
// font-size: 30rpx;
line-height: 40rpx;
display: inline-block;
width: 80%;
margin-left: 30rpx;
margin-top: 30rpx;
}
}
}
.user {
width: 100%;
height: 500rpx;
background: #4C7BC9;
position: relative;
color: #FFFFFF;
.modify {
font-size: 32rpx;
position: absolute;
right: 3%;
top: 18%;
}
.nickname {
position: absolute;
top: 18%;
left: 28%;
}
.phone {
position: absolute;
top: 13%;
left: 28%;
}
.img {
width: 120rpx;
height: 120rpx;
position: absolute;
top: 10%;
left: 5%;
image {
border-radius: 50%;
width: 120rpx;
margin-left: 50%;
margin-top: 50%;
transform: translate(-50%, -50%);
height: 120rpx;
}
}
}
}
</style>

View File

@ -0,0 +1,172 @@
.app {
height: 100vh;
padding: 20rpx 0;
.Agreement{
width: 100%;
background-color: #F4F5F7;
text-align: center;
height: 1000rpx;
position: absolute;
// left:3%;
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;
span {
margin-left: 3%;
}
.addition {
line-height: 100rpx;
font-size: 34rpx;
font-weight: 400;
margin-left: 3%;
}
.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;
}
}
}
.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;
margin-left: 26%;
margin-top: 22%;
// margin: 0 auto;
}
}
}
}
.switch {
text-align: center;
line-height: 60rpx;
color: #46ABD7;
position: absolute;
top: 70%;
}
.loginbtn {
width: 70%;
height: 100rpx;
text-align: center;
line-height: 100rpx;
background: #4C7BC9;
border-radius: 51rpx;
font-size: 41rpx;
color: #FFFFFF;
position: absolute;
top: 60%;
left: 15%;
}
}

175
pages/register/register.vue Normal file
View File

@ -0,0 +1,175 @@
<template>
<view class="app">
<view class="item">
<view class="lefttext">
姓名
</view>
<input class="righttext" type="text" placeholder="请输入" v-model="appPersonallist.nickName" maxlength="30" />
</view>
<view class="item">
<view class="lefttext">
输入密码
</view>
<u-input class='righttext' style='left:30%' placeholder="请输入密码" maxlength="10"
v-model="appPersonallist.stationPersonPassword" type="password" :border="false" :password-icon="true" />
</view>
<view class="item">
<view class="lefttext">
重复密码
</view>
<u-input class='righttext' style='left:30%' placeholder="请再次输入密码" maxlength="10"
v-model="appPersonallist.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="11"
v-model="appPersonallist.phonenumber" />
</view>
<view class="item" @tap='show=true'>
<span>护理站</span>
<text class='addition'>{{nurseStationName}}</text>
</view>
<view class="radio-content">
<view class="radio-right" @tap="changeRadio">
<view class="radio" :class="radio == 2 ? 'radio-default':''">
<view :class="radio == 2 ? 'radio-active':''"></view>
</view>
</view>
<view class="agreement">我已阅读并同意<text @tap='maskshow=true'
style="color: #000000;border-bottom: 1rpx solid #000000;">用户协议</text></view>
</view>
<view class="loginbtn" @tap='getInfo'>
注册
</view>
<view class="switch" style="right:5%" @tap='gologin'>
已有账号,去登录
</view>
<u-select v-model="show" mode="single-column" :list="listinfo" @confirm="confirm"></u-select>
<u-toast ref="uToast" />
<!-- // -->
<u-mask :show="maskshow" class='mask' @click='maskshow=false'>
<view class="Agreement">
<view class="title">
用户协议与隐私政策
</view>
<scroll-view scroll-y="true" class="scroll-Y" style="">
<contenttext></contenttext>
</scroll-view>
<view class="cancel" @tap='maskshow=false'>
取消
</view>
<view class="determine" @tap='tapradio'>
确定并同意
</view>
</view>
</u-mask>
</view>
</template>
<script>
import {
nurseAppLoginSysUser,
personNurseStationLists
} from '@/api/register/index.js'
import contenttext from './text.vue'
export default {
components: {
contenttext
},
data() {
return {
maskshow: false, //
listinfo: [],
show: false,
radio: 1, //
nurseStationName: '',
pageSize: 999,
pageNum: 1,
appPersonallist: {
nickName: '',
newpassword: '',
phonenumber: '',
stationPersonPassword: '',
nurseStationIds: '',
}
};
},
onLoad() {
this.info()
},
methods: {
//
getInfo() {
if (this.radio == 1) {
this.$refs.uToast.show({
title: '请审核并同意用户协议',
type: 'error'
})
} else if (this.appPersonallist.stationPersonPassword !== this.appPersonallist.newpassword) {
this.$refs.uToast.show({
title: '密码输入不一致,请重新输入',
type: 'error',
duration: '1500'
})
} else {
nurseAppLoginSysUser(this.appPersonallist).then(res => {
if (res.code == 200) {
this.$refs.uToast.show({
title: '注册成功,前往登录',
type: 'success',
duration: '1500'
})
setTimeout(e => {
uni.navigateTo({
url: `/pages/login/login?phonenumber=${this.appPersonallist.phonenumber}&password=${this.appPersonallist.stationPersonPassword}`
})
}, 1500)
} else {
this.$refs.uToast.show({
title: res.msg,
type: 'error'
})
}
})
}
},
//
info() {
personNurseStationLists(this.pageNum, this.pageSize).then(res => {
this.listinfo = res.rows.map((e) => {
return {
value: e.id,
label: e.nurseStationName,
}
})
})
},
confirm(e) {
this.appPersonallist.nurseStationIds = e[0].value
this.nurseStationName = e[0]['label']
},
tapradio() {
this.radio = 2;
this.maskshow = false;
},
//
gologin() {
uni.navigateTo({
url: `/pages/login/login`
})
},
changeRadio() {
if (this.radio == 1) {
this.radio = 2;
} else {
this.radio = 1;
}
},
},
}
</script>
<style lang="scss">
@import './register.scss';
</style>

384
pages/register/text.vue Normal file
View File

@ -0,0 +1,384 @@
<template>
<view class="">
泉医到家简称我们深知个人信息对您的重要性也感谢您对我们的信任
我们将通过本政策向您说明我们如何收集存储保护使用及对外提供您的信息并说明您享有的权利其中要点如下
<view class="">
1为了便于您了解您在使用我们的服务时我们需要收集的信息类型与用途我们将结合具体服务向您逐一说明
</view>
<view class="">
2为了向您提供服务所需我们会按照合法正当必要的原则收集您的信息
</view>
<view class="">
3如果为了向您提供服务而需要将您的信息共享至第三方我们将评估第三方收集信息的合法性正当性必要性我们将要求第三方对您的信息采取保护措施并且严格遵守相关法律法规与监管要求另外我们会按照法律法规及国家标准的要求以确认协议具体场景下的文案确认弹窗提示等形式征得您的同意或确认第三方已征得您的同意
</view>
<view class="">
4如果为了向您提供服务而需要从第三方获取您的信息我们将要求第三方说明信息来源并要求第三方保障其提供信息的合法性如果我们开展业务提供服务需进行的个人信息处理活动超出您原本向第三方提供个人信息的授权范围我们将征得您的明确同意
</view>
<view class="">
5 您可以通过本隐私政策介绍的方式访问和管理您的信息设置隐私功能或进行投诉举报
</view>
<view class="" style="padding-top: 20rpx;">
您可以根据以下索引阅读相应章节进一步了解本政策的具体约定
</view>
<view>我们如何收集和使用个人信息</view>
<view> 我们对Cookie或同类技术的使用</view>
<view> 我们如何存储个人信息</view>
<view> 我们如何共享转让公开披露个人信息</view>
<view> 我们如何保护个人信息的安全</view>
<view> 您的权利</view>
<view> 未成年人使用条款</view>
<view> 隐私政策的修订和通知</view>
<view> 适用范围</view>
<view> 第三方软件开发包SDK个人信息收集情况</view>
<view> 十一联系我们</view>
<view> 我们将按照法律规定保护您的个人信息及隐私安全我们制定本隐私政策并特别提示希望您在使用泉医到家及相关服务前仔细阅读并理解本隐私政策以便做出适当的选择</view>
<view class="" style="text-indent: 0em;padding: 20rpx 0;">
我们如何收集和使用个人信息
</view>
<view class="">
在您使用泉医到家及服务的过程中我们将根据合法正当必要的原则收集信息我们收集或您提供的信息将用于
</view>
<view class="">
1.保障产品的正常基础运行
</view>
<view> 2.实现各项功能和服务</view>
<view> 3.优化改善产品和服务</view>
<view> 4.保障产品服务以及用户使用安全</view>
<view> 5.遵循法律法规与国家标准的规定</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 我们直接收集与使用的个人信息</view>
<view> 我们会按照如下方式收集您在使用服务时主动提供的以及通过自动化手段收集您在使用功能或接受服务过程中产生的信息</view>
<view> 1.保障泉医到家和相关服务的正常运行</view>
<view>
当您使用泉医到家及相关服务时为了保障软件与服务的正常运行我们会收集您的硬件型号操作系统版本号国际移动设备识别码IMEI网络设备硬件地址MACIP地址软件版本号网络接入方式及类型操作日志电话状态等信息请您了解这些信息是我们提供服务和保障产品正常运行所必须收集的基本信息
</view>
<view> 2.注册认证登录泉医到家和相关服务</view>
<view>
1当您注册登录泉医到家及相关服务时您可以通过手机号创建账号我们将通过发送短信验证码来验证您的身份是否有效并且您可以完善相关的网络身份识别信息如头像昵称和密码收集这些信息是为了帮助您完成注册您还可以根据自身需求选择填写性别生日等信息完善您的个人信息
</view>
<view>
2您也可以使用第三方账号如微信登录进入泉医到家您此时将授权我们获取您在第三方平台注册的公开信息头像昵称等并在您同意本隐私政策后将您的第三方账号与您的泉医到家账号绑定使您可以通过第三方账号直接登录并使用本产品和相关服务
</view>
<view> 3.获得您的明示同意后的地理位置信息</view>
<view> 在本地频道中我们会基于IP地址对应的城市济南向您展示推荐您所在地区的本地相关信息</view>
<view> 拒绝提供地理位置信息我们将不会基于地理位置向您推送信息但不会影响泉医到家其他功能与服务的正常使用</view>
<view> 4.为您提供信息发布功能或服务</view>
<view> 您发布内容评论提问或回答时我们将收集您发布的信息并展示您的昵称头像发布内容等</view>
<view> 您使用上传图片发布音视频功能时我们会请求您授权相机照片麦克风等敏感权限您如果拒绝授权提供将无法使用此功能但不影响您正常使用泉医到家的其他功能</view>
<view> 您发布信息并选择显示位置时我们会请求您授权地理位置权限并收集与本服务相关的位置信息这些技术包括 IP 地址GPS 以及能够提供相关信息的
WI-FI接入点蓝牙和基站等传感器技术您如果拒绝授权提供将无法使用此功能但不影响您正常使用泉医到家的其他功能</view>
<view>
我们会将缓存写入外置存储器为此需要您授权外置存储器读写权限
</view>
<view>
5.为您提供搜索服务
</view>
<view>
您使用泉医到家的搜索服务时我们会收集您的搜索关键字信息日志记录等为了提供高效的搜索服务部分前述信息会暂时存储在您的本地存储设备之中并可向您展示搜索结果内容搜索历史记录
</view>
<view>
6.保障产品服务及用户使用安全
</view>
<view>
为帮助我们更好地了解泉医到家及相关服务的运行情况以便确保运行与提供服务的安全我们可能记录网络日志信息以及使用软件及相关服务的频率崩溃数据总体安装使用情况性能数据等信息
</view>
<view>
7.为您提供意见反馈服务
</view>
<view>
为了确认您的身份信息及在处理完您的意见反馈后便于向您回复需要您提交意见反馈时填写您的电话或QQ或邮箱等此信息仅用于确认身份及回复您使用
</view>
<view style="text-indent: 0em;padding: 10rpx 0;">
我们可能从第三方获得的您的个人信息
</view>
<view>
1.当您主动使用第三方账号登录泉医到家我们会收集第三方账号的昵称头像等信息
</view>
<view>
2.用户因使用我们的产品或者服务而被我们收集的信息例如其他用户发布的信息中可能含有您的部分信息在评论留言发布图文音视频中涉及到与您相关的信息
</view>
<view style="text-indent: 0em;padding: 10rpx 0;">
收集使用个人信息目的变更的处理
</view>
<view>
请您了解随着我们业务的发展可能会对泉医到家的功能和提供的服务有所调整变化原则上当新功能或服务与发布信息互动交流搜索查询注册认证等场景相关时收集与使用的个人信息将与原处理目的具有直接或合理关联在与原处理目的无直接或合理关联的场景下我们收集使用您的个人信息会再次进行告知并征得您的同意
</view>
<view style="text-indent: 0em;padding: 10rpx 0;">
依法豁免征得同意收集和使用的个人信息
</view>
<view> 请您理解在下列情形中根据法律法规及相关国家标准我们收集和使用您的个人信息无需征得您的授权同意</view>
<view> 1与国家安全国防安全直接相关的</view>
<view> 2与公共安全公共卫生重大公共利益直接相关的</view>
<view> 3与犯罪侦查起诉审判和判决执行等直接相关的</view>
<view> 4出于维护个人信息主体或其他个人的生命财产等重大合法权益但又很难得到本人同意的</view>
<view> 5所收集的您的个人信息是您自行向社会公众公开的</view>
<view> 6从合法公开披露的信息中收集的您的个人信息的如合法的新闻报道政府信息公开等渠道</view>
<view> 7根据您的要求签订或履行合同所必需的</view>
<view> 8用于维护泉医到家软件及相关服务的安全稳定运行所必需的例如发现处置泉医到家软件及相关服务的故障</view>
<view> 9学术研究机构基于公共利益开展统计或学术研究所必要且对外提供学术研究或描述的结果时对结果中所包含的个人信息进行去标识化处理的</view>
<view> 10法律法规规定的及与履行行业主管部门有关规定的义务相关的其他情形</view>
<view>
特别提示您注意如信息无法单独或结合其他信息识别到您的个人身份其不属于法律意义上您的个人信息当您的信息可以单独或结合其他信息识别到您的个人身份时或我们将无法与任何特定个人信息建立联系的数据与其他您的个人信息结合使用时这些信息在结合使用期间将作为您的个人信息按照本隐私政策处理与保护
</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 其他</view>
<view>
请您理解我们向您提供的服务是不断更新和发展的如您选择使用了前述说明当中未涵盖的其他服务基于该服务我们需要收集您的信息的我们会通过页面提示交互流程协议约定的方式另行向您说明信息收集的范围与目的并征得您的同意我们会按照本政策以及相应的用户协议约定使用存储对外提供及保护您的信息如您选择不提供前述信息您可能无法使用某项或某部分服务但不影响您使用我们提供的其他服务
</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 我们对Cookie或同类技术的使用</view>
<view> 为使您获得更轻松的访问体验您访问泉医到家提供的服务时我们可能会通过小型数据文件识别您的身份帮您省去重复输入登录信息的步骤或者帮助您判断您的账户是否安全这些数据文件可能是CookieFlash
Cookie或您的浏览器或关联应用程序提供的其他本地存储统称Cookie请您理解我们的某些服务只能通过使用Cookie才可得到实现如果您的浏览器或浏览器附加服务允许您可以修改对Cookie的接受程度或者拒绝泉医到家的Cookie但这一举动在某些情况下可能会影响您安全访问泉医到家和使用泉医到家提供的服务我们使用
Cookie或同类技术主要为了实现以下功能或服务</view>
<view> 保障产品与服务的安全高效运转</view>
<view> 我们可能会设置认证与保障安全性的cookie或匿名标识符使我们确认您是否安全登录服务或者是否遇到盗用欺诈等不法行为这些技术还会帮助我们改进服务效率提升登录和响应速度</view>
<view> 帮助您获得更轻松的访问体验</view>
<view> 使用此类技术可以帮助您省去重复您填写个人信息输入搜索内容的步骤和流程例如记录搜索历史</view>
<view> 为您推荐展示推送您可能感兴趣的内容或账号</view>
<view> 我们可能会利用Cookie或同类技术了解您的偏好和使用习惯进行咨询或数据分析以改善产品服务及用户体验并优化您对广告的选择</view>
<view> 我们承诺我们不会将Cookie用于本隐私政策所述目的之外的任何其他用途</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 我们如何存储个人信息</view>
<view> 信息存储的地点</view>
<view> 我们依照法律法规的规定将在境内运营过程中收集和产生的您的个人信息存储于中华人民共和国境内</view>
<view> 存储期限</view>
<view>
我们仅在为提供泉医到家及服务之目的所必需的期间内保留您的个人信息例如您发布的信息评论点赞等信息在您未撤回删除或未注销账号期间我们会保留相关信息超出必要期限后我们将对您的个人信息进行删除或匿名化处理但法律法规另有规定的除外
</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 我们如何共享转让公开披露个人信息</view>
<view> 个人信息的共享转让</view>
<view> 我们不会向第三方共享转让您的个人信息除非经过您本人事先授权同意或者共享转让的个人信息是去标识化处理后的信息且共享第三方无法重新识别此类信息的自然人主体</view>
<view> 1.我们可能会共享的个人信息</view>
<view> 1.1为实现特定功能而与业务合作伙伴共享</view>
<view>
当软件服务提供商智能设备提供商或系统服务提供商与我们联合为您提供服务时例如您需要使用地理位置功能时为实现这一功能我们可能会收集您的位置信息及相关设备信息例如硬件型号操作系统版本号国际移动设备身份识别码IMEI网络设备硬件地址MAC经过去标识化后并提供给前述提供商
</view>
<view> 1.2帮助您参加营销推广活动</view>
<view> 当您选择参加我们举办的有关营销活动时根据活动需要您提供姓名通信地址联系方式等信息经过您的明示同意我们会将上述信息与第三方共享以便我们能委托第三方及时向您提供奖品</view>
<view> 2.对共享个人信息第三方主体的谨慎评估及责任约束</view>
<view>
2.1如果为了向您提供服务而需要将您的信息共享至第三方我们将评估第三方收集信息的合法性正当性必要性我们将要求第三方对您的信息采取保护措施并且严格遵守相关法律法规与监管要求另外我们会按照法律法规及国家标准的要求以确认协议具体场景下的文案确认弹窗提示等形式征得您的同意或确认第三方已征得您的同意
</view>
<view> 2.2对我们与之共享您个人信息的第三方该些第三方会与我们签订保密协议同时我们会对其数据安全能力与环境进行评估并要求第三方以不低于本隐私政策所要求的保密和安全措施来保护信息</view>
<view> 个人信息的公开披露</view>
<view> 我们不会公开披露您的信息除非遵循国家法律法规规定或者获得您的同意我们公开披露您的个人信息会采用符合行业内标准的安全保护措施</view>
<view> 依法豁免征得同意共享转让公开披露的个人信息</view>
<view> 请您理解在下列情形中根据法律法规及国家标准我们共享转让公开披露您的个人信息无需征得您的授权同意</view>
<view> 1.与国家安全国防安全直接相关的</view>
<view> 2.与公共安全公共卫生重大公共利益直接相关的</view>
<view> 3.与犯罪侦查起诉审判和判决执行等直接相关的</view>
<view> 4.出于维护您或其他个人的生命财产等重大合法权益但又很难得到本人同意的</view>
<view> 5.您自行向社会公众公开的个人信息</view>
<view> 6.从合法公开披露的信息中收集个人信息的如合法的新闻报道政府信息公开等渠道</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 我们如何保护个人信息安全</view>
<view> 我们非常重视您个人信息的安全将努力采取合理的安全措施包括技术方面和管理方面来保护您的个人信息防止您提供的个人信息被不当使用或未经授权的情况下被访问公开披露使用修改损坏丢失或泄漏
</view>
<view> 我们会使用加密技术匿名化处理等合理可行的手段保护您的个人信息并使用安全保护机制防止您的个人信息遭到恶意攻击</view>
<view> 我们会建立专门的安全部门安全管理制度数据安全流程保障您的个人信息安全我们采取严格的数据使用和访问制度确保只有授权人员才可访问您的个人 信息并适时对数据和技术进行安全审计</view>
<view>
尽管已经采取了上述合理有效措施并已经遵守了相关法律规定要求的标准但请您理解由于技术的限制以及可能存在的各种恶意手段在互联网行业即便竭尽所能加强安全措施也不可能始终保证信息百分之百的安全我们将尽力确保您提供给我们的个人信息的安全性您知悉并理解您接入我们的服务所用的系统和通讯网络有可能因我们可控范围外的因素而出现问题因此我们强烈建议您采取积极措施保护个人信息的安全包括但不限于使用复杂密码定期修改密码不将自己的账号密码等个人信息透露给他人
</view>
<view>
我们会制定应急处理预案并在发生用户信息安全事件时立即启动应急预案努力阻止该等安全事件的影响和后果扩大一旦发生用户信息安全事件泄露丢失等我们将按照法律法规的要求及时向您告知安全事件的基本情况和可能的影响我们已经采取或将要采取的处置措施您可自主防范和降低风险的建议对您的补救措施等我们将及时将事件相关情况以推送通知邮件信函短信等形式告知您难以逐一告知时我们会采取合理有效的方式发布公告同时我们还将按照相关监管部门要求上报用户信息安全事件的处置情况
</view>
<view>
我们谨此特别提醒您本隐私政策提供的个人信息保护措施仅适用于泉医到家及相关服务一旦您离开泉医到家及相关服务浏览或使用其他网站服务及内容资源我们即没有能力及义务保护您在泉医到家及相关服务之外的软件网站提交的任何个人信息无论您登录浏览或使用上述软件网站是否基于泉医到家的链接或引导
</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 您的权利</view>
<view> 我们非常重视您对个人信息的管理并尽全力保护您对于您个人信息的查询访问修改删除撤回同意授权在设置页面注销账号投诉举报以及设置隐私功能等权利以使您有能力保障您的隐私和安全</view>
<view> 访问删除更正您的个人信息</view>
<view> 您可以通过以下方式管理您的信息</view>
<view> 1. 访问个人账号信息</view>
<view> 您可以查询访问您的头像用户名简介性别生日地区位置等基本信息身份证个人信息除外您可以在泉医到家的编辑资料中进行查询访问</view>
<view> 2. 查询访问更改删除您的收藏记录清理缓存</view>
<view> 2.1 点击我的点击我的收藏进入查询访问删除</view>
<view> 2.2 您可以通过点击我的设置点击清理缓存</view>
<view> 3. 注销账号</view>
<view> 点击我的点击设置点击账号注销同意账户注销协议并点击确定按钮如需人工处理我们将在核实您的身份之日起15日之内予以处理并回复</view>
<view>
特别提示您注意出于安全性和身份识别如号码申诉服务的考虑您可能无法自主修改注册时提交的某些初始注册信息如您确有需要修改该类注册信息请根据本隐私政策载明的联系方式联系我们我们核查并验证您的用户身份后会在15个工作日内处理并给予回复
</view>
<view> 改变您授权同意范围或撤销授权</view>
<view> 1. 改变或撤回敏感信息权限</view>
<view> 您可以通过更改系统设置以及在设备本身操作系统中关闭地理位置通讯录摄像头麦克风等权限改变同意范围或撤回您的授权</view>
<view> 2. 拒绝接受推送及营销信息</view>
<view> 您可以通过设置关闭推送通知拒绝消息的推送</view>
<view> 请您理解特定的业务功能和服务将需要您的信息才能得以完成当您撤回同意或授权后我们无法继续为您提供撤回同意或授权所对应的功能和服务也不再处理您相应的个人信息</view>
<view> 投诉举报</view>
<view>
您可按照我们公示的制度进行投诉或举报如果您认为您的个人信息权利可能受到侵害或者发现侵害个人信息权利的线索例如认为我们收集您的个人信息违反法律规定或者双方约定您可以通过点击我的进入举报反馈界面与我们联系我们核查后会在15个工作日内反馈您的投诉与举报
</view>
<view> 访问隐私政策</view>
<view> 您可以在我的设置中查看本隐私政策的全部内容</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 未成年人使用条款</view>
<view> 若您是未满18周岁的未成年人且无完全民事行为能力在使用泉医到家及相关服务前应在您的父母或其他监护人监护指导下共同阅读并在征得您父母或者监护人同意的前提下使用我们的服务或向我们提供信息
</view>
<view>
我们根据国家相关法律法规的规定保护未成年人的个人信息只会在法律允许父母或其他监护人明确同意或保护未成年人所必要的情况下收集使用储存共享转让或披露未成年人的个人信息如果我们发现在违背了法律有关规定或未事先获得可证实的父母同意的情况下收集了未成年人的个人信息则会设法尽快删除相关信息
</view>
<view> 若您是未成年人的监护人当您对您所监护的未成年人的个人信息有相关疑问时请通过本隐私政策公示的联系方式与我们联系</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 隐私政策的修订和通知</view>
<view>
为了给您提供更好的服务泉医到家及相关服务将不时更新与变化我们会适时对本隐私政策进行修订这些修订构成本隐私政策的一部分并具有等同于本隐私政策的效力未经您明确同意我们不会削减您依据当前生效的本隐私政策所应享受的权利
</view>
<view> 本隐私政策更新后我们会在泉医到家发出更新版本以便您及时了解本隐私政策的最新版本</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 适用范围</view>
<view> 本隐私政策仅适用于泉医到家客户端不适用于有单独的隐私政策且未纳入本隐私政策的第三方产品或服务</view>
<view> 本隐私权政策不适用于</view>
<view> 1. 其他第三方产品或服务可能包括在推荐中向您显示的产品或网站和广告内容或者泉医到家服务中链接到的其他产品或网站</view>
<view> 2. 泉医到家服务进行广告宣传的其他第三方</view>
<view> 第三方主体可能会通过泉医到家向您提供服务当您进入第三方主体运营的服务界面时请注意相关服务由第三方主体向您提供涉及到第三方主体向您收集信息的建议您仔细查看第三方主体的隐私政策或协议约定</view>
<view> 请您了解本隐私政策中所述的泉医到家及相关服务可能会根据您所使用的手机型号系统版本软件应用程序版本移动客户端等因素而有所不同最终的产品和服务以您所使用的泉医到家软件及相关服务为准</view>
<view style="text-indent: 0em;padding: 10rpx 0;"> 第三方软件开发包SDK个人信息收集情况</view>
<view>
1.地理位置服务当您使用地理位置相关服务时我们会将您的WLAN状态信息定位信息终端设备唯一标识符与位置服务提供商百度地图进行共享以便可以返回您的位置信息并最终向您提供定位服务我们会使用各种技术进行定位包括IP地址GNSS以及能够提供相关信息的其他传感器如可能会为百度提供附近设备WLAN接入点和基站的信息这些个人信息的收集仅会在已获得您的终端设备系统权限允许的前提下进行若您拒绝提供仅会影响地理位置服务功能但不影响其他功能的正常使用
</view>
<view> 以下将详细列出我们的基本服务功能及为实现该功能所需收集的个人信息类型以及与收集个人信息相关的权限</view>
<uni-table border stripe emptyText="">
<uni-tr>
<uni-th>权限类型</uni-th>
<uni-th>功能及服务</uni-th>
<uni-th>权限授权方式</uni-th>
</uni-tr>
<uni-tr>
<uni-td>访问WI-FI状态</uni-td>
<uni-td>获取连接WIFI信息返回至百度定位服务端作为辅助定位依据再返回给开发者更精准的位置信息 </uni-td>
<uni-td> 由设备系统开发方及开发者应用决定当最终用户同意向开发者应用授予该权限时开启</uni-td>
</uni-tr>
<uni-tr>
<uni-td>获取位置</uni-td>
<uni-td>
获取的位置信息可能包括GNSS信息WIFI地址及信号强度信息基站ID数据信息传感器信息手机信号强度信息以便无需最终用户手动输入自身地理坐标就可以给开发者返回最终用户的位置信息
</uni-td>
<uni-td>由设备系统开发方及开发者应用决定当最终用户同意向开发者应用授予该权限时开启</uni-td>
</uni-tr>
</uni-table>
<view style="text-indent: 0em">更多内容请参考百度地图隐私政策链接http://privacy.baidu.com/detail?id=288</view>
<view>
2.分享服务当您使用客户端分享服务时我们会向提供该服务的上海游昆信息技术有限公司以下称MobTech共享您的系统运营网络状态MAC地址国际移动设备识别码IMEI匿名设备标识符(OAID)国际移动用户识别码IMSI应用列表基站信息社交平台OpenID地理位置以确保您的分享功能能够正常使用以上信息将在您授权后收集关于MobTech收集个人信息的保护规则及退出机制等更多内容详见MobTech官网www.mob.com
隐私政策条款https://www.mob.com/about/policy</view>
<uni-table border stripe emptyText="">
<uni-tr>
<uni-th>SDK名称</uni-th>
<uni-th>场景描述</uni-th>
<uni-th>收集个人信息的类型</uni-th>
</uni-tr>
<uni-tr>
<uni-td>MobTechShareSDK</uni-td>
<uni-td>社交分享第三方登录</uni-td>
<uni-td>
系统运营信息网络状态信息MAC地址国际移动设备识别码IMEI匿名设备标识符(OAID)国际移动用户识别码IMSI应用列表信息基站信息社交平台OpenID地理位置
</uni-td>
</uni-tr>
</uni-table>
<view>
3.推送服务当您使用客户端消息推送接收服务时我们会收集您的设备信息网络信息位置信息与推送服务提供商极光进行共享以便您能够正常收到本软件推送的消息此外我们将收集您的推送打开情况等统计数据与推送服务提供商极光共享以协助本软件运营人员分析服务使用情况提供更好的消息推送服务极光收集使用实现服务所必须的个人信息将通过加密通道将消息和通知推送给您
</view>
<view>极光SDK绝不收集或者要求您提供包括但不限于个人种族政治倾向宗教信仰个人基因数据或生物特征数据性取向等个人敏感信息当我们要将收集而来的个人信息用于本政策未载明的其它用途时会事先征求您的同意
</view>
<view>如您拒绝开启消息推送服务以上信息将不会共享给第三方且仅影响消息推送服务功能不影响其他功能的正常使用</view>
<view> 极光SDK收集信息及目的如下</view>
<uni-table border stripe emptyText="">
<uni-tr>
<uni-th>权限类型</uni-th>
<uni-th>内容</uni-th>
<uni-th>目的</uni-th>
</uni-tr>
<uni-tr>
<uni-td>设备信息</uni-td>
<uni-td>设备标识符IMEIIDFAAndroid
IDMACOAID等相关信息应用信息或运行中的进程信息应用崩溃信息通知开关状态软件列表等相关信息设备参数及系统信息设备类型设备型号操作系统及硬件相关信息
</uni-td>
<uni-td>
用于识别唯一用户保证消息推送的精准送达优化推送通道资源我们会根据设备上不同APP的活跃情况整合消息推送的通道资源为开发者提高消息送达率为开发者提供智能标签以及展示业务统计信息的服务
</uni-td>
</uni-tr>
<uni-tr>
<uni-td>网络信息</uni-td>
<uni-td>
</uni-td>
<uni-td>
优化SDK与极光服务器的网络连接请求保证服务的稳定性和连续性</uni-td>
</uni-tr>
<uni-tr>
<uni-td>位置信息</uni-td>
<uni-td></uni-td>
<uni-td>
实现区域推送功能 </uni-td>
</uni-tr>
</uni-table>
<view> 提请您注意并知悉极光 SDK 为实现上述业务功能收集您终端用户设备信 网络信息/位置信息的前提是终端用户授权同意开启 SD
卡权限网络访问权限设备信息权限/位置权限 如果您的终端用户不想被收集上述信息可以通过关闭读写 SD 卡权限 络访问权限设备信息权限/位置权限实现</view>
<view style="text-indent: 0em"> 更多内容请参考极光隐私政策链接https://www.jiguang.cn/license/privacy</view>
<view>4.分析统计 : 为分析产品与服务的使用情况提升用户使用的体验我们会与移动应用统计服务商友盟统计共享产品使用情况打开闪退崩溃的统计性数据以及硬件
型号操作系统版本号网络设备硬件地址软件版本号网络信息启动来源 使用时长地理位置访问路经等统计性数据这些数据难以与其他信息结合识 别您的个人身份将通过加密技术传输我们不会在您同意隐私协议并同意获取
相应数据前分享给相应 SDK</view>
<view> 各项业务功能对系统隐私权限的调用将在经过您的授权后开启您可 以随时在系统中取消授权取消授权会导致您无法使用相关业务功能 但不会导致最终用户无法使用其他业务功能的使用</view>
<view> +SDK 需要收集您的唯一设备识别码 IMEI/android ID/IDFA/OPENUDID/GUIDSIM IMSI
信息您安装的应用信息或运行中的进程信息无法通过唯一设备识别码标识设备的特殊情况下如您使用平板设备或电视盒子时 集设备 Mac 地址作为用户唯一标识以提供统计分析服务并获取您的 位置信息及 IP
地址校准用户地域分布数据提供基础反作弊能力</view>
<view style="text-indent: 0;">具体获取权限及其用途列表如下</view>
<view class="" style="width: 100%;">
<uni-table border stripe emptyText="">
<uni-tr>
<uni-th>权限</uni-th>
<uni-th>用途</uni-th>
</uni-tr>
<uni-tr>
<uni-td> ACCESS_NETWORK_STATE</uni-td>
<uni-td>检测联网方式在网络异常状态下避免数据发送节省流量和电量</uni-td>
</uni-tr>
<uni-tr>
<uni-td>READ_PHONE_STATE</uni-td>
<uni-td>获取用户设备的 IMEI通过 IMEI 对用户进行唯一标识以便提供统计分析服务</uni-td>
</uni-tr>
<uni-tr>
<uni-td>ACCESS_WIFI_STATE </uni-td>
<uni-td> 获取 WIFI mac 地址在平板设备或电视盒子上无法通过 IMEI 标识设备我们会将 WIFI mac 地址作为用户的唯一标识以便正
常提供统计分析服务</uni-td>
</uni-tr>
<uni-tr>
<uni-td>INTERNET</uni-td>
<uni-td>
允许应用程序联网和发送统计数据的权限以便提供统计分析服务
</uni-td>
</uni-tr>
<uni-tr>
<uni-td>ACCESS_FINE_LOCATION可选) </uni-td>
<uni-td>
通过获取位置信息为开发者提供反作弊功能剔除作弊设备 同时校正用户的地域分布数据使报表数据更加准确
</uni-td>
</uni-tr>
<uni-tr>
<uni-td>ACCESS_COARSE_LOCATION可选</uni-td>
<uni-td>
通过获取位置信息为开发者提供反作弊功能剔除作弊设备 同时校正用户的地域分布数据使报表数据更加准确
</uni-td>
</uni-tr>
</uni-table>
</view>
<view> 友盟 SDK 安全能力通过</view>
<view> 公安部三级等保认证非银机构最高安全等级</view>
<view> ISO27001 信息安全管理体系认证</view>
<view> ISO27018 公有云个人信息保护体系认证</view>
<view> 更多内容请参考友盟隐私政策链接https://www.umeng.com/page/policy</view>
<view>
5.语音服务当您使用客户端语音搜索服务时我们会向提供该服务的科大讯飞股份有限公司以下称讯飞共享您的设备标识信息地理位置信息以确保您的语音功能能够正常使用以上信息将在您授权后收集关于讯飞收集个人信息的保护规则及退出机制等更多内容详见讯飞官网隐私政策页面https://www.xfyun.cn/doc/policy/privacy.html
</view>
<view style="text-indent: 0; padding: 20rpx 0;"> 十一联系我们</view>
<view> 1.如果您对个人信息保护问题有投诉建议疑问您可通过登录泉医到家客户端内的举报反馈页面与我们联系我们核查并验证您的用户身份后会在15个工作日内反馈您的投诉与举报 </view>
<view> 2.如对本隐私政策内容有任何疑问意见或建议您也可通过登录泉医到家客户端内的举报反馈页面与我们联系</view>
<view> 3.APP运营单位山东新医路信息科技有限公司地址山东省济南市槐荫区经十路22799号银座中心2号楼1608室 联系电话0558-69900398</view>
<view></view>
<view></view>
<view></view>
</view>
</template>
<script>
</script>
<style>
</style>

View File

@ -0,0 +1,49 @@
<template>
<view class="" style="background-color: #F4F5F7;">
<Signature @init="onSignInit" style='background-color: #fff;'></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'>
.btns {
margin-top: 50rpx;
display: flex;
}
button {
width: 30%;
}
</style>

60
pages/startup/startup.vue Normal file
View File

@ -0,0 +1,60 @@
<template>
<view class="app">
<image src="../../static/logo.png" mode=""></image>
<view class="title">
泉医到家
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
export default {
data() {
return {};
},
onShow() {
this.info()
},
methods: {
info() {
setTimeout(() => {
uni.reLaunch({
url: '/pages/homepage/homepage',
})
}, 2000);
// const value = uni.getStorageSync('phonenumber');
// const value2 = uni.getStorageSync('password');
// if (value && value2) {} else {}
}
},
}
</script>
<style lang="scss">
.app {
height: 100vh;
background-color: #fff;
}
image {
width: 50%;
height: 400rpx;
position: absolute;
left: 25%;
top: 28%;
}
.title {
width: 80%;
height: 48rpx;
font-size: 49rpx;
text-align: center;
font-family: DengXian;
font-weight: bold;
color: #000000;
position: absolute;
top: 50%;
left: 10%;
}
</style>

View File

@ -0,0 +1,120 @@
.app {
padding: 0;
height: 100vh;
padding: 3%;
.img{
line-height: 90rpx;
view{
font-size: 32rpx;
padding: 20rpx 0;
}
image{
width: 100%;
height: 700rpx;
}
}
.details {
width: 100%;
height: 250rpx;
background: #FFFFFF;
box-shadow: 0rpx 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20rpx;
margin: 0 auto;
position: relative;
image {
width: 170rpx;
height: 170rpx;
border-radius: 10rpx;
margin: 20rpx 0 0 30rpx;
}
.detailsinfo {
width: 60%;
height: 200rpx;
border-radius: 10rpx;
position: absolute;
top: 12%;
left: 35%;
.change {
width: 100%;
color: #000000;
font-size: 34rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.time {
width: 100%;
font-size: 32rpx;
color: #999999;
position: absolute;
top: 32%;
}
.price {
width: 100%;
font-size: 30rpx;
color: #D43953;
position: absolute;
top: 65%;
}
}
}
.info {
width: 100%;
background: #FFFFFF;
box-shadow: 0px 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20rpx;
position: relative;
top: 20rpx;
.item {
line-height: 110rpx;
border-bottom: 1rpx solid #D8D4D4;
font-size: 32rpx;
color: #000000;
margin-left: 30rpx;
}
}
.submit {
width: 100%;
height: 100rpx;
height: 68rpx;
font-size: 32rpx;
color: #FFFFFF;
text-align: center;
position: fixed;
bottom: 80rpx;
// background-color: red;
left: 15%;
// padding: 20rpx;
.return {
width: 216rpx;
height: 68rpx;
background: #E1AE3C;
border-radius: 26rpx;
line-height: 68rpx;
display: inline-block;
}
.finish {
width: 217rpx;
height: 68rpx;
line-height: 68rpx;
background: #4C7BC9;
border-radius: 26rpx;
display: inline-block;
margin-left: 30rpx;
}
}
}

View File

@ -0,0 +1,100 @@
<template>
<view class="app">
<view class="details">
<image :src="baseurl+list.itemPictureUrl" mode=""></image>
<view class="detailsinfo">
<view class="change">
{{list.nurseItemName}}
</view>
<view class="time">
服务时长 {{list.itemServeDurationUnit}}
</view>
<view class="price">
{{list.totalPrice}}
</view>
</view>
</view>
<view class="info">
<view class="item">
姓名 {{list.patientName}}
</view>
<view class="item">
电话{{list.phone}}
</view>
<view class="item" style="border:none;line-height: 60rpx;padding: 20rpx 0;">
地址{{list.serviceAddress}}
</view>
</view>
<view class="img" v-if="list.orderStatus=='COMPLETE'||list.orderStatus=='EVALUATED'">
<view class="">
护理员到岗照片
</view>
<image :src="baseurl+list.onDutyPictureUrl" mode=""></image>
</view>
<view class="img" v-if="list.orderStatus=='COMPLETE'||list.orderStatus=='EVALUATED'">
<view class="" >
服务结束照片
</view>
<image :src="baseurl+list.serviceEndPictureUrl" mode=""></image>
</view>
<view class="img" v-if="list.orderStatus=='COMPLETE'||list.orderStatus=='EVALUATED'">
<view class="">
签名
</view>
<image :src="baseurl+list.userSignaturePictureUrl" mode=""></image>
</view>
<view class="submit">
<view class="return" @tap='goreturn' v-if="list.orderStatus=='NOT_FINISH'">
任务退回
</view>
<view class="finish" @tap='gocomplete' v-if="list.orderStatus=='NOT_FINISH'">
去完成
</view>
</view>
</view>
</template>
<script>
import {
taskDetails
} from '@/api/taskDetails.js'
import baseurl from '@/api/baseurl.js'
export default {
data() {
return {
baseurl: '',
list: {},
orderDetailsId: null,
}
},
methods: {
//
taskDetailsinfo(orderDetailsId) {
taskDetails(orderDetailsId).then(res => {
this.list = res.data
})
},
goreturn() {
uni.navigateTo({
url: `/pages/taskReturn/taskReturn?orderNo=${this.list.orderNo}`
})
},
gocomplete() {
uni.navigateTo({
url: `/pages/confirmCompletion/confirmCompletion?orderDetailsId=${this.list.orderDetailsId}&orderNo=${this.list.orderNo}`
})
},
},
onLoad(options) {
this.baseurl = baseurl
this.orderDetailsId = options.orderDetailsId
},
onShow() {
this.taskDetailsinfo(this.orderDetailsId)
},
}
</script>
<style lang="scss">
@import './taskDetails.scss';
</style>

View File

@ -0,0 +1,99 @@
<template>
<view class="app">
<view class="return">
<view class="reason">
退回原因
</view>
<view class="reason" style="border: none;margin: 20rpx 0 0 50rpx;">
<input type="text" placeholder="请填写" v-model="taskReturnReason" />
</view>
</view>
<view class="submit">
<view class="finish" @tap='taskreturn'>
确定
</view>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
orderFallback
} from '@/api/taskReturn/index.js'
export default {
data() {
return {
orderNo: null,
taskReturnReason: null,
}
},
methods: {
taskreturn() {
orderFallback(this.orderNo, this.taskReturnReason).then(res => {
this.$refs.uToast.show({
title: '任务退回成功',
type: 'success',
duration: '1500'
})
setTimeout(() => {
uni.navigateBack({
delta: 1
})
}, 1500);
})
},
},
onLoad(options) {
this.orderNo = options.orderNo
},
}
</script>
<style lang="scss">
.app {
padding: 0;
// font-size: 35rpx;
height: 100vh;
padding: 3%;
.return {
width: 98%;
height: 342rpx;
background: #FFFFFF;
box-shadow: 0px 9rpx 31rpx 9rpx rgba(0, 0, 0, 0.03);
border-radius: 20rpx;
margin: 0 auto;
.reason {
width: 93%;
height: 80rpx;
font-size: 30rpx;
color: #030303;
line-height: 80rpx;
border-bottom: 1rpx solid #D8D4D4;
margin: 0 auto;
}
}
.submit {
height: 68rpx;
font-size: 32rpx;
color: #FFFFFF;
text-align: center;
position: fixed;
bottom: 80rpx;
left: 60%;
.finish {
width: 217rpx;
height: 68rpx;
line-height: 68rpx;
background: #4C7BC9;
border-radius: 26rpx;
margin-left: 30rpx;
}
}
}
</style>

BIN
static/1024.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
static/autograph.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/detailed.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
static/dingdan.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
static/evaluated.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
static/finished.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
static/gb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
static/headportrait.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
static/home.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
static/home1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
static/homepagew.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
static/homepagews.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
static/jiantou.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
static/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
static/noorder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
static/order.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
static/person.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
static/pic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

BIN
static/radio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
static/rowsright.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 638 B

BIN
static/shopping.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
static/sousuo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/users.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
static/userw.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
static/v-sign/clear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

BIN
static/v-sign/next.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
static/v-sign/prev.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
static/v-sign/save.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

77
uni.scss Normal file
View File

@ -0,0 +1,77 @@
/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场https://ext.dcloud.net.cn上很多三方插件均使用了这些样式变量
* 如果你是插件开发者建议你使用scss预处理并在插件代码中直接使用这些变量无需 import 这个文件方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者插件使用者你可以通过修改这些变量来定制自己的插件主题实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理你也可以直接在你的 scss 代码中使用如下变量同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
@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:16;
/* 图片尺寸 */
$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;