初始化仓库
117
.gitignore
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Microbundle cache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
.cache/
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
package-lock.json
|
||||
16
.hbuilderx/launch.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
|
||||
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
|
||||
"version": "0.0",
|
||||
"configurations": [{
|
||||
"default" :
|
||||
{
|
||||
"launchtype" : "local"
|
||||
},
|
||||
"mp-weixin" :
|
||||
{
|
||||
"launchtype" : "local"
|
||||
},
|
||||
"type" : "uniCloud"
|
||||
}
|
||||
]
|
||||
}
|
||||
144
App.vue
Normal file
@@ -0,0 +1,144 @@
|
||||
<template>
|
||||
<view></view>
|
||||
</template>
|
||||
<script>
|
||||
import {
|
||||
info,
|
||||
personalData,
|
||||
leadInfo,
|
||||
servInfo,
|
||||
} from "@/api/all.js"
|
||||
export default {
|
||||
onLaunch() {
|
||||
// 获取小程序更新机制兼容
|
||||
if (uni.canIUse('getUpdateManager')) {
|
||||
const updateManager = uni.getUpdateManager()
|
||||
// 检查是否有新版本发布
|
||||
updateManager.onCheckForUpdate(function(res) {
|
||||
if (res.hasUpdate) {
|
||||
//小程序有新版本,则静默下载新版本,做好更新准备
|
||||
updateManager.onUpdateReady(function() {
|
||||
uni.showModal({
|
||||
title: '更新提示',
|
||||
content: '新版本已经准备好,是否重启应用?',
|
||||
success: function(res) {
|
||||
if (res.confirm) {
|
||||
//新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate()
|
||||
} else if (res.cancel) {
|
||||
//如果需要强制更新,则给出二次弹窗,如果不需要,则这里的代码都可以删掉了
|
||||
uni.showModal({
|
||||
title: '温馨提示',
|
||||
content: '我们已经做了新的优化,请及时更新哦~',
|
||||
showCancel: false, //隐藏取消按钮,也可显示,取消会走res.cancel,然后从新开始提示
|
||||
success: function(res) {
|
||||
//第二次提示后,强制更新
|
||||
if (res.confirm) {
|
||||
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate()
|
||||
uni.clearStorageSync()
|
||||
} else if (res.cancel) {
|
||||
//重新回到版本更新提示
|
||||
autoUpdate()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
// 新的版本下载失败
|
||||
updateManager.onUpdateFailed(function() {
|
||||
uni.showModal({
|
||||
title: '温馨提示',
|
||||
content: '新版本已经上线,请您删除当前小程序,重新搜索打开',
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 提示用户在最新版本的客户端上体验
|
||||
uni.showModal({
|
||||
title: '温馨提示',
|
||||
content: '当前微信版本过低,可能无法使用该功能,请升级到最新版本后重试。'
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if (uni.getStorageSync('token')) {
|
||||
this.getInfo()
|
||||
}
|
||||
},
|
||||
onShow: function() {},
|
||||
onHide: function() {
|
||||
// this.$store.dispatch('closeWebSocket')
|
||||
},
|
||||
methods: {
|
||||
async getInfo() {
|
||||
let role = uni.getStorageSync('identity')
|
||||
let req = {};
|
||||
const data = {
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
}
|
||||
role == 1 && (req = await info(data))
|
||||
role == 2 && (req = await personalData(data))
|
||||
if (req.errcode == 0) {
|
||||
console.log(req, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
||||
// 未完善信息
|
||||
if (req.data.user.status == 3) {
|
||||
// this.$toast('您还没有完善信息,请先完善信息')
|
||||
// this.$go('../../subPackages/sub_workbench/workbench_upInfo/index')
|
||||
uni.navigateTo({
|
||||
url: '/pages/workbench/examine'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (role == 2 && req.data.user.status == 2) {
|
||||
let logInfo = uni.getStorageSync('logInfo') || {}
|
||||
let userInfo = {
|
||||
...logInfo,
|
||||
...(uni.getStorageSync('userInfo') || {}),
|
||||
...req.data
|
||||
}
|
||||
userInfo.status = userInfo.user && userInfo.user.status != '' ? userInfo.user.status : userInfo
|
||||
.status
|
||||
|
||||
uni.setStorageSync('identity', userInfo['role'])
|
||||
uni.removeStorageSync('logInfo')
|
||||
uni.setStorageSync('userInfo', userInfo)
|
||||
setTimeout(() => {
|
||||
console.log('mainnnnnnnnnnnnnnnnnnnnnnnn');
|
||||
role == 2 && this.$go('/pages/pharmacist/index', 3)
|
||||
}, 100)
|
||||
}
|
||||
|
||||
if (role == 1 && req.data.DoctorInfo.user.status == 2) {
|
||||
let logInfo = uni.getStorageSync('logInfo') || {}
|
||||
let userInfo = {
|
||||
...logInfo,
|
||||
...(uni.getStorageSync('userInfo') || {}),
|
||||
...req.data
|
||||
}
|
||||
userInfo.status = userInfo.user && userInfo.user.status != '' ? userInfo.user.status : userInfo
|
||||
.status
|
||||
|
||||
uni.setStorageSync('identity', userInfo['role'])
|
||||
uni.removeStorageSync('logInfo')
|
||||
uni.setStorageSync('userInfo', userInfo)
|
||||
setTimeout(() => {
|
||||
console.log('mainnnnnnnnnnnnnnnnnnnnnnnn');
|
||||
role == 1 && this.$go('/pages/workbench/index', 3)
|
||||
}, 100)
|
||||
}
|
||||
} else {
|
||||
this.$toast(req.msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import "uview-ui/index.scss";
|
||||
@import "common/css/app.css";
|
||||
</style>
|
||||
1728
api/all.js
Normal file
138
api/consult.js
Normal file
@@ -0,0 +1,138 @@
|
||||
// 咨询相关接口
|
||||
import {
|
||||
req
|
||||
} from '@/common/js/index.js';
|
||||
|
||||
/*接诊
|
||||
order_id int 是 订单id
|
||||
*/
|
||||
export function imageOrderAccess(data) {
|
||||
return req.request({
|
||||
url: 'image-order/access',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 结束问诊 https://app.xiaokang88.com/service/v1/store-accept/register-over
|
||||
export function accessEnd(data) {
|
||||
return req.request({
|
||||
url: 'store-accept/register-over',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/*退诊
|
||||
order_id int 是 订单id
|
||||
reason_id int 是 退针原因id
|
||||
*/
|
||||
export function imageOrderRefuse(data) {
|
||||
return req.request({
|
||||
url: 'image-order/refuse',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/*退诊原因
|
||||
*/
|
||||
export function RefuseReason(data) {
|
||||
return req.request({
|
||||
url: 'store-accept/refuse-list',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/*患者详情
|
||||
order_id int 是 订单id
|
||||
*/
|
||||
export function imageOrderPatientInfo(data) {
|
||||
return req.request({
|
||||
url: 'image-order/patient-info',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/*患者详情
|
||||
patient_id int 是 患者id
|
||||
*/
|
||||
export function storePatientInfo(data) {
|
||||
return req.request({
|
||||
url: 'store-accept/patient-detail',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/*患者详情 接诊/拒诊
|
||||
patient_id int 是 患者id status 1接诊2拒绝
|
||||
*/
|
||||
export function storePatientRefuse(data) {
|
||||
return req.request({
|
||||
url: 'store-accept/accept-or-refuse',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/*咨询详情
|
||||
order_id int 是 订单id
|
||||
*/
|
||||
export function imageOrderInfo(data) {
|
||||
return req.request({
|
||||
url: 'image-order/info',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/*咨询列表 挂号列表
|
||||
order_id int 是 订单id
|
||||
*/
|
||||
export function registerList(data) {
|
||||
return req.request({
|
||||
url: 'register/list',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
// 咨询列表角标
|
||||
/**
|
||||
* @param {Object} data
|
||||
* 参数名称 必须 参数类型 说明
|
||||
*/
|
||||
export function listMain(data) {
|
||||
return req.request({
|
||||
url: 'image-order/list-main',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
/*服务端发送消息
|
||||
ims_id int 是 会话id
|
||||
session_type int 是 会话类型1医生发给用户3导医发给用户5医生和客服会话6药师和客服7导医和客服
|
||||
content json 是 消息内容
|
||||
*/
|
||||
export function messageSend(data) {
|
||||
return req.request({
|
||||
url: 'im/message-send',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
/*会话消息记录
|
||||
ims_id int 是 会话id
|
||||
page int 否 1 页码
|
||||
page_size int 否 20 每页条数
|
||||
*/
|
||||
export function messageList(data) {
|
||||
return req.request({
|
||||
url: 'im/message-list',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
164
common/common.js
Normal file
@@ -0,0 +1,164 @@
|
||||
import $store from '@/store/index.js';
|
||||
import {
|
||||
registerList,
|
||||
} from '@/api/consult.js'
|
||||
class common {
|
||||
constructor(arg) {
|
||||
this.timer = null
|
||||
this.url = arg.url
|
||||
this.isOnline = false //是否在线
|
||||
this.socket = null //socket对象
|
||||
this.reconnectTime = 0
|
||||
this.isOpenReconnect = true //是否重连
|
||||
this.loadFinish = false;
|
||||
// 获取当前用户相关信息
|
||||
let user = uni.getStorageSync('userInfo')
|
||||
this.user_token = uni.getStorageSync('token')
|
||||
this.user = user ? user : {}
|
||||
// 初始化聊天对象
|
||||
this.TO = false;
|
||||
// 连接和监听
|
||||
if (this.user) {
|
||||
this.connectSocket()
|
||||
}
|
||||
}
|
||||
// 断线重连
|
||||
reconnect() {
|
||||
console.log(this.isOnline)
|
||||
console.log("进入reconnect准备重新链接")
|
||||
if (this.isOnline) {
|
||||
return
|
||||
}
|
||||
if (this.reconnectTime >= 3) {
|
||||
return this.reconnectConfirm()
|
||||
}
|
||||
this.reconnectTime += 1
|
||||
console.log("重新链接")
|
||||
// this.connectSocket();
|
||||
|
||||
}
|
||||
// 连接socket
|
||||
connectSocket() {
|
||||
console.log("链接connectSocket")
|
||||
this.socket = uni.connectSocket({
|
||||
url: this.url,
|
||||
header: {
|
||||
authorization: `Bearer ${uni.getStorageSync('token')}`
|
||||
},
|
||||
method: 'POST',
|
||||
complete: () => {}
|
||||
})
|
||||
// 监听连接成功
|
||||
this.socket.onOpen && this.socket.onOpen(() => this.onOpen())
|
||||
// 监听接收信息
|
||||
this.socket.onMessage && this.socket.onMessage((res) => this.onMessage(res))
|
||||
// 监听断开
|
||||
this.socket.onClose && this.socket.onClose((e) => this.onClose(e))
|
||||
// 监听错误
|
||||
this.socket.onError && this.socket.onError(() => this.onError())
|
||||
}
|
||||
onOpen() {
|
||||
// 用户上线
|
||||
console.log('websocket连接成功')
|
||||
this.isOnline = true
|
||||
this.isOpenReconnect = true
|
||||
console.log(this.url, 'doctor');
|
||||
console.log(this.user, 'user')
|
||||
// 获取用户离线消息
|
||||
if (this.socket != null) {
|
||||
var login = {
|
||||
cmd: 'login',
|
||||
userId: Number(this.user.su_id),
|
||||
imStatus: Number(this.user.im_status),
|
||||
userType: Number(this.user.role),
|
||||
data: ''
|
||||
};
|
||||
this.initSocketLogin(login);
|
||||
}
|
||||
}
|
||||
// 监听关闭
|
||||
onClose(e) {
|
||||
// 用户下线
|
||||
this.isOnline = false
|
||||
this.socket = null
|
||||
console.log('socket连接已关闭:' + e)
|
||||
if (this.isOpenReconnect) {
|
||||
var that = this;
|
||||
setTimeout(function() {
|
||||
that.reconnect();
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
// 监听连接错误
|
||||
onError() {
|
||||
// 用户下线
|
||||
this.isOnline = false
|
||||
this.socket = null
|
||||
console.log('socket连接错误:' + e)
|
||||
if (!this.socket) {
|
||||
var that = this;
|
||||
setTimeout(function() {
|
||||
that.reconnect();
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
// 监听接收消息
|
||||
onMessage(data) {
|
||||
console.log('监听接收消息:' + data);
|
||||
// let res = JSON.parse(data.data)
|
||||
// uni.$emit('onMessage', res)
|
||||
}
|
||||
// 关闭连接
|
||||
close() {
|
||||
if (this.socket) {
|
||||
this.socket.close()
|
||||
this.isOpenReconnect = false
|
||||
} else if (uni.onSocketClose) {
|
||||
uni.onSocketClose()
|
||||
this.isOpenReconnect = false
|
||||
}
|
||||
this.destoryChatObject();
|
||||
}
|
||||
initSocketLogin(login) {
|
||||
this.socket.send({
|
||||
data: JSON.stringify(login),
|
||||
success() {
|
||||
console.log('用户IM登录成功:success')
|
||||
},
|
||||
fail(e) {
|
||||
console.log('用户IM登录失败fail:' + e)
|
||||
}
|
||||
})
|
||||
// setTimeout(() => {
|
||||
// this.socket.send({
|
||||
// data: JSON.stringify({
|
||||
// data: '发送内容是:测试测试测试',
|
||||
// }),
|
||||
// })
|
||||
// }, 4000)
|
||||
}
|
||||
// 创建聊天对象
|
||||
createChatObject(detail) {
|
||||
this.TO = detail
|
||||
}
|
||||
// 销毁聊天对象
|
||||
destoryChatObject() {
|
||||
this.TO = false
|
||||
}
|
||||
// 断线重连提示
|
||||
reconnectConfirm() {
|
||||
// this.close()
|
||||
// this.connectSocket()
|
||||
// this.reconnectTime = 0
|
||||
}
|
||||
// 验证是否上线
|
||||
checkOnline() {
|
||||
if (!this.isOnline) {
|
||||
// 断线重连提示
|
||||
this.reconnectConfirm()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
export default common
|
||||
482
common/css/app.css
Normal file
@@ -0,0 +1,482 @@
|
||||
/* 安全区域距离顶部边界距离 */
|
||||
|
||||
.safe-area-inset-top {
|
||||
padding-top: 0 !important;
|
||||
padding-top: constant(safe-area-inset-top) !important;
|
||||
padding-top: env(safe-area-inset-top) !important;
|
||||
}
|
||||
|
||||
.safe-area-inset-bottom {
|
||||
padding-bottom: 0 !important;
|
||||
padding-bottom: constant(safe-area-inset-bottom) !important;
|
||||
padding-bottom: env(safe-area-inset-bottom) !important;
|
||||
}
|
||||
|
||||
.flex-con {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.main-c {
|
||||
color: #0D111A !important
|
||||
}
|
||||
|
||||
.light-c {
|
||||
color: #1E293B !important
|
||||
}
|
||||
|
||||
.content-c {
|
||||
color: #31353D !important
|
||||
}
|
||||
|
||||
.tips-c {
|
||||
color: #6C7380 !important
|
||||
}
|
||||
|
||||
.error-c {
|
||||
color: #F44336 !important
|
||||
}
|
||||
|
||||
.primary-c {
|
||||
color: #2979FF !important
|
||||
}
|
||||
|
||||
.w-c {
|
||||
color: white !important
|
||||
}
|
||||
|
||||
.fs-2 {
|
||||
font-size: 20rpx !important
|
||||
}
|
||||
|
||||
.fs-24 {
|
||||
font-size: 24rpx !important
|
||||
}
|
||||
|
||||
.fs-28 {
|
||||
font-size: 28rpx !important
|
||||
}
|
||||
|
||||
.fs-3 {
|
||||
font-size: 30rpx !important
|
||||
}
|
||||
|
||||
.fs-32 {
|
||||
font-size: 32rpx !important
|
||||
}
|
||||
|
||||
.fs-36 {
|
||||
font-size: 36rpx !important
|
||||
}
|
||||
|
||||
.fs-4 {
|
||||
font-size: 40rpx !important
|
||||
}
|
||||
|
||||
.fs-44 {
|
||||
font-size: 44rpx !important
|
||||
}
|
||||
|
||||
.fs-48 {
|
||||
font-size: 48rpx !important
|
||||
}
|
||||
|
||||
.ff_pfsc {
|
||||
font-family: 'PingFang SC' !important;
|
||||
}
|
||||
|
||||
.fw-700 {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
||||
/* 竖直排列 */
|
||||
|
||||
.flex-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
/* 水平排列 */
|
||||
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.flex-nowrap {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.flex-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.flex-1 {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.flex-jus-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.flex-jus-sp {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.flex-jus-sa {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.flex-jus-se {
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.flex-jus-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.flex-jus-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.flex-ali-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flex-ali-end {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.flex-ali-start {
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.flex-ali-baseline {
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
.grid-tem-col-2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.grid-tem-col-3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.vain-btn {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
border: none !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.vain-btn::after {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.m-l-1 {
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.m-l-12 {
|
||||
margin-left: 12rpx;
|
||||
}
|
||||
|
||||
.m-r-16 {
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.m-l-16 {
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
.m-l-2 {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.m-r-2 {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.m-r08 {
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.m-l-24 {
|
||||
margin-left: 24upx;
|
||||
}
|
||||
|
||||
.m-l-32 {
|
||||
margin-left: 32rpx;
|
||||
}
|
||||
|
||||
.m-l-4 {
|
||||
margin-left: 40rpx;
|
||||
}
|
||||
|
||||
.m-l-48 {
|
||||
margin-left: 48rpx;
|
||||
}
|
||||
|
||||
.m-b-16 {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.m-b-2 {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.m-b-32 {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.m-b-48 {
|
||||
margin-bottom: 48rpx;
|
||||
}
|
||||
|
||||
.m-l-8 {
|
||||
margin-left: 80rpx;
|
||||
}
|
||||
|
||||
.m-t08 {
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.p-col-08 {
|
||||
padding: 8rpx 0;
|
||||
}
|
||||
|
||||
.m-t-1 {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.m-t-12 {
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.m-t-16 {
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.m-t-2 {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.m-t-3 {
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.m-t-32 {
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.m-t-50 {
|
||||
margin-top: 50rpx;
|
||||
}
|
||||
|
||||
.m-t-4 {
|
||||
margin-top: 40rpx;
|
||||
}
|
||||
|
||||
.m-t-48 {
|
||||
margin-top: 48rpx;
|
||||
}
|
||||
|
||||
.m-t-8 {
|
||||
margin-top: 80rpx;
|
||||
}
|
||||
|
||||
.m-t-32 {
|
||||
margin-top: 32rpx;
|
||||
}
|
||||
|
||||
.m-t-24 {
|
||||
margin-top: 24rpx;
|
||||
}
|
||||
|
||||
.p-col-32 {
|
||||
padding: 32rpx 0;
|
||||
}
|
||||
|
||||
.p-col-12 {
|
||||
padding: 12rpx 0;
|
||||
}
|
||||
|
||||
.p-col-16 {
|
||||
padding: 16rpx 0;
|
||||
}
|
||||
|
||||
.p-col-2 {
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.p-row-16 {
|
||||
padding: 0 16rpx;
|
||||
}
|
||||
|
||||
.p-16 {
|
||||
padding: 16rpx;
|
||||
}
|
||||
|
||||
.p-row-32 {
|
||||
padding: 0 32rpx;
|
||||
}
|
||||
|
||||
.p-row-48 {
|
||||
padding: 0 48rpx;
|
||||
}
|
||||
|
||||
.p-row-52 {
|
||||
padding: 0 52rpx;
|
||||
}
|
||||
|
||||
.p-t-32 {
|
||||
padding-top: 32rpx;
|
||||
}
|
||||
|
||||
.p-32 {
|
||||
padding: 32rpx;
|
||||
}
|
||||
|
||||
.p-t-0 {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.p-2 {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.p-col-4 {
|
||||
padding: 40rpx 0;
|
||||
}
|
||||
|
||||
.white {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.bg {
|
||||
background-color: #F9FAFB;
|
||||
}
|
||||
|
||||
.p-row-2 {
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.b-r-8 {
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
.b-r-16 {
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.full-height {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
.seperator {
|
||||
width: 1px;
|
||||
background-color: #F7F6F6;
|
||||
}
|
||||
|
||||
.seperator-h {
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: #F7F6F6;
|
||||
}
|
||||
|
||||
.bottom-border {
|
||||
border-bottom: 1px solid #F7F8FA;
|
||||
}
|
||||
|
||||
.bottom-col-border {
|
||||
border-top: 1px solid #000;
|
||||
border-bottom: 1px solid #000;
|
||||
}
|
||||
|
||||
.b-r-half {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
||||
/* 字体超出一行显示省略号 ,宽度自行设置,不支持多行*/
|
||||
|
||||
.text-hide {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.text-cut {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.text-twoline {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.btn-none {
|
||||
padding: 0 !important;
|
||||
border: none !important;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.btn-none::after {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.size-32 {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
|
||||
.text-align-justify {
|
||||
text-align-last: justify !important;
|
||||
-ms-text-align-last: justify !important;
|
||||
-moz-text-align-last: justify !important
|
||||
}
|
||||
|
||||
.text-align-start {
|
||||
text-align-last: start !important;
|
||||
-ms-text-align-last: start !important;
|
||||
-moz-text-align-last: start !important
|
||||
}
|
||||
|
||||
.text-align-end {
|
||||
text-align-last: end !important;
|
||||
-ms-text-align-last: end !important;
|
||||
-moz-text-align-last: end !important;
|
||||
}
|
||||
|
||||
.text-align-cen {
|
||||
text-align: center !important;
|
||||
}
|
||||
|
||||
.box-border {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.box-content {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.min-w-140 {
|
||||
min-width: 140rpx;
|
||||
}
|
||||
917
common/getPingYin.js
Normal file
53
common/js/common.js
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
export async function requestConfig(ins, options, successHandler = null, failHandler = null, completeHandler = null){
|
||||
// base
|
||||
ins.header = options.header || ins.header
|
||||
//原来是:ins.baseUrl = options.baseUrl || ins.baseUrl
|
||||
let baseUrl = options.baseUrl || ins.baseUrl;
|
||||
// config base
|
||||
let config = {
|
||||
url:`${baseUrl}${options.url?options.url:''}`,
|
||||
header:ins.header
|
||||
}
|
||||
if(ins.requestInterceptor){
|
||||
let _cg = null
|
||||
// 合并请求拦截器配置
|
||||
try {
|
||||
_cg = await ins.requestInterceptor(Object.assign({}, options, config))
|
||||
} catch (e){
|
||||
return false
|
||||
}
|
||||
// config为false或null return
|
||||
if(!_cg || typeof _cg !== 'object'){
|
||||
return false
|
||||
}
|
||||
// 更新options
|
||||
Object.assign(options, _cg)
|
||||
config.url = options.url
|
||||
config.header = options.header
|
||||
}
|
||||
const type = options.type || "request"
|
||||
// config 详情 如果options没有直接使用,删除props
|
||||
if(type === "request"){
|
||||
config["data"] = options.data || options.params || {}
|
||||
config["method"] = options.method || "GET"
|
||||
config["dataType"] = options.dataType || "json"
|
||||
config["responseType"] = options.responseType || "text"
|
||||
config['sslVerify'] = false
|
||||
}else if(type === "upload"){
|
||||
config["filePath"] = options.filePath
|
||||
config["name"] = options.name
|
||||
config["method"] = options.method || "POST"
|
||||
config["formData"] = options.formData
|
||||
// fileType for alipay
|
||||
config["fileType"] = options.fileType || "image"
|
||||
config['sslVerify'] = false
|
||||
// 强制删除 Content-Type
|
||||
delete config.header["Content-Type"]
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
function _isPromise(obj) {
|
||||
return obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
|
||||
}
|
||||
7
common/js/errorCode.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export default {
|
||||
'500':'服务器错误',
|
||||
'405': '资源被禁止',
|
||||
'404': '操作失败',
|
||||
'401': '无效的登录,或者登录已过期,请重新登录。',
|
||||
'default': '未知错误'
|
||||
}
|
||||
384
common/js/handwriting.js
Normal file
@@ -0,0 +1,384 @@
|
||||
export default class {
|
||||
// 内置数据
|
||||
ctx = '';
|
||||
linePrack = []; //划线轨迹 ; 生成线条的实际点
|
||||
currentLine = [];
|
||||
transparent = 1; // 透明度
|
||||
pressure = 0.5; // 默认压力
|
||||
smoothness = 100; //顺滑度,用60的距离来计算速度
|
||||
lineSize = 1.5; // 笔记倍数
|
||||
lineMin = 0.5; // 最小笔画半径
|
||||
lineMax = 2; // 最大笔画半径
|
||||
currentPoint = {};
|
||||
firstTouch = true; // 第一次触发
|
||||
radius = 1; //画圆的半径
|
||||
cutArea = {
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
left: 0
|
||||
}; //裁剪区域
|
||||
lastPoint = 0;
|
||||
chirography = []; //笔迹
|
||||
startY = 0;
|
||||
deltaY = 0;
|
||||
startValue = 0;
|
||||
constructor(opts, _this) {
|
||||
this.lineColor = opts.lineColor || '#1A1A1A' // 颜色
|
||||
this.lineSise = opts.lineSise || 50
|
||||
this.canvasName = opts.canvasName || 'handWriting'
|
||||
this.init(_this)
|
||||
}
|
||||
init(_this) {
|
||||
this.ctx = uni.createCanvasContext(this.canvasName, _this)
|
||||
}
|
||||
// 笔迹开始
|
||||
penStart(event) {
|
||||
let e = event.mp
|
||||
if (e.type != 'touchstart') return false;
|
||||
this.ctx.setFillStyle(this.lineColor); // 初始线条设置颜色
|
||||
this.ctx.setGlobalAlpha(this.transparent); // 设置半透明
|
||||
this.currentPoint = {
|
||||
x: e.touches[0].x,
|
||||
y: e.touches[0].y
|
||||
}
|
||||
this.currentLine.unshift({
|
||||
time: new Date().getTime(),
|
||||
dis: 0,
|
||||
x: this.currentPoint.x,
|
||||
y: this.currentPoint.y
|
||||
})
|
||||
if (this.firstTouch) {
|
||||
this.cutArea = {
|
||||
top: this.currentPoint.y,
|
||||
right: this.currentPoint.x,
|
||||
bottom: this.currentPoint.y,
|
||||
left: this.currentPoint.x
|
||||
}
|
||||
this.firstTouch = false
|
||||
}
|
||||
this.pointToLine(this.currentLine);
|
||||
}
|
||||
// 笔迹移动
|
||||
penMove(event) {
|
||||
let e = event.mp
|
||||
if (e.type != 'touchmove') return false;
|
||||
if (e.cancelable) {
|
||||
// 判断默认行为是否已经被禁用
|
||||
if (!e.defaultPrevented) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
let point = {
|
||||
x: e.touches[0].x,
|
||||
y: e.touches[0].y
|
||||
}
|
||||
//测试裁剪
|
||||
if (point.y < this.cutArea.top) {
|
||||
this.cutArea.top = point.y;
|
||||
}
|
||||
if (point.y < 0) this.cutArea.top = 0;
|
||||
|
||||
if (point.x > this.cutArea.right) {
|
||||
this.cutArea.right = point.x;
|
||||
}
|
||||
if (this.canvasWidth - point.x <= 0) {
|
||||
this.cutArea.right = this.canvasWidth;
|
||||
}
|
||||
if (point.y > this.cutArea.bottom) {
|
||||
this.cutArea.bottom = point.y;
|
||||
}
|
||||
if (this.canvasHeight - point.y <= 0) {
|
||||
this.cutArea.bottom = this.canvasHeight;
|
||||
}
|
||||
if (point.x < this.cutArea.left) {
|
||||
this.cutArea.left = point.x;
|
||||
}
|
||||
if (point.x < 0) this.cutArea.left = 0;
|
||||
|
||||
this.lastPoint = this.currentPoint;
|
||||
this.currentPoint = point
|
||||
this.currentLine.unshift({
|
||||
time: new Date().getTime(),
|
||||
dis: this.distance(this.currentPoint, this.lastPoint, 'move'),
|
||||
x: point.x,
|
||||
y: point.y
|
||||
})
|
||||
this.pointToLine(this.currentLine);
|
||||
}
|
||||
// 笔迹结束
|
||||
penEnd(event) {
|
||||
let e = event.mp
|
||||
if (e.type != 'touchend') return 0;
|
||||
let point = {
|
||||
x: e.changedTouches[0].x,
|
||||
y: e.changedTouches[0].y
|
||||
}
|
||||
|
||||
this.lastPoint = this.currentPoint;
|
||||
this.currentPoint = point
|
||||
this.currentLine.unshift({
|
||||
time: new Date().getTime(),
|
||||
dis: this.distance(this.currentPoint, this.lastPoint, 'end'),
|
||||
x: point.x,
|
||||
y: point.y
|
||||
})
|
||||
if (this.currentLine.length > 2) {
|
||||
var info = (this.currentLine[0].time - this.currentLine[this.currentLine.length - 1].time) / this
|
||||
.currentLine.length;
|
||||
//$("#info").text(info.toFixed(2));
|
||||
}
|
||||
//一笔结束,保存笔迹的坐标点,清空,当前笔迹
|
||||
//增加判断是否在手写区域;
|
||||
this.pointToLine(this.currentLine);
|
||||
var currentChirography = {
|
||||
lineSize: this.lineSize,
|
||||
lineColor: this.lineColor
|
||||
};
|
||||
this.chirography.unshift(currentChirography);
|
||||
this.linePrack.unshift(this.currentLine);
|
||||
this.currentLine = []
|
||||
}
|
||||
retDraw() {
|
||||
this.ctx.clearRect(0, 0, 700, 730)
|
||||
this.ctx.draw()
|
||||
}
|
||||
|
||||
//画两点之间的线条;参数为:line,会绘制最近的开始的两个点;
|
||||
pointToLine(line) {
|
||||
this.calcBethelLine(line);
|
||||
// this.calcBethelLine1(line);
|
||||
return;
|
||||
}
|
||||
//计算插值的方式;
|
||||
calcBethelLine(line) {
|
||||
if (line.length <= 1) {
|
||||
line[0].r = this.radius;
|
||||
return;
|
||||
}
|
||||
let x0, x1, x2, y0, y1, y2, r0, r1, r2, len, lastRadius, dis = 0,
|
||||
time = 0,
|
||||
curveValue = 0.5;
|
||||
if (line.length <= 2) {
|
||||
x0 = line[1].x
|
||||
y0 = line[1].y
|
||||
x2 = line[1].x + (line[0].x - line[1].x) * curveValue;
|
||||
y2 = line[1].y + (line[0].y - line[1].y) * curveValue;
|
||||
//x2 = line[1].x;
|
||||
//y2 = line[1].y;
|
||||
x1 = x0 + (x2 - x0) * curveValue;
|
||||
y1 = y0 + (y2 - y0) * curveValue;;
|
||||
|
||||
} else {
|
||||
x0 = line[2].x + (line[1].x - line[2].x) * curveValue;
|
||||
y0 = line[2].y + (line[1].y - line[2].y) * curveValue;
|
||||
x1 = line[1].x;
|
||||
y1 = line[1].y;
|
||||
x2 = x1 + (line[0].x - x1) * curveValue;
|
||||
y2 = y1 + (line[0].y - y1) * curveValue;
|
||||
}
|
||||
//从计算公式看,三个点分别是(x0,y0),(x1,y1),(x2,y2) ;(x1,y1)这个是控制点,控制点不会落在曲线上;实际上,这个点还会手写获取的实际点,却落在曲线上
|
||||
len = this.distance({
|
||||
x: x2,
|
||||
y: y2
|
||||
}, {
|
||||
x: x0,
|
||||
y: y0
|
||||
}, 'calc');
|
||||
lastRadius = this.radius;
|
||||
for (let n = 0; n < line.length - 1; n++) {
|
||||
dis += line[n].dis;
|
||||
time += line[n].time - line[n + 1].time;
|
||||
if (dis > this.smoothness) break;
|
||||
}
|
||||
this.radius = Math.min(time / len * this.pressure + this.lineMin, this.lineMax) * this.lineSize
|
||||
line[0].r = this.radius;
|
||||
//计算笔迹半径;
|
||||
if (line.length <= 2) {
|
||||
r0 = (lastRadius + this.radius) / 2;
|
||||
r1 = r0;
|
||||
r2 = r1;
|
||||
//return;
|
||||
} else {
|
||||
r0 = (line[2].r + line[1].r) / 2;
|
||||
r1 = line[1].r;
|
||||
r2 = (line[1].r + line[0].r) / 2;
|
||||
}
|
||||
let n = 5;
|
||||
let point = [];
|
||||
for (let i = 0; i < n; i++) {
|
||||
let t = i / (n - 1);
|
||||
let x = (1 - t) * (1 - t) * x0 + 2 * t * (1 - t) * x1 + t * t * x2;
|
||||
let y = (1 - t) * (1 - t) * y0 + 2 * t * (1 - t) * y1 + t * t * y2;
|
||||
let r = lastRadius + (this.radius - lastRadius) / n * i;
|
||||
point.push({
|
||||
x: x,
|
||||
y: y,
|
||||
r: r
|
||||
});
|
||||
if (point.length == 3) {
|
||||
let a = this.ctaCalc(point[0].x, point[0].y, point[0].r, point[1].x, point[1].y, point[1].r, point[
|
||||
2].x, point[2].y,
|
||||
point[2].r);
|
||||
a[0].color = this.lineColor;
|
||||
this.bethelDraw(a, 1);
|
||||
point = [{
|
||||
x: x,
|
||||
y: y,
|
||||
r: r
|
||||
}];
|
||||
}
|
||||
}
|
||||
}
|
||||
//求两点之间距离
|
||||
distance(a, b, type) {
|
||||
let x = b.x - a.x;
|
||||
let y = b.y - a.y;
|
||||
return Math.sqrt(x * x + y * y) * 5;
|
||||
}
|
||||
ctaCalc(x0, y0, r0, x1, y1, r1, x2, y2, r2) {
|
||||
let a = [],
|
||||
vx01, vy01, norm, n_x0, n_y0, vx21, vy21, n_x2, n_y2;
|
||||
vx01 = x1 - x0;
|
||||
vy01 = y1 - y0;
|
||||
norm = Math.sqrt(vx01 * vx01 + vy01 * vy01 + 0.0001) * 2;
|
||||
vx01 = vx01 / norm * r0;
|
||||
vy01 = vy01 / norm * r0;
|
||||
n_x0 = vy01;
|
||||
n_y0 = -vx01;
|
||||
vx21 = x1 - x2;
|
||||
vy21 = y1 - y2;
|
||||
norm = Math.sqrt(vx21 * vx21 + vy21 * vy21 + 0.0001) * 2;
|
||||
vx21 = vx21 / norm * r2;
|
||||
vy21 = vy21 / norm * r2;
|
||||
n_x2 = -vy21;
|
||||
n_y2 = vx21;
|
||||
a.push({
|
||||
mx: x0 + n_x0,
|
||||
my: y0 + n_y0,
|
||||
color: "#1A1A1A"
|
||||
});
|
||||
a.push({
|
||||
c1x: x1 + n_x0,
|
||||
c1y: y1 + n_y0,
|
||||
c2x: x1 + n_x2,
|
||||
c2y: y1 + n_y2,
|
||||
ex: x2 + n_x2,
|
||||
ey: y2 + n_y2
|
||||
});
|
||||
a.push({
|
||||
c1x: x2 + n_x2 - vx21,
|
||||
c1y: y2 + n_y2 - vy21,
|
||||
c2x: x2 - n_x2 - vx21,
|
||||
c2y: y2 - n_y2 - vy21,
|
||||
ex: x2 - n_x2,
|
||||
ey: y2 - n_y2
|
||||
});
|
||||
a.push({
|
||||
c1x: x1 - n_x2,
|
||||
c1y: y1 - n_y2,
|
||||
c2x: x1 - n_x0,
|
||||
c2y: y1 - n_y0,
|
||||
ex: x0 - n_x0,
|
||||
ey: y0 - n_y0
|
||||
});
|
||||
a.push({
|
||||
c1x: x0 - n_x0 - vx01,
|
||||
c1y: y0 - n_y0 - vy01,
|
||||
c2x: x0 + n_x0 - vx01,
|
||||
c2y: y0 + n_y0 - vy01,
|
||||
ex: x0 + n_x0,
|
||||
ey: y0 + n_y0
|
||||
});
|
||||
a[0].mx = a[0].mx.toFixed(1);
|
||||
a[0].mx = parseFloat(a[0].mx);
|
||||
a[0].my = a[0].my.toFixed(1);
|
||||
a[0].my = parseFloat(a[0].my);
|
||||
for (let i = 1; i < a.length; i++) {
|
||||
a[i].c1x = a[i].c1x.toFixed(1);
|
||||
a[i].c1x = parseFloat(a[i].c1x);
|
||||
a[i].c1y = a[i].c1y.toFixed(1);
|
||||
a[i].c1y = parseFloat(a[i].c1y);
|
||||
a[i].c2x = a[i].c2x.toFixed(1);
|
||||
a[i].c2x = parseFloat(a[i].c2x);
|
||||
a[i].c2y = a[i].c2y.toFixed(1);
|
||||
a[i].c2y = parseFloat(a[i].c2y);
|
||||
a[i].ex = a[i].ex.toFixed(1);
|
||||
a[i].ex = parseFloat(a[i].ex);
|
||||
a[i].ey = a[i].ey.toFixed(1);
|
||||
a[i].ey = parseFloat(a[i].ey);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
bethelDraw(point, is_fill, color) {
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(point[0].mx, point[0].my);
|
||||
if (undefined != color) {
|
||||
this.ctx.setFillStyle(color);
|
||||
this.ctx.setStrokeStyle(color);
|
||||
} else {
|
||||
this.ctx.setFillStyle(point[0].color);
|
||||
this.ctx.setStrokeStyle(point[0].color);
|
||||
}
|
||||
for (let i = 1; i < point.length; i++) {
|
||||
this.ctx.bezierCurveTo(point[i].c1x, point[i].c1y, point[i].c2x, point[i].c2y, point[i].ex, point[i]
|
||||
.ey);
|
||||
}
|
||||
this.ctx.stroke();
|
||||
if (undefined != is_fill) {
|
||||
this.ctx.fill(); //填充图形 ( 后绘制的图形会覆盖前面的图形, 绘制时注意先后顺序 )
|
||||
}
|
||||
this.ctx.draw(true)
|
||||
}
|
||||
selectColorEvent(lineColor) {
|
||||
this.lineColor = lineColor;
|
||||
}
|
||||
selectSlideValue(lineSise) {
|
||||
switch (lineSise) {
|
||||
case 10:
|
||||
this.lineSize = 0.1;
|
||||
this.lineMin = 0.1;
|
||||
this.lineMax = 0.1;
|
||||
break;
|
||||
case 20:
|
||||
this.lineSize = 1;
|
||||
this.lineMin = 0.5;
|
||||
this.lineMax = 2;
|
||||
break;
|
||||
case 30:
|
||||
this.lineSize = 1.5;
|
||||
this.lineMin = 1;
|
||||
this.lineMax = 3;
|
||||
break;
|
||||
case 40:
|
||||
this.lineSize = 1.5;
|
||||
this.lineMin = 2;
|
||||
this.lineMax = 3.5;
|
||||
break;
|
||||
case 50:
|
||||
this.lineSize = 3;
|
||||
this.lineMin = 2;
|
||||
this.lineMax = 3.5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
saveCanvas(_this) {
|
||||
return new Promise((resolve, rej) => {
|
||||
uni.canvasToTempFilePath({
|
||||
canvasId: this.canvasName,
|
||||
success: (res) => {
|
||||
uni.getFileSystemManager().readFile({
|
||||
filePath: res.tempFilePath,
|
||||
encoding: 'base64',
|
||||
success: r => {
|
||||
resolve(r.data);
|
||||
}
|
||||
})
|
||||
},
|
||||
fail: function(err) {
|
||||
rej(err);
|
||||
}
|
||||
}, _this)
|
||||
})
|
||||
}
|
||||
}
|
||||
111
common/js/index.js
Normal file
@@ -0,0 +1,111 @@
|
||||
import Request from './request.js';
|
||||
import errorCode from './errorCode.js';
|
||||
let protocol = 'https'; //协议
|
||||
let baseUrl = 'app.xiaokang88.com/service/v1/'; // 域名
|
||||
export const config = {
|
||||
baseUrl: `${protocol}://${baseUrl}`
|
||||
}
|
||||
/**
|
||||
* 请求拦截器
|
||||
* @param {*} options
|
||||
*/
|
||||
const reqInterceptor = async (options) => {
|
||||
options.header = {
|
||||
...options.header
|
||||
}
|
||||
const isToken = (options.header || {}).isToken === false
|
||||
if (uni.getStorageSync('token') && !isToken) {
|
||||
options.header['authorization'] = `Bearer ${uni.getStorageSync('token')}`// 让每个请求携带自定义token 请根据实际情况自行修改
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应拦截器
|
||||
*/
|
||||
const resInterceptor = (response, conf = {}) => {
|
||||
// 网络状态码
|
||||
const statusCode = response.statusCode|| response.errcode;
|
||||
// 响应拦截器
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
_responseLog(response, conf, "response 200-299")
|
||||
return response.data
|
||||
} else if (statusCode === 500) {
|
||||
uni.showToast({
|
||||
icon: 'error',
|
||||
title: response['msg'] || errorCode[statusCode]
|
||||
})
|
||||
_responseLog(response, conf, "response 500")
|
||||
// 增加一个控制字段wakaryReqToReject 使 reject的内容更加可控
|
||||
return {
|
||||
// 根据当前字段来判断是否reject
|
||||
wakaryReqToReject: true,
|
||||
// 下面可以配置其他返回信息,方便统一处理reject
|
||||
// 以下内容作为reject的返回,根据需求处理,返回具体错误信息
|
||||
msg: "服务器错误",
|
||||
res: response
|
||||
}
|
||||
} else if (statusCode === 401) {
|
||||
uni.showToast({
|
||||
icon: 'error',
|
||||
title: response['msg'] || errorCode[statusCode]
|
||||
})
|
||||
uni.removeStorageSync()
|
||||
setTimeout(()=>{
|
||||
uni.navigateTo({
|
||||
url:'/pages/login/index'
|
||||
})
|
||||
},1000)
|
||||
_responseLog(response, conf, "response 401")
|
||||
// 增加一个控制字段wakaryReqToReject 使 reject的内容更加可控
|
||||
return {
|
||||
// 根据当前字段来判断是否reject
|
||||
wakaryReqToReject: true,
|
||||
// 下面可以配置其他返回信息,方便统一处理reject
|
||||
// 以下内容作为reject的返回,根据需求处理,返回具体错误信息
|
||||
msg: response['msg'] || errorCode[statusCode],
|
||||
res: response
|
||||
}
|
||||
} else {
|
||||
console.log
|
||||
uni.showToast({
|
||||
icon: 'error',
|
||||
title: response['msg'] || errorCode[statusCode]
|
||||
})
|
||||
_responseLog(response, conf, "response 300-499");
|
||||
// 增加一个控制字段wakaryReqToReject 使 reject的内容更加可控
|
||||
return {
|
||||
// 根据当前字段来判断是否reject
|
||||
wakaryReqToReject: true,
|
||||
// 下面可以配置其他返回信息,方便统一处理reject
|
||||
// 以下内容作为reject的返回,根据需求处理,返回具体错误信息
|
||||
msg: "response 300-499",
|
||||
res: response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* request log
|
||||
*/
|
||||
function _requestLog(req, describe = null) {
|
||||
if (process.env.NODE_ENV === 'development') {}
|
||||
}
|
||||
|
||||
/**
|
||||
* response log
|
||||
*/
|
||||
function _responseLog(res, conf = {}, describe = null) {
|
||||
let _statusCode = res.statusCode;
|
||||
if (process.env.NODE_ENV === 'development') {}
|
||||
|
||||
if (_statusCode === 500) {
|
||||
// save log to server
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求方法封装
|
||||
*/
|
||||
|
||||
export const req = new Request(config, reqInterceptor, resInterceptor)
|
||||
97
common/js/request.js
Normal file
@@ -0,0 +1,97 @@
|
||||
|
||||
import { requestConfig } from './common.js';
|
||||
|
||||
export default class Request {
|
||||
// 构造方法
|
||||
constructor(config = {}, reqInterceptor = null, resInterceptor = null, successHandler, failHandler = null, completeHandler = null){
|
||||
// 基础属性
|
||||
this.baseUrl = config.baseUrl
|
||||
this.header = config.header || {
|
||||
"Content-Type":"application/x-www-form-urlencoded"
|
||||
}
|
||||
// 自定义响应处理器
|
||||
this.success = successHandler
|
||||
this.fail = failHandler
|
||||
this.complete = completeHandler
|
||||
// 自定义拦截器(请求、响应)
|
||||
this.requestInterceptor = reqInterceptor
|
||||
this.responseInterceptor = resInterceptor
|
||||
}
|
||||
// 请求type request/upload/download
|
||||
async request(options, successHandler = null, failHandler = null, completeHandler = null){
|
||||
const task = options.task || false
|
||||
const type = options.type || "request"
|
||||
// delete options.task
|
||||
let config = null
|
||||
try {
|
||||
config = await requestConfig(this, options, successHandler, failHandler, completeHandler)
|
||||
} catch (e) {
|
||||
// reject the error
|
||||
return Promise.reject(e)
|
||||
}
|
||||
if(!config || typeof config != 'object'){
|
||||
return Promise.reject({})
|
||||
}
|
||||
|
||||
const _this = this
|
||||
if(task){
|
||||
config["success"] = (response) => {
|
||||
if (_this.responseInterceptor) {
|
||||
_this.responseInterceptor(response, config)
|
||||
}
|
||||
_this.success && _this.success(response)
|
||||
successHandler && successHandler(response)
|
||||
}
|
||||
config["fail"] = (response) => {
|
||||
_this.fail && _this.fail(response)
|
||||
failHandler && failHandler(response)
|
||||
}
|
||||
config["complete"] = (response) => {
|
||||
_this.complete && _this.complete(response)
|
||||
completeHandler && completeHandler(response)
|
||||
}
|
||||
if (type === "request"){
|
||||
return uni.request(config)
|
||||
}else if(type === "upload"){
|
||||
return uni.uploadFile(config)
|
||||
}else{
|
||||
return uni.downloadFile(config)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
config["success"] = (response) => {
|
||||
let _res = null
|
||||
if(_this.responseInterceptor){
|
||||
_res = _this.responseInterceptor(response, config)
|
||||
}
|
||||
_this.success && _this.success(response)
|
||||
successHandler && successHandler(response)
|
||||
// 为了对reject的内容更加可控,增加了一个控制字段 wakaryReqToReject
|
||||
if(_res.wakaryReqToReject){
|
||||
delete _res.wakaryReqToReject
|
||||
reject(_res)
|
||||
}else{
|
||||
resolve(_res)
|
||||
}
|
||||
}
|
||||
config["fail"] = (error) => {
|
||||
_this.fail && _this.fail(error)
|
||||
failHandler && failHandler(error)
|
||||
reject(error)
|
||||
}
|
||||
config["complete"] = (response) => {
|
||||
_this.complete && _this.complete(response)
|
||||
completeHandler && completeHandler(response)
|
||||
}
|
||||
if( type === "request"){
|
||||
uni.request(config)
|
||||
} else if(type === "upload"){
|
||||
uni.uploadFile(config)
|
||||
} else {
|
||||
uni.downloadFile(config)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
51
common/js/timeFormat.js
Normal file
@@ -0,0 +1,51 @@
|
||||
// padStart 的 polyfill,因为某些机型或情况,还无法支持es7的padStart,比如电脑版的微信小程序
|
||||
// 所以这里做一个兼容polyfill的兼容处理
|
||||
if (!String.prototype.padStart) {
|
||||
// 为了方便表示这里 fillString 用了ES6 的默认参数,不影响理解
|
||||
String.prototype.padStart = function(maxLength, fillString = ' ') {
|
||||
if (Object.prototype.toString.call(fillString) !== "[object String]") throw new TypeError(
|
||||
'fillString must be String')
|
||||
let str = this
|
||||
// 返回 String(str) 这里是为了使返回的值是字符串字面量,在控制台中更符合直觉
|
||||
if (str.length >= maxLength) return String(str)
|
||||
|
||||
let fillLength = maxLength - str.length,
|
||||
times = Math.ceil(fillLength / fillString.length)
|
||||
while (times >>= 1) {
|
||||
fillString += fillString
|
||||
if (times === 1) {
|
||||
fillString += fillString
|
||||
}
|
||||
}
|
||||
return fillString.slice(0, fillLength) + str;
|
||||
}
|
||||
}
|
||||
|
||||
// 其他更多是格式化有如下:
|
||||
// yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合
|
||||
function timeFormat(dateTime = null, fmt = 'yyyy-mm-dd') {
|
||||
// 如果为null,则格式化当前时间
|
||||
if (!dateTime) dateTime = Number(new Date());
|
||||
// 如果dateTime长度为10或者13,则为秒和毫秒的时间戳,如果超过13位,则为其他的时间格式
|
||||
if (dateTime.toString().length == 10) dateTime *= 1000;
|
||||
let date = new Date(dateTime);
|
||||
let ret;
|
||||
let opt = {
|
||||
"y+": date.getFullYear().toString(), // 年
|
||||
"m+": (date.getMonth() + 1).toString(), // 月
|
||||
"d+": date.getDate().toString(), // 日
|
||||
"h+": date.getHours().toString(), // 时
|
||||
"M+": date.getMinutes().toString(), // 分
|
||||
"s+": date.getSeconds().toString() // 秒
|
||||
// 有其他格式化字符需求可以继续添加,必须转化成字符串
|
||||
};
|
||||
for (let k in opt) {
|
||||
ret = new RegExp("(" + k + ")").exec(fmt);
|
||||
if (ret) {
|
||||
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
|
||||
};
|
||||
};
|
||||
return fmt;
|
||||
}
|
||||
|
||||
export default timeFormat
|
||||
75
common/js/tool.js
Normal file
@@ -0,0 +1,75 @@
|
||||
// 时间格式
|
||||
const commonTimeAgo = num => {
|
||||
if (num) {
|
||||
var t = new Date().getTime() - Date.parse(num.replace(/-/gi, "/")),
|
||||
n = t / 31104e6,
|
||||
a = t / 2592e6,
|
||||
r = t / 6048e5,
|
||||
o = t / 864e5,
|
||||
i = t / 36e5,
|
||||
u = t / 6e4;
|
||||
return n >= 1 ? parseInt(n) + "年前" : a >= 1 ? parseInt(a) + "个月前" : r >= 1 ? parseInt(r) + "周前" : o >= 1 ?
|
||||
parseInt(o) + "天前" : i >= 1 ? parseInt(i) + "小时前" : u >= 1 ? parseInt(u) + "分钟前" : "刚刚";
|
||||
}
|
||||
}
|
||||
|
||||
//判断闰年代码
|
||||
function isLeapYear(Year) {
|
||||
if (((Year % 4) == 0) && ((Year % 100) != 0) || ((Year % 400) == 0)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//计算某月份天数
|
||||
function TotalDays(year, month) {
|
||||
var days = 0;
|
||||
switch (month) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
days += 31;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
case 9:
|
||||
case 11:
|
||||
days += 30;
|
||||
break;
|
||||
case 2:
|
||||
if (isLeapYear(year)) {
|
||||
days += 29;
|
||||
} else {
|
||||
days += 28;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return days;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} mobile
|
||||
* 手机号加密
|
||||
*/
|
||||
function encode(mobile) {
|
||||
if (mobile.length == 13) {
|
||||
let pre = mobile.slice(0, 3); // 前三位
|
||||
let mid = '****';
|
||||
let suf = mobile.slice(-4); // 后四位
|
||||
return `${pro}${mid}${suf}`;
|
||||
} else {
|
||||
return mobile
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
commonTimeAgo,
|
||||
isLeapYear,
|
||||
TotalDays,
|
||||
encode
|
||||
}
|
||||
300
common/js/util.js
Normal file
@@ -0,0 +1,300 @@
|
||||
let systemInfo = uni.getSystemInfoSync();
|
||||
/**
|
||||
* 更新小程序
|
||||
*/
|
||||
function updateMiniapp() {
|
||||
const updateManager = uni.getUpdateManager();
|
||||
|
||||
updateManager.onCheckForUpdate(function(res) {
|
||||
// 请求完新版本信息的回调
|
||||
});
|
||||
|
||||
updateManager.onUpdateReady(function(res) {
|
||||
uni.showModal({
|
||||
title: "更新提示",
|
||||
content: "新版本已经准备好,是否重启应用?",
|
||||
success(res) {
|
||||
if (res.confirm) {
|
||||
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
|
||||
updateManager.applyUpdate();
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
updateManager.onUpdateFailed(function(res) {
|
||||
// 新的版本下载失败
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取AppInfo
|
||||
*/
|
||||
|
||||
async function getAppInfo() {
|
||||
const accountInfo = await uni.getAccountInfoSync();
|
||||
const appId = await accountInfo.miniProgram.appId;
|
||||
return appId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取code
|
||||
*/
|
||||
async function getCode() {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.getProvider({
|
||||
service: "oauth",
|
||||
success: (res) => {
|
||||
// 平台来源
|
||||
uni.login({
|
||||
provider: res.provider[0],
|
||||
scopes: ["auth_base"],
|
||||
success(loginRes) {
|
||||
let code = loginRes.code;
|
||||
resolve(code);
|
||||
},
|
||||
fail(err) {
|
||||
uni.showModal({
|
||||
title: err.errMsg,
|
||||
showCancel: false,
|
||||
});
|
||||
},
|
||||
complete() {},
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
//校验手机号有效性
|
||||
const checkPhoneNumber = mobile => {
|
||||
//验证手机号真实性
|
||||
if (mobile == null || mobile == undefined) {
|
||||
wx.showToast({
|
||||
title: '手机号不能为空',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
// 匹配所有号码(手机卡 + 数据卡 + 上网卡)
|
||||
if (!(/^(?:\+?86)?1(?:3\d{3}|5[^4\D]\d{2}|8\d{3}|7(?:[01356789]\d{2}|4(?:0\d|1[0-2]|9\d))|9[01356789]\d{2}|6[2567]\d{2}|4(?:[14]0\d{3}|[68]\d{4}|[579]\d{2}))\d{6}$/
|
||||
.test(mobile))) {
|
||||
wx.showToast({
|
||||
title: '手机号格式错误',
|
||||
icon: 'none'
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
let m_checkProv = (val) => {
|
||||
var pattern = /^[1-9][0-9]/;
|
||||
var provs = {
|
||||
11: "北京",
|
||||
12: "天津",
|
||||
13: "河北",
|
||||
14: "山西",
|
||||
15: "内蒙古",
|
||||
21: "辽宁",
|
||||
22: "吉林",
|
||||
23: "黑龙江 ",
|
||||
31: "上海",
|
||||
32: "江苏",
|
||||
33: "浙江",
|
||||
34: "安徽",
|
||||
35: "福建",
|
||||
36: "江西",
|
||||
37: "山东",
|
||||
41: "河南",
|
||||
42: "湖北 ",
|
||||
43: "湖南",
|
||||
44: "广东",
|
||||
45: "广西",
|
||||
46: "海南",
|
||||
50: "重庆",
|
||||
51: "四川",
|
||||
52: "贵州",
|
||||
53: "云南",
|
||||
54: "西藏 ",
|
||||
61: "陕西",
|
||||
62: "甘肃",
|
||||
63: "青海",
|
||||
64: "宁夏",
|
||||
65: "新疆",
|
||||
71: "台湾",
|
||||
81: "香港",
|
||||
82: "澳门"
|
||||
};
|
||||
if (pattern.test(val)) {
|
||||
if (provs[val]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
let m_checkDate = (val) => {
|
||||
var pattern = /^(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)$/;
|
||||
if (pattern.test(val)) {
|
||||
var year = val.substring(0, 4);
|
||||
var month = val.substring(4, 6);
|
||||
var date = val.substring(6, 8);
|
||||
var date2 = new Date(year + "-" + month + "-" + date);
|
||||
if (date2 && date2.getMonth() == (parseInt(month) - 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
let m_checkCode = (val) => {
|
||||
var p = /^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
|
||||
var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
|
||||
var parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2];
|
||||
var code = val.substring(17);
|
||||
if (p.test(val)) {
|
||||
var sum = 0;
|
||||
for (var i = 0; i < 17; i++) {
|
||||
sum += val[i] * factor[i];
|
||||
}
|
||||
if (parity[sum % 11] == code.toUpperCase()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
function m_by_checkID(val = '') {
|
||||
if (m_checkCode(val) && val) {
|
||||
var date = val.substring(6, 14);
|
||||
if (m_checkDate(date)) {
|
||||
if (m_checkProv(val.substring(0, 2))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
function trim(str, pos = 'both') {
|
||||
if (pos == 'both') {
|
||||
return str.replace(/^\s+|\s+$/g, "");
|
||||
} else if (pos == "left") {
|
||||
return str.replace(/^\s*/, '');
|
||||
} else if (pos == 'right') {
|
||||
return str.replace(/(\s*$)/g, "");
|
||||
} else if (pos == 'all') {
|
||||
return str.replace(/\s+/g, "");
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 样式转换
|
||||
* 对象转字符串,或者字符串转对象
|
||||
* @param {Object | String} 需要转换的目标
|
||||
* @param {String} 转换的目的,object-转为对象,string-转为字符串
|
||||
*/
|
||||
function addStyle(customStyle, target = 'object') {
|
||||
// 字符串转字符串,对象转对象情形,直接返回
|
||||
if (uni.$u.test.empty(customStyle) || typeof(customStyle) === 'object' && target === 'object' || target ===
|
||||
'string' &&
|
||||
typeof(customStyle) === 'string') {
|
||||
return customStyle
|
||||
}
|
||||
// 字符串转对象
|
||||
if (target === 'object') {
|
||||
// 去除字符串样式中的两端空格(中间的空格不能去掉,比如padding: 20px 0如果去掉了就错了),空格是无用的
|
||||
customStyle = trim(customStyle)
|
||||
// 根据";"将字符串转为数组形式
|
||||
const styleArray = customStyle.split(';')
|
||||
const style = {}
|
||||
// 历遍数组,拼接成对象
|
||||
for (let i = 0; i < styleArray.length; i++) {
|
||||
// 'font-size:20px;color:red;',如此最后字符串有";"的话,会导致styleArray最后一个元素为空字符串,这里需要过滤
|
||||
if (styleArray[i]) {
|
||||
const item = styleArray[i].split(':')
|
||||
style[trim(item[0])] = trim(item[1])
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
// 这里为对象转字符串形式
|
||||
let string = ''
|
||||
for (const i in customStyle) {
|
||||
// 驼峰转为中划线的形式,否则css内联样式,无法识别驼峰样式属性名
|
||||
const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
|
||||
string += `${key}:${customStyle[i]};`
|
||||
}
|
||||
// 去除两端空格
|
||||
return trim(string)
|
||||
}
|
||||
|
||||
// 导航栏高度
|
||||
function navbarHeight(height = '') {
|
||||
// #ifdef APP-PLUS || H5
|
||||
return height ? height : 44;
|
||||
// #endif
|
||||
// #ifdef MP
|
||||
// 小程序特别处理,让导航栏高度 = 胶囊高度 + 两倍胶囊顶部与状态栏底部的距离之差(相当于同时获得了导航栏底部与胶囊底部的距离)
|
||||
// 此方法有缺陷,暂不用(会导致少了几个px),采用直接固定值的方式
|
||||
// return menuButtonInfo.height + (menuButtonInfo.top - this.statusBarHeight) * 2;//导航高度
|
||||
let he = systemInfo.platform == 'ios' ? 44 : 48;
|
||||
return height ? height : he;
|
||||
// #endif
|
||||
}
|
||||
|
||||
// 导航栏高度
|
||||
function navbarHeight(height = '') {
|
||||
// #ifdef APP-PLUS || H5
|
||||
return height ? height : 44;
|
||||
// #endif
|
||||
// #ifdef MP
|
||||
// 小程序特别处理,让导航栏高度 = 胶囊高度 + 两倍胶囊顶部与状态栏底部的距离之差(相当于同时获得了导航栏底部与胶囊底部的距离)
|
||||
// 此方法有缺陷,暂不用(会导致少了几个px),采用直接固定值的方式
|
||||
// return menuButtonInfo.height + (menuButtonInfo.top - this.statusBarHeight) * 2;//导航高度
|
||||
let he = systemInfo.platform == 'ios' ? 44 : 48;
|
||||
return height ? height : he;
|
||||
// #endif
|
||||
}
|
||||
|
||||
function getAge(identityCard) {
|
||||
var len = (identityCard + "").length;
|
||||
if (len == 0) {
|
||||
return '';
|
||||
} else {
|
||||
if ((len != 15) && (len != 18)) //身份证号码只能为15位或18位其它不合法
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
var strBirthday = "";
|
||||
if (len == 18) //处理18位的身份证号码从号码中得到生日和性别代码
|
||||
{
|
||||
strBirthday = identityCard.substr(6, 4) + "/" + identityCard.substr(10, 2) + "/" + identityCard.substr(
|
||||
12, 2);
|
||||
}
|
||||
if (len == 15) {
|
||||
strBirthday = "19" + identityCard.substr(6, 2) + "/" + identityCard.substr(8, 2) + "/" + identityCard
|
||||
.substr(10, 2);
|
||||
}
|
||||
//时间字符串里,必须是“/”
|
||||
var birthDate = new Date(strBirthday);
|
||||
var nowDateTime = new Date();
|
||||
var age = nowDateTime.getFullYear() - birthDate.getFullYear();
|
||||
//再考虑月、天的因素;.getMonth()获取的是从0开始的,这里进行比较,不需要加1
|
||||
if (nowDateTime.getMonth() < birthDate.getMonth() || (nowDateTime.getMonth() == birthDate.getMonth() &&
|
||||
nowDateTime.getDate() < birthDate.getDate())) {
|
||||
age--;
|
||||
}
|
||||
return age;
|
||||
}
|
||||
module.exports = {
|
||||
getAge,
|
||||
updateMiniapp,
|
||||
getAppInfo,
|
||||
getCode,
|
||||
checkPhoneNumber,
|
||||
m_by_checkID,
|
||||
addStyle,
|
||||
navbarHeight
|
||||
};
|
||||
14
common/messageType.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export const messageType = {
|
||||
"desc": '病情描述信息',
|
||||
"text_a": '基本健康信息',
|
||||
"images": '图片信息',
|
||||
"record": "就诊记录",
|
||||
"system": "系统信息",
|
||||
"end": "系统信息",
|
||||
"text": "文本信息",
|
||||
"voice": "语音信息",
|
||||
"img": "图片信息",
|
||||
"video": "视频信息",
|
||||
"doctorCcard":'[医生名片]',
|
||||
"prescription":'[处方]'
|
||||
}
|
||||
27
common/share.js
Normal file
@@ -0,0 +1,27 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
// 默认的全局分享内容
|
||||
share: {
|
||||
title: '萧康云医',
|
||||
path: '/pages/login/index', // 全局分享的路径,比如 首页
|
||||
}
|
||||
}
|
||||
},
|
||||
onShareAppMessage(res) {
|
||||
return {
|
||||
title: this.share.title,
|
||||
path: this.share.path,
|
||||
}
|
||||
},
|
||||
onShareTimeline() {
|
||||
let that = this;
|
||||
var url = "/pages/login/index"
|
||||
return {
|
||||
title: '萧康云医',
|
||||
path: url,
|
||||
query: "", //你的参数拼接,注意:不需要加?
|
||||
imageUrl: '' //你分享的封面
|
||||
};
|
||||
},
|
||||
}
|
||||
213
common/utils.js
Normal file
@@ -0,0 +1,213 @@
|
||||
|
||||
import $store from '@/store/index.js';
|
||||
import pinyin from './getPingYin.js';
|
||||
class utils {
|
||||
constructor(arg) {
|
||||
|
||||
}
|
||||
|
||||
//返回上一页
|
||||
back(delta = 1){
|
||||
uni.navigateBack({
|
||||
delta:delta
|
||||
})
|
||||
}
|
||||
|
||||
//获取好友备注,没有返回昵称
|
||||
getNickName(friend_id,nickname){
|
||||
var friendIds = uni.getStorageSync("friendIds");
|
||||
if(friendIds.length){
|
||||
let petName = nickname;
|
||||
friendIds.forEach((item)=>{
|
||||
if(friend_id == item.friend_id){
|
||||
if(item.pet_name != undefined){
|
||||
petName = item.pet_name;
|
||||
}
|
||||
}
|
||||
})
|
||||
return petName;
|
||||
}else{
|
||||
return nickname;
|
||||
}
|
||||
}
|
||||
|
||||
getGroupById(id){
|
||||
let groups = uni.getStorageSync("groupList");
|
||||
let info = [];
|
||||
if(groups && groups.length){
|
||||
groups.forEach((item)=>{
|
||||
if(id == item._id){
|
||||
info = item;
|
||||
}
|
||||
})
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
getGroupAvatarList(id){
|
||||
var avatarList = [];
|
||||
if(id){
|
||||
let groups = this.getGroupById(id);
|
||||
if(groups.group_users != undefined && groups.group_users.length){
|
||||
groups.group_users.forEach((item)=>{
|
||||
avatarList.push(item.avatar)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
return avatarList;
|
||||
}
|
||||
|
||||
getFriendInfoById(id){
|
||||
let friends = $store.state.user.friendList;
|
||||
let info = [];
|
||||
if(friends.length){
|
||||
friends.forEach((item)=>{
|
||||
if(id == item._id){
|
||||
info = item;
|
||||
}
|
||||
})
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
//获取缓存头像
|
||||
getImageCache(url) {
|
||||
return url;
|
||||
let key = `images_cache`;
|
||||
let list = uni.getStorageSync(key);
|
||||
list = list ? list : [];
|
||||
let index = list.findIndex(item => item.url === url)
|
||||
|
||||
if (index !== -1) {
|
||||
return list[index]['cache'];
|
||||
} else {
|
||||
var cache = {
|
||||
url: url,
|
||||
cache: url,
|
||||
};
|
||||
uni.downloadFile({
|
||||
url: url,
|
||||
success: (res) => {
|
||||
if (res.statusCode === 200) {
|
||||
cache.cache = res.tempFilePath;
|
||||
list.push(cache);
|
||||
uni.setStorageSync(key, list);
|
||||
}
|
||||
},
|
||||
fail: (e) => {
|
||||
|
||||
}
|
||||
});
|
||||
return cache.cache;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//好友列表按首字母排序
|
||||
sortFriendList(data) {
|
||||
var friendList = data;
|
||||
var letter = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
|
||||
"U", "V", "W", "X", "Y", "Z" ,"#"
|
||||
];
|
||||
var indexData = [];
|
||||
letter.forEach((letterItem, letterIndex) => {
|
||||
var letterData = {
|
||||
letter: letterItem,
|
||||
data: []
|
||||
}
|
||||
friendList.forEach((friendListItem, friendListIndex) => {
|
||||
var firstLetter = friendListItem.nickname.substr(0, 1);
|
||||
var p = /[a-z]/i;
|
||||
var b = p.test(firstLetter);
|
||||
if(b){
|
||||
var firstWord = firstLetter.toUpperCase();
|
||||
}else{
|
||||
var firstWord = pinyin.initial(firstLetter);
|
||||
}
|
||||
var p2 = /[A-Z]/i;
|
||||
var b2 = p2.test(firstWord);
|
||||
if(!b2 && letterItem === "#"){
|
||||
letterData.data.push(friendListItem);
|
||||
}
|
||||
if (b2 && letterItem === firstWord) {
|
||||
letterData.data.push(friendListItem);
|
||||
}
|
||||
})
|
||||
if (letterData.data.length > 0) {
|
||||
indexData.push(letterData);
|
||||
}
|
||||
})
|
||||
return indexData;
|
||||
}
|
||||
//格式化时间
|
||||
formatChatTime(time) {
|
||||
time = this.dateFormat("YY-mm-dd HH:MM:SS", new Date(time));
|
||||
var date = time.toString();
|
||||
var year = date.split("-")[0];
|
||||
var month = date.split("-")[1];
|
||||
var day = date.split("-")[2];
|
||||
var d1 = new Date(year + '/' + month + '/' + day.split(" ")[0]);
|
||||
var d3 = new Date(date.replace(/-/g, "/"));
|
||||
var dd = new Date();
|
||||
var y = dd.getFullYear();
|
||||
var m = dd.getMonth() + 1;
|
||||
var d = dd.getDate();
|
||||
var d2 = new Date(y + '/' + m + '/' + d);
|
||||
var iday = parseInt(d2 - d1) / 1000 / 60 / 60 / 24;
|
||||
var hours = d3.getHours();
|
||||
var minutes = d3.getMinutes();
|
||||
if (minutes < 10) {
|
||||
minutes = '0' + minutes;
|
||||
}
|
||||
if (hours < 10) {
|
||||
hours = '0' + hours;
|
||||
}
|
||||
if (iday == 0) {
|
||||
if (hours >= 12) {
|
||||
return "下午 " + hours + ":" + minutes;
|
||||
} else {
|
||||
return "上午 " + hours + ":" + minutes;;
|
||||
}
|
||||
} else if (iday == 1) {
|
||||
var dt = "";
|
||||
if (hours >= 12) {
|
||||
dt = "下午 " + hours + ":" + minutes;
|
||||
} else {
|
||||
dt = "上午 " + hours + ":" + minutes;;
|
||||
}
|
||||
return "昨天 " + dt;
|
||||
} else if (iday == 2) {
|
||||
var dt = "";
|
||||
if (hours >= 12) {
|
||||
dt = "下午 " + hours + ":" + minutes;
|
||||
} else {
|
||||
dt = "上午 " + hours + ":" + minutes;;
|
||||
}
|
||||
return "前天 " + dt;
|
||||
} else {
|
||||
return year + '/' + month + "/" + d1.getDate()
|
||||
}
|
||||
}
|
||||
dateFormat(fmt, date) {
|
||||
let ret;
|
||||
const opt = {
|
||||
"Y+": date.getFullYear().toString(), // 年
|
||||
"m+": (date.getMonth() + 1).toString(), // 月
|
||||
"d+": date.getDate().toString(), // 日
|
||||
"H+": date.getHours().toString(), // 时
|
||||
"M+": date.getMinutes().toString(), // 分
|
||||
"S+": date.getSeconds().toString() // 秒
|
||||
};
|
||||
for (let k in opt) {
|
||||
ret = new RegExp("(" + k + ")").exec(fmt);
|
||||
if (ret) {
|
||||
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
|
||||
};
|
||||
};
|
||||
return fmt;
|
||||
}
|
||||
|
||||
}
|
||||
export default utils
|
||||
16
components/d-audit/d-audit.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<view class="flex-col flex-ali-center state">
|
||||
<image src="../../static/image/sf.png"></image>
|
||||
<d-text text="您的认证信息已提交!" className="tips-c m-t-10 m-t-3"></d-text>
|
||||
<d-text text="我们会尽快审核,请耐心等待" className="tips-c m-t-1"></d-text>
|
||||
</view>
|
||||
</template>
|
||||
<style lang="scss" scoped>
|
||||
.state {
|
||||
margin-top: 160rpx;
|
||||
image {
|
||||
width: 300rpx;
|
||||
height: 223rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
325
components/d-dragSorts/d-dragSorts.vue
Normal file
@@ -0,0 +1,325 @@
|
||||
<template>
|
||||
<view class="p-row-32 white">
|
||||
<movable-area :style="{ height: `${areaHeight}px`}">
|
||||
<block v-for="(item, index) in list" :key="index">
|
||||
<movable-view :key="item.sign" @change="e => change(e, index)" @touchend="touchend"
|
||||
@touchstart="touchstart($event);touchStart(index)" class="drag_item"
|
||||
:y="item.y" direction="vertical" :disabled='disabled' :style="{zIndex:`${current==index?2:1}`}">
|
||||
<u-swipe-action :disabled="isSlide" :show="item.show" :index="index" :key="item.sign" @click="click"
|
||||
@open="open" :options="options" :style="{zIndex:list.length-index}">
|
||||
<view class="touch_view"
|
||||
:style="{minHeight: item.itemHeight?item.itemHeight+'px':itemHeight+'px',borderBottom: (index+1)!=list.length?'1px solid #E8E9EB':'1px solid #fff',paddingTop: ifCustomHeight?'48rpx':'32rpx'}"
|
||||
@click="$emit('click',item)">
|
||||
<view class="left">
|
||||
<text>{{ item[name]}}</text>
|
||||
</view>
|
||||
<view class="right">
|
||||
<u-icon size="40" color="#B7B7BA" name="list"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</u-swipe-action>
|
||||
</movable-view>
|
||||
</block>
|
||||
</movable-area>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
ifCustomHeight: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
propList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
isSlide: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 104
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
default: 'name'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
longpress: false,
|
||||
oldIndex: -1, //记录移动前的位置,为了和移动后进行比较是否发生了位移
|
||||
newIndex: -1, //当前移动到的位置
|
||||
direction: '',
|
||||
current: -1,
|
||||
itemHeight: uni.upx2px(this.height),
|
||||
difference: 0, //记录移动前的位置
|
||||
disabled: true, //是否可以拖动
|
||||
list: [], //渲染的list
|
||||
options: [{
|
||||
text: '删除',
|
||||
style: {
|
||||
backgroundColor: '#dd524d'
|
||||
}
|
||||
}],
|
||||
timer: null,
|
||||
startX: 0, //touchStart开始坐标
|
||||
startY: 0,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.ifCustomHeight && this.getElRect()
|
||||
},
|
||||
computed: {
|
||||
areaHeight() {
|
||||
let height = this.list.reduce((to, item) => {
|
||||
to += (item.itemHeight || this.itemHeight)
|
||||
return to
|
||||
}, 0)
|
||||
return height
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
propList: {
|
||||
handler(val) {
|
||||
this.list = this.updateList(val);
|
||||
this.cloneList = JSON.parse(JSON.stringify(this.list));
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 计算滑动角度
|
||||
touchstart(e) {
|
||||
this.startX = e.changedTouches[0].clientX,
|
||||
this.startY = e.changedTouches[0].clientY
|
||||
},
|
||||
//计算滑动角度 start 起点坐标 end 终点坐标
|
||||
angle(start, end) {
|
||||
var _X = end.X - start.X,
|
||||
_Y = end.Y - start.Y;
|
||||
//返回角度 Math.atan()返回数字的反正切值
|
||||
return 360 * Math.atan(_Y / _X) / (2 * Math.PI);
|
||||
},
|
||||
getDirection(e) {
|
||||
let {
|
||||
startX,
|
||||
startY
|
||||
} = this;
|
||||
let slidingRange = 45;
|
||||
let touchMoveX = e.changedTouches[0].clientX;
|
||||
let touchMoveY = e.changedTouches[0].clientY;
|
||||
let angle = this.angle({
|
||||
X: startX,
|
||||
Y: startY
|
||||
}, {
|
||||
X: touchMoveX,
|
||||
Y: touchMoveY
|
||||
});
|
||||
//为了方便计算取绝对值判断
|
||||
if (Math.abs(angle) > slidingRange && touchMoveY < startY) {
|
||||
// 向上滑动
|
||||
this.direction = 'up'
|
||||
};
|
||||
if (Math.abs(angle) > slidingRange && touchMoveY > startY) {
|
||||
// 向下滑动
|
||||
this.direction = 'down'
|
||||
}
|
||||
},
|
||||
// 获取一个目标元素的高度
|
||||
getElRect() {
|
||||
let query = uni.createSelectorQuery().in(this);
|
||||
query.selectAll('.drag_item').boundingClientRect(res => {
|
||||
// 如果节点尚未生成,res值为null,循环调用执行
|
||||
if (res.length == 0) {
|
||||
setTimeout(() => {
|
||||
this.getElRect();
|
||||
}, 10);
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < res.length; i++) {
|
||||
this.$set(this.list[i], 'itemHeight', res[i].height < this.itemHeight ? this.itemHeight :
|
||||
res[i].height)
|
||||
this.$set(this.list[i], 'y', this.getTop(this.list, i))
|
||||
}
|
||||
this.updateList(this.list)
|
||||
this.cloneList = JSON.parse(JSON.stringify(this.list));
|
||||
}).exec();
|
||||
},
|
||||
getTop(list = [], end = 0) {
|
||||
let itemHeight = 0
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
if (end == i) {
|
||||
break
|
||||
}
|
||||
itemHeight += list[i]['itemHeight']
|
||||
}
|
||||
return itemHeight
|
||||
},
|
||||
// 添加或更新数组y值
|
||||
updateList(list = []) {
|
||||
return list.map((item, index) => {
|
||||
let obj = {
|
||||
...item,
|
||||
show: false,
|
||||
sign: Math.random() + index //防止不更新的情况和标识位
|
||||
}
|
||||
if (this.ifCustomHeight) {
|
||||
return obj;
|
||||
} else {
|
||||
return {
|
||||
...obj,
|
||||
y: index * this.itemHeight
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
touchStart(index) {
|
||||
this.disabled = false
|
||||
this.current = index;
|
||||
this.oldIndex = index;
|
||||
},
|
||||
change(e, index) {
|
||||
// 不是当前元素位移直接不处理
|
||||
if (index != this.current) return;
|
||||
this.longpress = true
|
||||
if (this.ifCustomHeight) {
|
||||
this.difference = e.detail.y;
|
||||
} else {
|
||||
//位移的距离px
|
||||
let difference = e.detail.y - this.current * this.itemHeight;
|
||||
//计算位移几个位置
|
||||
let tempIndex = difference > 0 ? parseInt((difference + (this.itemHeight / 2)) / this.itemHeight) :
|
||||
parseInt((difference - (this.itemHeight / 2)) / this.itemHeight);
|
||||
//当前拖到的位置
|
||||
this.newIndex = Math.abs(this.current + tempIndex);
|
||||
if (this.newIndex > -1 && this.oldIndex > -1 && this.newIndex !== this.oldIndex) {
|
||||
this.changeList();
|
||||
}
|
||||
}
|
||||
},
|
||||
changeList() {
|
||||
// 没想到怎么改变原数组, 直接拷贝一份数组出来,不考虑情况 一把梭 直接遍历拷贝的原数组.
|
||||
//直接把改变位置赋值回去不行,不知道为什么,只能改变每一项的y值
|
||||
let arr = JSON.parse(JSON.stringify(this.cloneList));
|
||||
arr.splice(this.newIndex, 0, ...arr.splice(this.current, 1));
|
||||
this.list.forEach((item, index) => {
|
||||
if (index !== this.current) {
|
||||
item.y = arr.findIndex(citem => citem.sign == item.sign) * this.itemHeight;
|
||||
}
|
||||
});
|
||||
this.oldIndex = this.newIndex;
|
||||
},
|
||||
touchend(e) {
|
||||
if (!this.longpress) {
|
||||
return
|
||||
}
|
||||
if (this.ifCustomHeight) {
|
||||
if (!this.list[this.current] || this.current < 0) {
|
||||
return
|
||||
}
|
||||
this.getDirection(e)
|
||||
let itemHeight = this.list[this.current]['itemHeight'];
|
||||
console.log(this.difference);
|
||||
let difference = this.difference;
|
||||
let arr = JSON.parse(JSON.stringify(this.cloneList));
|
||||
let index = this.current;
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
let item = arr[i]['y'] + arr[i]['itemHeight'] / 2
|
||||
if (this.direction == 'down' && difference + itemHeight >= item) {
|
||||
index = i
|
||||
} else if (this.direction == 'up' && item >= difference) {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
index >= 0 && arr.splice(index, 0, ...arr.splice(this.current, 1));
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
arr[i]['y'] = this.getTop(arr, i)
|
||||
}
|
||||
this.list = this.updateList(arr);
|
||||
} else {
|
||||
if (this.newIndex > -1 && this.current > -1 && this.newIndex !== this.current) {
|
||||
this.cloneList.splice(this.newIndex, 0, ...this.cloneList.splice(this.current, 1));
|
||||
this.list = this.updateList(this.cloneList);
|
||||
}
|
||||
}
|
||||
this.cloneList = JSON.parse(JSON.stringify(this.list));
|
||||
this.emitChang(this.list)
|
||||
this.current = -1;
|
||||
this.oldIndex = -1;
|
||||
this.newIndex = -1;
|
||||
this.disabled = true
|
||||
this.difference=0
|
||||
this.longpress = false
|
||||
},
|
||||
click(index, index1) {
|
||||
if (index1 == 0) {
|
||||
this.$emit('del', index)
|
||||
}
|
||||
},
|
||||
// 如果打开一个的时候,不需要关闭其他,则无需实现本方法
|
||||
open(index) {
|
||||
// 先将正在被操作的swipeAction标记为打开状态,否则由于props的特性限制,
|
||||
// 原本为'false',再次设置为'false'会无效
|
||||
this.list[index].show = true;
|
||||
this.list.map((val, idx) => {
|
||||
if (index != idx) this.list[idx].show = false;
|
||||
});
|
||||
},
|
||||
emitChang(arr) {
|
||||
let tempArr = JSON.parse(JSON.stringify(arr))
|
||||
tempArr.forEach(item => {
|
||||
delete item.y
|
||||
delete item.show
|
||||
delete item.sign
|
||||
})
|
||||
this.$emit('change', tempArr)
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.drag_item {
|
||||
width: 686rpx;
|
||||
background-color: #fff;
|
||||
height: max-content;
|
||||
}
|
||||
|
||||
movable-area {
|
||||
width: 686rpx;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.touch_view {
|
||||
width: 686rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
|
||||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-bottom: 16rpx;
|
||||
padding-right: 16rpx;
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
color: #31353D;
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0px 0px 8rpx 0px rgba(0, 0, 0, 0.08);
|
||||
border-radius: 4rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
1092
components/d-editor/d-editor.vue
Normal file
139
components/d-editor/iconfont.wxss
Normal file
@@ -0,0 +1,139 @@
|
||||
@font-face {
|
||||
font-family: 'iconfont';
|
||||
/* Project id 2843597 */
|
||||
src: url('//at.alicdn.com/t/font_2843597_kx4g4k3cyrh.woff2?t=1633846789896') format('woff2'),
|
||||
url('//at.alicdn.com/t/font_2843597_kx4g4k3cyrh.woff?t=1633846789896') format('woff'),
|
||||
url('//at.alicdn.com/t/font_2843597_kx4g4k3cyrh.ttf?t=1633846789896') format('truetype');
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: 'iconfont2';
|
||||
/* Project id 3757975 */
|
||||
src: url('//at.alicdn.com/t/c/font_3757975_9yihr8amvjk.woff2?t=1670469782943') format('woff2'),
|
||||
url('//at.alicdn.com/t/c/font_3757975_9yihr8amvjk.woff?t=1670469782943') format('woff'),
|
||||
url('//at.alicdn.com/t/c/font_3757975_9yihr8amvjk.ttf?t=1670469782943') format('truetype');
|
||||
}
|
||||
|
||||
.iconfont {
|
||||
font-family: "iconfont" !important;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.iconfont2 {
|
||||
font-family: "iconfont2" !important;
|
||||
font-size: 25rpx;
|
||||
font-style: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon-release:before {
|
||||
content: "\e61b";
|
||||
}
|
||||
|
||||
.icon-list-check:before {
|
||||
content: "\e667";
|
||||
}
|
||||
|
||||
.icon-add:before {
|
||||
content: "\e664";
|
||||
}
|
||||
|
||||
.icon-textformat:before {
|
||||
content: "\e8b8";
|
||||
}
|
||||
|
||||
.icon-image:before {
|
||||
content: "\e65b";
|
||||
}
|
||||
|
||||
.icon-photo:before {
|
||||
content: "\e65f";
|
||||
}
|
||||
|
||||
.icon-keyboard:before {
|
||||
content: "\e64c";
|
||||
}
|
||||
|
||||
.icon-undo:before {
|
||||
content: "\e6f0";
|
||||
}
|
||||
|
||||
.icon-redo:before {
|
||||
content: "\e6f1";
|
||||
}
|
||||
|
||||
.icon-bgcolors:before {
|
||||
content: "\eb95";
|
||||
}
|
||||
|
||||
.icon-fontbgcolor:before {
|
||||
content: "\e68d";
|
||||
}
|
||||
|
||||
.icon-indent:before {
|
||||
content: "\e7f3";
|
||||
}
|
||||
|
||||
.icon-outdent:before {
|
||||
content: "\e7f4";
|
||||
}
|
||||
|
||||
.icon-menu:before {
|
||||
content: "\e7f5";
|
||||
}
|
||||
|
||||
.icon-unorderedlist:before {
|
||||
content: "\e7f6";
|
||||
}
|
||||
|
||||
.icon-orderedlist:before {
|
||||
content: "\e7f7";
|
||||
}
|
||||
|
||||
.icon-align-right:before {
|
||||
content: "\e7f8";
|
||||
}
|
||||
|
||||
.icon-align-center:before {
|
||||
content: "\e7f9";
|
||||
}
|
||||
|
||||
.icon-align-left:before {
|
||||
content: "\e7fa";
|
||||
}
|
||||
|
||||
.icon-bold:before {
|
||||
content: "\e7fb";
|
||||
}
|
||||
|
||||
.icon-font-size:before {
|
||||
content: "\e7fd";
|
||||
}
|
||||
|
||||
.icon-line-height:before {
|
||||
content: "\e7fe";
|
||||
}
|
||||
|
||||
.icon-strikethrough:before {
|
||||
content: "\e7ff";
|
||||
}
|
||||
|
||||
.icon-underline:before {
|
||||
content: "\e800";
|
||||
}
|
||||
|
||||
.icon-italic:before {
|
||||
content: "\e801";
|
||||
}
|
||||
|
||||
.icon-check:before {
|
||||
content: "\e802";
|
||||
}
|
||||
|
||||
.icon-line:before {
|
||||
content: "\e803";
|
||||
}
|
||||
14
components/d-editor/util.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 处理html中的图片地址和宽度
|
||||
* resetClass: 是否将class="editor-- 更改为class="
|
||||
* EditorContext.setContents时img标签的class会自带一个前缀editor--,如原class="editor-img",EditorContext.setContents后class="editor--editor-img" */
|
||||
export const handleHtmlImage = (html = '', resetClass) => {
|
||||
var newHtml = html.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/ig, function(match, src) {
|
||||
let result = match
|
||||
//返回每个匹配的字符串
|
||||
if(resetClass) result = result.replace(/class=\"(.*)editor--/gi,'class="');
|
||||
result = result.replace(/\<img/gi, '<img style="max-width:100%;height:auto"');
|
||||
return result;
|
||||
});
|
||||
return newHtml;
|
||||
}
|
||||
71
components/d-empty/d-empty.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<view class="box">
|
||||
<image :src="image?image:images[mode]"></image>
|
||||
<slot v-if="!text">
|
||||
<view class="hiht">暂无商品,去<text @click="$emit('click')">添加商品</text></view>
|
||||
</slot>
|
||||
<view class="hiht" v-if="text" @click="$emit('click')">{{text}}</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* steps 内容为空
|
||||
* @description 该组件用于需要加载内容,但是加载的第一页数据就为空,提示一个"没有内容"的场景
|
||||
* @property {String} mode 设置模式(默认list)
|
||||
*/
|
||||
export default {
|
||||
name: 'd-empty',
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'list'
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
image: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
images: {
|
||||
type: [Object,Array],
|
||||
default: () => {
|
||||
return {
|
||||
'list': '../../static/image/list.png',
|
||||
'search': '../../static/image/search.png'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box {
|
||||
padding: 32rpx 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 200rpx;
|
||||
height: 173rpx;
|
||||
}
|
||||
|
||||
.hiht {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
margin-top: 32rpx;
|
||||
text-align: center;
|
||||
text {
|
||||
color: #6ACDBB;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
112
components/d-handwritten/d-handwritten.vue
Normal file
@@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<view>
|
||||
<u-popup v-model="show" mode="bottom" :closeable="true" @close="show=false" close-icon-pos='top-right'
|
||||
:safe-area-inset-bottom="true" :mask-close-able="false">
|
||||
<view class="handwritten flex-col flex-ali-center">
|
||||
<text class="title">签字确认</text>
|
||||
<view class="">
|
||||
<canvas :style="{width: '686rpx',height: '480rpx',border:'1px solid #2979FF'}" disable-scroll="true"
|
||||
data-id="1" @touchstart="penStart" @touchmove="penMove" @touchend="penEnd"
|
||||
canvas-id="canvas"></canvas>
|
||||
</view>
|
||||
<view class="flex-row" style="margin-top: 80rpx;">
|
||||
<view class="retDraw" @click="retDraw">重写</view>
|
||||
<view style="width: 343rpx;height: 86rpx;">
|
||||
<u-button :throttle-time="0" @click="saveCanvas();loading=true" type="primary" :loading="loading"
|
||||
:custom-style="{borderRadius:'0'}">确定</u-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Mycanvas from "@/common/js/handwriting.js";
|
||||
export default {
|
||||
name: 'd-handwritten',
|
||||
props: {
|
||||
// 是否显示d-handwritten
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: this.value,
|
||||
canvas: '',
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value() {
|
||||
this.show = this.value
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 清除画布
|
||||
retDraw() {
|
||||
this.canvas.retDraw();
|
||||
},
|
||||
// 笔迹开始
|
||||
penStart(event) {
|
||||
this.canvas.penStart(event);
|
||||
},
|
||||
// 笔迹移动
|
||||
penMove(event) {
|
||||
this.canvas.penMove(event);
|
||||
},
|
||||
// 笔迹结束
|
||||
penEnd(event) {
|
||||
this.canvas.penEnd(event);
|
||||
},
|
||||
// 保存
|
||||
async saveCanvas() {
|
||||
let pic = await this.canvas.saveCanvas(this);
|
||||
this.loading = false;
|
||||
this.$emit('saveCanvas', pic)
|
||||
}
|
||||
},
|
||||
onReady() {
|
||||
this.$nextTick(() => {
|
||||
this.canvas = new Mycanvas({
|
||||
lineColor: this.lineColor,
|
||||
lineSise: this.lineSise,
|
||||
canvasName: "canvas"
|
||||
}, this)
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.handwritten {
|
||||
width: 750rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 16rpx 16rpx 0px 0px;
|
||||
height: calc(840rpx + env(safe-area-inset-bottom));
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #323233;
|
||||
margin-top: 30rpx;
|
||||
margin-bottom: 48rpx;
|
||||
}
|
||||
|
||||
.retDraw {
|
||||
width: 343rpx;
|
||||
height: 86rpx;
|
||||
background: #FFFFFF rgba(41, 121, 255, 0);
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #2979FF;
|
||||
line-height: 86rpx;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
256
components/d-image/d-image.vue
Normal file
@@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<view class="u-image" @tap="onClick" :style="[wrapStyle, backgroundStyle]">
|
||||
<image v-if="!isError" :src="src" :mode="mode" @error="onErrorHandler" @load="onLoadHandler"
|
||||
:lazy-load="lazyLoad" class="u-image__image" :show-menu-by-longpress="showMenuByLongpress" :style="[{
|
||||
borderRadius: shape == 'circle' ? '50%' : $u.addUnit(borderRadius)
|
||||
},wrapStyle]"></image>
|
||||
<view v-if="showLoading && loading" class="u-image__loading" :style="{
|
||||
borderRadius: shape == 'circle' ? '50%' : $u.addUnit(borderRadius),
|
||||
backgroundColor: this.bgColor
|
||||
}">
|
||||
<slot v-if="$slots.loading" name="loading" />
|
||||
<u-icon v-else :name="loadingIcon" :width="width" :height="height"></u-icon>
|
||||
</view>
|
||||
<view v-if="showError && isError && !loading" class="u-image__error" :style="{
|
||||
borderRadius: shape == 'circle' ? '50%' : $u.addUnit(borderRadius)
|
||||
}">
|
||||
<slot v-if="$slots.error" name="error" />
|
||||
<u-icon v-else :name="errorIcon" :width="width" :height="height"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Image 图片
|
||||
* @description 此组件为uni-app的image组件的加强版,在继承了原有功能外,还支持淡入动画、加载中、加载失败提示、圆角值和形状等。
|
||||
* @tutorial https://uviewui.com/components/image.html
|
||||
* @property {String} src 图片地址
|
||||
* @property {String} mode 裁剪模式,见官网说明
|
||||
* @property {String | Number} width 宽度,单位任意,如果为数值,则为rpx单位(默认100%)
|
||||
* @property {String | Number} height 高度,单位任意,如果为数值,则为rpx单位(默认 auto)
|
||||
* @property {String} shape 图片形状,circle-圆形,square-方形(默认square)
|
||||
* @property {String | Number} border-radius 圆角值,单位任意,如果为数值,则为rpx单位(默认 0)
|
||||
* @property {Boolean} lazy-load 是否懒加载,仅微信小程序、App、百度小程序、字节跳动小程序有效(默认 true)
|
||||
* @property {Boolean} show-menu-by-longpress 是否开启长按图片显示识别小程序码菜单,仅微信小程序有效(默认 false)
|
||||
* @property {String} loading-icon 加载中的图标,或者小图片(默认 photo)
|
||||
* @property {String} error-icon 加载失败的图标,或者小图片(默认 error-circle)
|
||||
* @property {Boolean} show-loading 是否显示加载中的图标或者自定义的slot(默认 true)
|
||||
* @property {Boolean} show-error 是否显示加载错误的图标或者自定义的slot(默认 true)
|
||||
* @property {Boolean} fade 是否需要淡入效果(默认 true)
|
||||
* @property {String Number} width 传入图片路径时图片的宽度
|
||||
* @property {String Number} height 传入图片路径时图片的高度
|
||||
* @property {Boolean} webp 只支持网络资源,只对微信小程序有效(默认 false)
|
||||
* @property {String | Number} duration 搭配fade参数的过渡时间,单位ms(默认 500)
|
||||
* @event {Function} click 点击图片时触发
|
||||
* @event {Function} error 图片加载失败时触发
|
||||
* @event {Function} load 图片加载成功时触发
|
||||
* @example <u-image width="100%" height="300rpx" :src="src"></u-image>
|
||||
*/
|
||||
export default {
|
||||
name: 'd-image',
|
||||
props: {
|
||||
// 图片地址
|
||||
src: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 裁剪模式
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'aspectFill'
|
||||
},
|
||||
// 宽度,单位任意
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: '100%'
|
||||
},
|
||||
// 高度,单位任意
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: 'auto'
|
||||
},
|
||||
// 图片形状,circle-圆形,square-方形
|
||||
shape: {
|
||||
type: String,
|
||||
default: 'square'
|
||||
},
|
||||
// 圆角,单位任意
|
||||
borderRadius: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
// 是否懒加载,微信小程序、App、百度小程序、字节跳动小程序
|
||||
lazyLoad: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 开启长按图片显示识别微信小程序码菜单
|
||||
showMenuByLongpress: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 加载中的图标,或者小图片
|
||||
loadingIcon: {
|
||||
type: String,
|
||||
default: 'photo'
|
||||
},
|
||||
// 加载失败的图标,或者小图片
|
||||
errorIcon: {
|
||||
type: String,
|
||||
default: 'error-circle'
|
||||
},
|
||||
// 是否显示加载中的图标或者自定义的slot
|
||||
showLoading: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否显示加载错误的图标或者自定义的slot
|
||||
showError: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否需要淡入效果
|
||||
fade: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 只支持网络资源,只对微信小程序有效
|
||||
webp: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 过渡时间,单位ms
|
||||
duration: {
|
||||
type: [String, Number],
|
||||
default: 500
|
||||
},
|
||||
// 背景颜色,用于深色页面加载图片时,为了和背景色融合
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: '#f3f4f6'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 图片是否加载错误,如果是,则显示错误占位图
|
||||
isError: false,
|
||||
// 初始化组件时,默认为加载中状态
|
||||
loading: true,
|
||||
// 不透明度,为了实现淡入淡出的效果
|
||||
opacity: 1,
|
||||
// 过渡时间,因为props的值无法修改,故需要一个中间值
|
||||
durationTime: this.duration,
|
||||
// 图片加载完成时,去掉背景颜色,因为如果是png图片,就会显示灰色的背景
|
||||
backgroundStyle: {}
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
src: {
|
||||
immediate: true,
|
||||
handler(n) {
|
||||
if (!n) {
|
||||
// 如果传入null或者'',或者false,或者undefined,标记为错误状态
|
||||
this.isError = true;
|
||||
this.loading = false;
|
||||
} else {
|
||||
this.isError = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
wrapStyle() {
|
||||
let style = {};
|
||||
// 通过调用addUnit()方法,如果有单位,如百分比,px单位等,直接返回,如果是纯粹的数值,则加上rpx单位
|
||||
style.width = this.$u.addUnit(this.width);
|
||||
style.height = this.$u.addUnit(this.height);
|
||||
// 如果是配置了圆形,设置50%的圆角,否则按照默认的配置值
|
||||
style.borderRadius = this.shape == 'circle' ? '50%' : this.$u.addUnit(this.borderRadius);
|
||||
// 如果设置圆角,必须要有hidden,否则可能圆角无效
|
||||
style.overflow = this.borderRadius > 0 ? 'hidden' : 'visible';
|
||||
if (this.fade) {
|
||||
style.opacity = this.opacity;
|
||||
style.transition = `opacity ${Number(this.durationTime) / 1000}s ease-in-out`;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 点击图片
|
||||
onClick() {
|
||||
this.$emit('click');
|
||||
},
|
||||
// 图片加载失败
|
||||
onErrorHandler(err) {
|
||||
this.loading = false;
|
||||
this.isError = true;
|
||||
this.$emit('error', err);
|
||||
},
|
||||
// 图片加载完成,标记loading结束
|
||||
onLoadHandler() {
|
||||
this.loading = false;
|
||||
this.isError = false;
|
||||
this.$emit('load');
|
||||
// 如果不需要动画效果,就不执行下方代码,同时移除加载时的背景颜色
|
||||
// 否则无需fade效果时,png图片依然能看到下方的背景色
|
||||
if (!this.fade) return this.removeBgColor();
|
||||
// 原来opacity为1(不透明,是为了显示占位图),改成0(透明,意味着该元素显示的是背景颜色,默认的灰色),再改成1,是为了获得过渡效果
|
||||
this.opacity = 0;
|
||||
// 这里设置为0,是为了图片展示到背景全透明这个过程时间为0,延时之后延时之后重新设置为duration,是为了获得背景透明(灰色)
|
||||
// 到图片展示的过程中的淡入效果
|
||||
this.durationTime = 0;
|
||||
// 延时50ms,否则在浏览器H5,过渡效果无效
|
||||
setTimeout(() => {
|
||||
this.durationTime = this.duration;
|
||||
this.opacity = 1;
|
||||
setTimeout(() => {
|
||||
this.removeBgColor();
|
||||
}, this.durationTime);
|
||||
}, 50);
|
||||
},
|
||||
// 移除图片的背景色
|
||||
removeBgColor() {
|
||||
// 淡入动画过渡完成后,将背景设置为透明色,否则png图片会看到灰色的背景
|
||||
this.backgroundStyle = {
|
||||
backgroundColor: 'transparent'
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// 定义混入指令,用于在非nvue环境下的flex定义,因为nvue没有display属性,会报错
|
||||
@mixin vue-flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
flex-direction: $direction;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.u-image {
|
||||
position: relative;
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
|
||||
&__image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
&__loading,
|
||||
&__error {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
@include vue-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: $u-bg-color;
|
||||
color: $u-tips-color;
|
||||
font-size: 46rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
466
components/d-input-code/d-input-code.vue
Normal file
@@ -0,0 +1,466 @@
|
||||
<template>
|
||||
<view
|
||||
class="u-input"
|
||||
:class="{
|
||||
'u-input--border': border,
|
||||
'u-input--error': validateState
|
||||
}"
|
||||
:style="{
|
||||
padding: `0 ${border ? 20 : 34}rpx`,
|
||||
borderColor: borderColor,
|
||||
textAlign: inputAlign,
|
||||
borderRadius:borderRadius
|
||||
}"
|
||||
@tap.stop="inputClick"
|
||||
>
|
||||
<view
|
||||
class="u-input__prefix-icon"
|
||||
v-if="prefixIcon || $slots.prefix"
|
||||
>
|
||||
<slot name="prefix">
|
||||
<u-icon
|
||||
:name="prefixIcon"
|
||||
:size="prefixIconSize"
|
||||
:customStyle="prefixIconStyle"
|
||||
:color="prefixIconColor"
|
||||
></u-icon>
|
||||
</slot>
|
||||
</view>
|
||||
<textarea
|
||||
v-if="type == 'textarea'"
|
||||
class="u-input__input u-input__textarea"
|
||||
:style="[getStyle]"
|
||||
:value="defaultValue"
|
||||
:placeholder="placeholder"
|
||||
:placeholderStyle="placeholderStyle"
|
||||
:disabled="disabled"
|
||||
:maxlength="inputMaxlength"
|
||||
:fixed="fixed"
|
||||
:focus="focus"
|
||||
:autoHeight="autoHeight"
|
||||
:selection-end="uSelectionEnd"
|
||||
:selection-start="uSelectionStart"
|
||||
:cursor-spacing="getCursorSpacing"
|
||||
:show-confirm-bar="showConfirmbar"
|
||||
@input="handleInput"
|
||||
@blur="handleBlur"
|
||||
@focus="onFocus"
|
||||
@confirm="onConfirm"
|
||||
/>
|
||||
<input
|
||||
v-else
|
||||
class="u-input__input"
|
||||
:type="type == 'password' ? 'text' : type"
|
||||
:style="[getStyle]"
|
||||
:value="defaultValue"
|
||||
|
||||
:placeholder="placeholder"
|
||||
:placeholderStyle="placeholderStyle"
|
||||
:disabled="disabled || type === 'select'"
|
||||
:maxlength="inputMaxlength"
|
||||
:focus="focus"
|
||||
:confirmType="confirmType"
|
||||
:cursor-spacing="getCursorSpacing"
|
||||
:selection-end="uSelectionEnd"
|
||||
:selection-start="uSelectionStart"
|
||||
:show-confirm-bar="showConfirmbar"
|
||||
@focus="onFocus"
|
||||
@blur="handleBlur"
|
||||
@input="handleInput"
|
||||
@confirm="onConfirm"
|
||||
/>
|
||||
<View class="line" />
|
||||
<view style="color:#536DFE;" @click="send">
|
||||
{{codeText}}
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
/**
|
||||
* input 输入框
|
||||
* @description 此组件为一个输入框,默认没有边框和样式,是专门为配合表单组件u-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。
|
||||
* @tutorial http://uviewui.com/components/input.html
|
||||
* @property {String} type 模式选择,见官网说明
|
||||
* @property {Boolean} clearable 是否显示右侧的清除图标(默认true)
|
||||
* @property {} v-model 用于双向绑定输入框的值
|
||||
* @property {String} input-align 输入框文字的对齐方式(默认left)
|
||||
* @property {String} placeholder placeholder显示值(默认 '请输入内容')
|
||||
* @property {Boolean} disabled 是否禁用输入框(默认false)
|
||||
* @property {String Number} maxlength 输入框的最大可输入长度(默认140)
|
||||
* @property {String Number} selection-start 光标起始位置,自动聚焦时有效,需与selection-end搭配使用(默认-1)
|
||||
* @property {String Number} maxlength 光标结束位置,自动聚焦时有效,需与selection-start搭配使用(默认-1)
|
||||
* @property {String Number} cursor-spacing 指定光标与键盘的距离,单位px(默认0)
|
||||
* @property {String} placeholderStyle placeholder的样式,字符串形式,如"color: red;"(默认 "color: #c0c4cc;")
|
||||
* @property {String} confirm-type 设置键盘右下角按钮的文字,仅在type为text时生效(默认done)
|
||||
* @property {Object} custom-style 自定义输入框的样式,对象形式
|
||||
* @property {Boolean} focus 是否自动获得焦点(默认false)
|
||||
* @property {Boolean} fixed 如果type为textarea,且在一个"position:fixed"的区域,需要指明为true(默认false)
|
||||
* @property {Boolean} password-icon type为password时,是否显示右侧的密码查看图标(默认true)
|
||||
* @property {Boolean} border 是否显示边框(默认false)
|
||||
* @property {String} border-color 输入框的边框颜色(默认#dcdfe6)
|
||||
* @property {Boolean} auto-height 是否自动增高输入区域,type为textarea时有效(默认true)
|
||||
* @property {String Number} height 高度,单位rpx(text类型时为70,textarea时为100)
|
||||
* @example <u-input v-model="value" :type="type" :border="border" />
|
||||
*/
|
||||
export default {
|
||||
name: 'u-input',
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
// 输入框的类型,textarea,text,number
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text'
|
||||
},
|
||||
inputAlign: {
|
||||
type: String,
|
||||
default: 'left'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请输入内容'
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxlength: {
|
||||
type: [Number, String],
|
||||
default: 140
|
||||
},
|
||||
placeholderStyle: {
|
||||
type: String,
|
||||
default: 'color: #c0c4cc;'
|
||||
},
|
||||
codeText: {
|
||||
type: String,
|
||||
default: '发送验证码'
|
||||
},
|
||||
|
||||
confirmType: {
|
||||
type: String,
|
||||
default: 'done'
|
||||
},
|
||||
// 输入框的自定义样式
|
||||
customStyle: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
// 图标的自定义样式
|
||||
prefixIconStyle: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
// 如果 textarea 是在一个 position:fixed 的区域,需要显示指定属性 fixed 为 true
|
||||
fixed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否自动获得焦点
|
||||
focus: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 密码类型时,是否显示右侧的密码图标
|
||||
passwordIcon: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// input|textarea是否显示边框
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 输入框的边框颜色
|
||||
borderColor: {
|
||||
type: String,
|
||||
default: '#dcdfe6'
|
||||
},
|
||||
autoHeight: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// type=select时,旋转右侧的图标,标识当前处于打开还是关闭select的状态
|
||||
// open-打开,close-关闭
|
||||
selectOpen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 高度,单位rpx
|
||||
height: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
// 是否可清空
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 指定光标与键盘的距离,单位 px
|
||||
cursorSpacing: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
// 光标起始位置,自动聚焦时有效,需与selection-end搭配使用
|
||||
selectionStart: {
|
||||
type: [Number, String],
|
||||
default: -1
|
||||
},
|
||||
// 光标结束位置,自动聚焦时有效,需与selection-start搭配使用
|
||||
selectionEnd: {
|
||||
type: [Number, String],
|
||||
default: -1
|
||||
},
|
||||
// 是否自动去除两端的空格
|
||||
trim: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否显示键盘上方带有”完成“按钮那一栏
|
||||
showConfirmbar:{
|
||||
type:Boolean,
|
||||
default:true
|
||||
},
|
||||
// 左边图标名称
|
||||
prefixIcon:{
|
||||
type:String,
|
||||
default:''
|
||||
},
|
||||
// 左边图标大小
|
||||
prefixIconSize:{
|
||||
type:[String,Number],
|
||||
default:'30rpx'
|
||||
},
|
||||
// 左边图标颜色
|
||||
prefixIconColor:{
|
||||
type:String,
|
||||
default:''
|
||||
},
|
||||
// 边框圆角
|
||||
borderRadius:{
|
||||
type:String,
|
||||
default:'6rpx'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultValue: this.value,
|
||||
inputHeight: 70, // input的高度
|
||||
textareaHeight: 100, // textarea的高度
|
||||
validateState: false, // 当前input的验证状态,用于错误时,边框是否改为红色
|
||||
focused: false, // 当前是否处于获得焦点的状态
|
||||
showPassword: false, // 是否预览密码
|
||||
lastValue: '', // 用于头条小程序,判断@input中,前后的值是否发生了变化,因为头条中文下,按下键没有输入内容,也会触发@input时间
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
value(nVal, oVal) {
|
||||
this.defaultValue = nVal;
|
||||
// 当值发生变化,且为select类型时(此时input被设置为disabled,不会触发@input事件),模拟触发@input事件
|
||||
if(nVal != oVal && this.type == 'select') this.handleInput({
|
||||
detail: {
|
||||
value: nVal
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,给用户可以传入字符串数值
|
||||
inputMaxlength() {
|
||||
return Number(this.maxlength);
|
||||
},
|
||||
getStyle() {
|
||||
let style = {};
|
||||
// 如果没有自定义高度,就根据type为input还是textare来分配一个默认的高度
|
||||
style.minHeight = this.height ? this.height + 'rpx' : this.type == 'textarea' ?
|
||||
this.textareaHeight + 'rpx' : this.inputHeight + 'rpx';
|
||||
style = Object.assign(style, this.customStyle);
|
||||
return style;
|
||||
},
|
||||
//
|
||||
getCursorSpacing() {
|
||||
return Number(this.cursorSpacing);
|
||||
},
|
||||
// 光标起始位置
|
||||
uSelectionStart() {
|
||||
return String(this.selectionStart);
|
||||
},
|
||||
// 光标结束位置
|
||||
uSelectionEnd() {
|
||||
return String(this.selectionEnd);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 监听u-form-item发出的错误事件,将输入框边框变红色
|
||||
this.$on('on-form-item-error', this.onFormItemError);
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 派发 (向上查找) (一个)
|
||||
* @param componentName // 需要找的组件的名称
|
||||
* @param eventName // 事件名称
|
||||
* @param params // 需要传递的参数
|
||||
*/
|
||||
dispatch(componentName, eventName, params) {
|
||||
let parent = this.$parent || this.$root;//$parent 找到最近的父节点 $root 根节点
|
||||
let name = parent.$options.name; // 获取当前组件实例的name
|
||||
// 如果当前有节点 && 当前没名称 且 当前名称等于需要传进来的名称的时候就去查找当前的节点
|
||||
// 循环出当前名称的一样的组件实例
|
||||
while (parent && (!name||name!==componentName)) {
|
||||
parent = parent.$parent;
|
||||
if (parent) {
|
||||
name = parent.$options.name;
|
||||
}
|
||||
}
|
||||
// 有节点表示当前找到了name一样的实例
|
||||
if (parent) {
|
||||
parent.$emit.apply(parent,[eventName].concat(params))
|
||||
}
|
||||
},
|
||||
/**
|
||||
* change 事件
|
||||
* @param event
|
||||
*/
|
||||
handleInput(event) {
|
||||
let value = event.detail.value;
|
||||
// 判断是否去除空格
|
||||
if(this.trim) value = this.$u.trim(value);
|
||||
// vue 原生的方法 return 出去
|
||||
this.$emit('input', value);
|
||||
// 当前model 赋值
|
||||
this.defaultValue = value;
|
||||
// 过一个生命周期再发送事件给u-form-item,否则this.$emit('input')更新了父组件的值,但是微信小程序上
|
||||
// 尚未更新到u-form-item,导致获取的值为空,从而校验混论
|
||||
// 这里不能延时时间太短,或者使用this.$nextTick,否则在头条上,会造成混乱
|
||||
setTimeout(() => {
|
||||
// 头条小程序由于自身bug,导致中文下,每按下一个键(尚未完成输入),都会触发一次@input,导致错误,这里进行判断处理
|
||||
// #ifdef MP-TOUTIAO
|
||||
if(this.$u.trim(value) == this.lastValue) return ;
|
||||
this.lastValue = value;
|
||||
// #endif
|
||||
// 将当前的值发送到 u-form-item 进行校验
|
||||
this.dispatch('u-form-item', 'on-form-change', value);
|
||||
}, 40)
|
||||
},
|
||||
/**
|
||||
* blur 事件
|
||||
* @param event
|
||||
*/
|
||||
handleBlur(event) {
|
||||
// 最开始使用的是监听图标@touchstart事件,自从hx2.8.4后,此方法在微信小程序出错
|
||||
// 这里改为监听点击事件,手点击清除图标时,同时也发生了@blur事件,导致图标消失而无法点击,这里做一个延时
|
||||
setTimeout(() => {
|
||||
this.focused = false;
|
||||
}, 100)
|
||||
// vue 原生的方法 return 出去
|
||||
this.$emit('blur', event.detail.value);
|
||||
setTimeout(() => {
|
||||
// 头条小程序由于自身bug,导致中文下,每按下一个键(尚未完成输入),都会触发一次@input,导致错误,这里进行判断处理
|
||||
// #ifdef MP-TOUTIAO
|
||||
if(this.$u.trim(value) == this.lastValue) return ;
|
||||
this.lastValue = value;
|
||||
// #endif
|
||||
// 将当前的值发送到 u-form-item 进行校验
|
||||
this.dispatch('u-form-item', 'on-form-blur', event.detail.value);
|
||||
}, 40)
|
||||
},
|
||||
onFormItemError(status) {
|
||||
this.validateState = status;
|
||||
},
|
||||
onFocus(event) {
|
||||
this.focused = true;
|
||||
this.$emit('focus');
|
||||
},
|
||||
onConfirm(e) {
|
||||
this.$emit('confirm', e.detail.value);
|
||||
},
|
||||
onClear(event) {
|
||||
this.$emit('input', '');
|
||||
},
|
||||
inputClick() {
|
||||
this.$emit('click');
|
||||
},
|
||||
send(e) {
|
||||
this.$emit('sendCode');
|
||||
},
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@mixin vue-flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
flex-direction: $direction;
|
||||
/* #endif */
|
||||
}
|
||||
.line{
|
||||
width: 0px;
|
||||
height: 58rpx;
|
||||
opacity: 1;
|
||||
margin: 0 20rpx;
|
||||
border: 1rpx solid #D5D9E5;
|
||||
}
|
||||
.u-input {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
background-color: #f9fafb;
|
||||
align-items: center;
|
||||
@include vue-flex;
|
||||
&__prefix-icon{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
&__input {
|
||||
//height: $u-form-item-height;
|
||||
font-size: 28rpx;
|
||||
color: $u-main-color;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__textarea {
|
||||
width: auto;
|
||||
font-size: 28rpx;
|
||||
color: $u-main-color;
|
||||
padding: 10rpx 0;
|
||||
line-height: normal;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&--border {
|
||||
border-radius: 6rpx;
|
||||
border-radius: 4px;
|
||||
border: 1px solid $u-form-item-border-color;
|
||||
}
|
||||
|
||||
&--error {
|
||||
border-color: $u-type-error!important;
|
||||
}
|
||||
|
||||
&__right-icon {
|
||||
|
||||
&__item {
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
&--select {
|
||||
transition: transform .4s;
|
||||
|
||||
&--reverse {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
459
components/d-input/d-input.vue
Normal file
@@ -0,0 +1,459 @@
|
||||
<template>
|
||||
<view
|
||||
class="u-input"
|
||||
:class="{
|
||||
'u-input--border': border,
|
||||
'u-input--error': validateState
|
||||
}"
|
||||
:style="{
|
||||
padding: `0 ${border ? 20 : 34}rpx`,
|
||||
borderColor: borderColor,
|
||||
textAlign: inputAlign,
|
||||
borderRadius:borderRadius
|
||||
}"
|
||||
@tap.stop="inputClick"
|
||||
>
|
||||
<view
|
||||
class="u-input__prefix-icon"
|
||||
v-if="prefixIcon || $slots.prefix"
|
||||
>
|
||||
<slot name="prefix">
|
||||
<u-icon
|
||||
:name="prefixIcon"
|
||||
:size="prefixIconSize"
|
||||
:customStyle="prefixIconStyle"
|
||||
:color="prefixIconColor"
|
||||
></u-icon>
|
||||
</slot>
|
||||
</view>
|
||||
<textarea
|
||||
v-if="type == 'textarea'"
|
||||
class="u-input__input u-input__textarea"
|
||||
:style="[getStyle]"
|
||||
:value="defaultValue"
|
||||
:placeholder="placeholder"
|
||||
:placeholderStyle="placeholderStyle"
|
||||
:disabled="disabled"
|
||||
:maxlength="inputMaxlength"
|
||||
:fixed="fixed"
|
||||
:focus="focus"
|
||||
:autoHeight="autoHeight"
|
||||
:selection-end="uSelectionEnd"
|
||||
:selection-start="uSelectionStart"
|
||||
:cursor-spacing="getCursorSpacing"
|
||||
:show-confirm-bar="showConfirmbar"
|
||||
@input="handleInput"
|
||||
@blur="handleBlur"
|
||||
@focus="onFocus"
|
||||
@confirm="onConfirm"
|
||||
/>
|
||||
<input
|
||||
v-else
|
||||
class="u-input__input"
|
||||
:type="type == 'password' ? 'text' : type"
|
||||
:style="[getStyle]"
|
||||
:value="defaultValue"
|
||||
:password="type == 'password' && !showPassword"
|
||||
:placeholder="placeholder"
|
||||
:placeholderStyle="placeholderStyle"
|
||||
:disabled="disabled || type === 'select'"
|
||||
:maxlength="inputMaxlength"
|
||||
:focus="focus"
|
||||
:confirmType="confirmType"
|
||||
:cursor-spacing="getCursorSpacing"
|
||||
:selection-end="uSelectionEnd"
|
||||
:selection-start="uSelectionStart"
|
||||
:show-confirm-bar="showConfirmbar"
|
||||
@focus="onFocus"
|
||||
@blur="handleBlur"
|
||||
@input="handleInput"
|
||||
@confirm="onConfirm"
|
||||
/>
|
||||
<view class="u-input__right-icon u-flex">
|
||||
<view class="u-input__right-icon__clear u-input__right-icon__item" @tap="onClear" v-if="clearable && value != '' && focused">
|
||||
<u-icon size="32" name="close-circle-fill" color="#c0c4cc"/>
|
||||
</view>
|
||||
<view class="u-input__right-icon__clear u-input__right-icon__item" v-if="passwordIcon && type == 'password'">
|
||||
<u-icon size="32" :name="!showPassword ? 'eye' : 'eye-fill'" color="#c0c4cc" @click="showPassword = !showPassword"/>
|
||||
</view>
|
||||
<view class="u-input__right-icon--select u-input__right-icon__item" v-if="type == 'select'" :class="{
|
||||
'u-input__right-icon--select--reverse': selectOpen
|
||||
}">
|
||||
<u-icon name="arrow-down-fill" size="26" color="#c0c4cc"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
/**
|
||||
* input 输入框
|
||||
* @description 此组件为一个输入框,默认没有边框和样式,是专门为配合表单组件u-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。
|
||||
* @tutorial http://uviewui.com/components/input.html
|
||||
* @property {String} type 模式选择,见官网说明
|
||||
* @property {Boolean} clearable 是否显示右侧的清除图标(默认true)
|
||||
* @property {} v-model 用于双向绑定输入框的值
|
||||
* @property {String} input-align 输入框文字的对齐方式(默认left)
|
||||
* @property {String} placeholder placeholder显示值(默认 '请输入内容')
|
||||
* @property {Boolean} disabled 是否禁用输入框(默认false)
|
||||
* @property {String Number} maxlength 输入框的最大可输入长度(默认140)
|
||||
* @property {String Number} selection-start 光标起始位置,自动聚焦时有效,需与selection-end搭配使用(默认-1)
|
||||
* @property {String Number} maxlength 光标结束位置,自动聚焦时有效,需与selection-start搭配使用(默认-1)
|
||||
* @property {String Number} cursor-spacing 指定光标与键盘的距离,单位px(默认0)
|
||||
* @property {String} placeholderStyle placeholder的样式,字符串形式,如"color: red;"(默认 "color: #c0c4cc;")
|
||||
* @property {String} confirm-type 设置键盘右下角按钮的文字,仅在type为text时生效(默认done)
|
||||
* @property {Object} custom-style 自定义输入框的样式,对象形式
|
||||
* @property {Boolean} focus 是否自动获得焦点(默认false)
|
||||
* @property {Boolean} fixed 如果type为textarea,且在一个"position:fixed"的区域,需要指明为true(默认false)
|
||||
* @property {Boolean} password-icon type为password时,是否显示右侧的密码查看图标(默认true)
|
||||
* @property {Boolean} border 是否显示边框(默认false)
|
||||
* @property {String} border-color 输入框的边框颜色(默认#dcdfe6)
|
||||
* @property {Boolean} auto-height 是否自动增高输入区域,type为textarea时有效(默认true)
|
||||
* @property {String Number} height 高度,单位rpx(text类型时为70,textarea时为100)
|
||||
* @example <u-input v-model="value" :type="type" :border="border" />
|
||||
*/
|
||||
export default {
|
||||
name: 'u-input',
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
// 输入框的类型,textarea,text,number
|
||||
type: {
|
||||
type: String,
|
||||
default: 'text'
|
||||
},
|
||||
inputAlign: {
|
||||
type: String,
|
||||
default: 'left'
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请输入内容'
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxlength: {
|
||||
type: [Number, String],
|
||||
default: 140
|
||||
},
|
||||
placeholderStyle: {
|
||||
type: String,
|
||||
default: 'color: #c0c4cc;'
|
||||
},
|
||||
confirmType: {
|
||||
type: String,
|
||||
default: 'done'
|
||||
},
|
||||
// 输入框的自定义样式
|
||||
customStyle: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
// 图标的自定义样式
|
||||
prefixIconStyle: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
// 如果 textarea 是在一个 position:fixed 的区域,需要显示指定属性 fixed 为 true
|
||||
fixed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否自动获得焦点
|
||||
focus: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 密码类型时,是否显示右侧的密码图标
|
||||
passwordIcon: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// input|textarea是否显示边框
|
||||
border: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 输入框的边框颜色
|
||||
borderColor: {
|
||||
type: String,
|
||||
default: '#dcdfe6'
|
||||
},
|
||||
autoHeight: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// type=select时,旋转右侧的图标,标识当前处于打开还是关闭select的状态
|
||||
// open-打开,close-关闭
|
||||
selectOpen: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 高度,单位rpx
|
||||
height: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
// 是否可清空
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 指定光标与键盘的距离,单位 px
|
||||
cursorSpacing: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
// 光标起始位置,自动聚焦时有效,需与selection-end搭配使用
|
||||
selectionStart: {
|
||||
type: [Number, String],
|
||||
default: -1
|
||||
},
|
||||
// 光标结束位置,自动聚焦时有效,需与selection-start搭配使用
|
||||
selectionEnd: {
|
||||
type: [Number, String],
|
||||
default: -1
|
||||
},
|
||||
// 是否自动去除两端的空格
|
||||
trim: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否显示键盘上方带有”完成“按钮那一栏
|
||||
showConfirmbar:{
|
||||
type:Boolean,
|
||||
default:true
|
||||
},
|
||||
// 左边图标名称
|
||||
prefixIcon:{
|
||||
type:String,
|
||||
default:''
|
||||
},
|
||||
// 左边图标大小
|
||||
prefixIconSize:{
|
||||
type:[String,Number],
|
||||
default:'30rpx'
|
||||
},
|
||||
// 左边图标颜色
|
||||
prefixIconColor:{
|
||||
type:String,
|
||||
default:''
|
||||
},
|
||||
// 边框圆角
|
||||
borderRadius:{
|
||||
type:String,
|
||||
default:'6rpx'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
defaultValue: this.value,
|
||||
inputHeight: 70, // input的高度
|
||||
textareaHeight: 100, // textarea的高度
|
||||
validateState: false, // 当前input的验证状态,用于错误时,边框是否改为红色
|
||||
focused: false, // 当前是否处于获得焦点的状态
|
||||
showPassword: false, // 是否预览密码
|
||||
lastValue: '', // 用于头条小程序,判断@input中,前后的值是否发生了变化,因为头条中文下,按下键没有输入内容,也会触发@input时间
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
value(nVal, oVal) {
|
||||
this.defaultValue = nVal;
|
||||
// 当值发生变化,且为select类型时(此时input被设置为disabled,不会触发@input事件),模拟触发@input事件
|
||||
if(nVal != oVal && this.type == 'select') this.handleInput({
|
||||
detail: {
|
||||
value: nVal
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,给用户可以传入字符串数值
|
||||
inputMaxlength() {
|
||||
return Number(this.maxlength);
|
||||
},
|
||||
getStyle() {
|
||||
let style = {};
|
||||
// 如果没有自定义高度,就根据type为input还是textare来分配一个默认的高度
|
||||
style.minHeight = this.height ? this.height + 'rpx' : this.type == 'textarea' ?
|
||||
this.textareaHeight + 'rpx' : this.inputHeight + 'rpx';
|
||||
style = Object.assign(style, this.customStyle);
|
||||
return style;
|
||||
},
|
||||
//
|
||||
getCursorSpacing() {
|
||||
return Number(this.cursorSpacing);
|
||||
},
|
||||
// 光标起始位置
|
||||
uSelectionStart() {
|
||||
return String(this.selectionStart);
|
||||
},
|
||||
// 光标结束位置
|
||||
uSelectionEnd() {
|
||||
return String(this.selectionEnd);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 监听u-form-item发出的错误事件,将输入框边框变红色
|
||||
this.$on('on-form-item-error', this.onFormItemError);
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 派发 (向上查找) (一个)
|
||||
* @param componentName // 需要找的组件的名称
|
||||
* @param eventName // 事件名称
|
||||
* @param params // 需要传递的参数
|
||||
*/
|
||||
dispatch(componentName, eventName, params) {
|
||||
let parent = this.$parent || this.$root;//$parent 找到最近的父节点 $root 根节点
|
||||
let name = parent.$options.name; // 获取当前组件实例的name
|
||||
// 如果当前有节点 && 当前没名称 且 当前名称等于需要传进来的名称的时候就去查找当前的节点
|
||||
// 循环出当前名称的一样的组件实例
|
||||
while (parent && (!name||name!==componentName)) {
|
||||
parent = parent.$parent;
|
||||
if (parent) {
|
||||
name = parent.$options.name;
|
||||
}
|
||||
}
|
||||
// 有节点表示当前找到了name一样的实例
|
||||
if (parent) {
|
||||
parent.$emit.apply(parent,[eventName].concat(params))
|
||||
}
|
||||
},
|
||||
/**
|
||||
* change 事件
|
||||
* @param event
|
||||
*/
|
||||
handleInput(event) {
|
||||
let value = event.detail.value;
|
||||
// 判断是否去除空格
|
||||
if(this.trim) value = this.$u.trim(value);
|
||||
// vue 原生的方法 return 出去
|
||||
this.$emit('input', value);
|
||||
// 当前model 赋值
|
||||
this.defaultValue = value;
|
||||
// 过一个生命周期再发送事件给u-form-item,否则this.$emit('input')更新了父组件的值,但是微信小程序上
|
||||
// 尚未更新到u-form-item,导致获取的值为空,从而校验混论
|
||||
// 这里不能延时时间太短,或者使用this.$nextTick,否则在头条上,会造成混乱
|
||||
setTimeout(() => {
|
||||
// 头条小程序由于自身bug,导致中文下,每按下一个键(尚未完成输入),都会触发一次@input,导致错误,这里进行判断处理
|
||||
// #ifdef MP-TOUTIAO
|
||||
if(this.$u.trim(value) == this.lastValue) return ;
|
||||
this.lastValue = value;
|
||||
// #endif
|
||||
// 将当前的值发送到 u-form-item 进行校验
|
||||
this.dispatch('u-form-item', 'on-form-change', value);
|
||||
}, 40)
|
||||
},
|
||||
/**
|
||||
* blur 事件
|
||||
* @param event
|
||||
*/
|
||||
handleBlur(event) {
|
||||
// 最开始使用的是监听图标@touchstart事件,自从hx2.8.4后,此方法在微信小程序出错
|
||||
// 这里改为监听点击事件,手点击清除图标时,同时也发生了@blur事件,导致图标消失而无法点击,这里做一个延时
|
||||
setTimeout(() => {
|
||||
this.focused = false;
|
||||
}, 100)
|
||||
// vue 原生的方法 return 出去
|
||||
this.$emit('blur', event.detail.value);
|
||||
setTimeout(() => {
|
||||
// 头条小程序由于自身bug,导致中文下,每按下一个键(尚未完成输入),都会触发一次@input,导致错误,这里进行判断处理
|
||||
// #ifdef MP-TOUTIAO
|
||||
if(this.$u.trim(value) == this.lastValue) return ;
|
||||
this.lastValue = value;
|
||||
// #endif
|
||||
// 将当前的值发送到 u-form-item 进行校验
|
||||
this.dispatch('u-form-item', 'on-form-blur', event.detail.value);
|
||||
}, 40)
|
||||
},
|
||||
onFormItemError(status) {
|
||||
this.validateState = status;
|
||||
},
|
||||
onFocus(event) {
|
||||
this.focused = true;
|
||||
this.$emit('focus');
|
||||
},
|
||||
onConfirm(e) {
|
||||
this.$emit('confirm', e.detail.value);
|
||||
},
|
||||
onClear(event) {
|
||||
this.$emit('input', '');
|
||||
},
|
||||
inputClick() {
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@mixin vue-flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
flex-direction: $direction;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.u-input {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
background-color: #f9fafb;
|
||||
@include vue-flex;
|
||||
&__prefix-icon{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
&__input {
|
||||
//height: $u-form-item-height;
|
||||
font-size: 28rpx;
|
||||
color: $u-main-color;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__textarea {
|
||||
width: auto;
|
||||
font-size: 28rpx;
|
||||
color: $u-main-color;
|
||||
padding: 10rpx 0;
|
||||
line-height: normal;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&--border {
|
||||
border-radius: 6rpx;
|
||||
border-radius: 4px;
|
||||
border: 1px solid $u-form-item-border-color;
|
||||
}
|
||||
|
||||
&--error {
|
||||
border-color: $u-type-error!important;
|
||||
}
|
||||
|
||||
&__right-icon {
|
||||
|
||||
&__item {
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
&--select {
|
||||
transition: transform .4s;
|
||||
|
||||
&--reverse {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
344
components/d-loading-icon/d-loading-icon.vue
Normal file
@@ -0,0 +1,344 @@
|
||||
<template>
|
||||
<view class="u-loading-icon" :style="[$d.addStyle(customStyle)]" :class="[vertical && 'u-loading-icon--vertical']"
|
||||
v-if="show">
|
||||
<view v-if="!webviewHide" class="u-loading-icon__spinner" :class="[`u-loading-icon__spinner--${mode}`]"
|
||||
ref="ani" :style="{
|
||||
color: color,
|
||||
width: $u.addUnit(size),
|
||||
height: $u.addUnit(size),
|
||||
borderTopColor: color,
|
||||
borderBottomColor: otherBorderColor,
|
||||
borderLeftColor: otherBorderColor,
|
||||
borderRightColor: otherBorderColor,
|
||||
'animation-duration': `${duration}ms`,
|
||||
'animation-timing-function': mode === 'semicircle' || mode === 'circle' ? timingFunction : ''
|
||||
}">
|
||||
<block v-if="mode === 'spinner'">
|
||||
<!-- #ifndef APP-NVUE -->
|
||||
<view v-for="(item, index) in array12" :key="index" class="u-loading-icon__dot">
|
||||
</view>
|
||||
<!-- #endif -->
|
||||
<!-- #ifdef APP-NVUE -->
|
||||
<!-- 此组件内部图标部分无法设置宽高,即使通过width和height配置了也无效 -->
|
||||
<loading-indicator v-if="!webviewHide" class="u-loading-indicator" :animating="true" :style="{
|
||||
color: color,
|
||||
width: $u.addUnit(size),
|
||||
height: $u.addUnit(size)
|
||||
}" />
|
||||
<!-- #endif -->
|
||||
</block>
|
||||
</view>
|
||||
<text v-if="text" class="u-loading-icon__text" :style="{
|
||||
fontSize: $u.addUnit(textSize),
|
||||
color: textColor,
|
||||
}">{{text}}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import props from './props.js';
|
||||
// #ifdef APP-NVUE
|
||||
const animation = weex.requireModule('animation');
|
||||
// #endif
|
||||
/**
|
||||
* loading 加载动画
|
||||
* @description 警此组件为一个小动画,目前用在uView的loadmore加载更多和switch开关等组件的正在加载状态场景。
|
||||
* @tutorial https://www.uviewui.com/components/loading.html
|
||||
* @property {Boolean} show 是否显示组件 (默认 true)
|
||||
* @property {String} color 动画活动区域的颜色,只对 mode = flower 模式有效(默认color['u-tips-color'])
|
||||
* @property {String} textColor 提示文本的颜色(默认color['u-tips-color'])
|
||||
* @property {Boolean} vertical 文字和图标是否垂直排列 (默认 false )
|
||||
* @property {String} mode 模式选择,见官网说明(默认 'circle' )
|
||||
* @property {String | Number} size 加载图标的大小,单位px (默认 24 )
|
||||
* @property {String | Number} textSize 文字大小(默认 15 )
|
||||
* @property {String | Number} text 文字内容
|
||||
* @property {String} timingFunction 动画模式 (默认 'ease-in-out' )
|
||||
* @property {String | Number} duration 动画执行周期时间(默认 1200)
|
||||
* @property {String} inactiveColor mode=circle时的暗边颜色
|
||||
* @property {Object} customStyle 定义需要用到的外部样式
|
||||
* @example <u-loading mode="circle"></u-loading>
|
||||
*/
|
||||
export default {
|
||||
name: 'u-loading-icon',
|
||||
mixins: [props],
|
||||
data() {
|
||||
return {
|
||||
// Array.form可以通过一个伪数组对象创建指定长度的数组
|
||||
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/from
|
||||
array12: Array.from({
|
||||
length: 12
|
||||
}),
|
||||
// 这里需要设置默认值为360,否则在安卓nvue上,会延迟一个duration周期后才执行
|
||||
// 在iOS nvue上,则会一开始默认执行两个周期的动画
|
||||
aniAngel: 360, // 动画旋转角度
|
||||
webviewHide: false, // 监听webview的状态,如果隐藏了页面,则停止动画,以免性能消耗
|
||||
loading: false, // 是否运行中,针对nvue使用
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 当为circle类型时,给其另外三边设置一个更轻一些的颜色
|
||||
// 之所以需要这么做的原因是,比如父组件传了color为红色,那么需要另外的三个边为浅红色
|
||||
// 而不能是固定的某一个其他颜色(因为这个固定的颜色可能浅蓝,导致效果没有那么细腻良好)
|
||||
otherBorderColor() {
|
||||
const lightColor = uni.$u.colorGradient(this.color, '#ffffff', 100)[80]
|
||||
if (this.mode === 'circle') {
|
||||
return this.inactiveColor ? this.inactiveColor : lightColor
|
||||
} else {
|
||||
return 'transparent'
|
||||
}
|
||||
// return this.mode === 'circle' ? this.inactiveColor ? this.inactiveColor : lightColor : 'transparent'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show(n) {
|
||||
// nvue中,show为true,且为非loading状态,就重新执行动画模块
|
||||
// #ifdef APP-NVUE
|
||||
if (n && !this.loading) {
|
||||
setTimeout(() => {
|
||||
this.startAnimate()
|
||||
}, 30)
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
setTimeout(() => {
|
||||
// #ifdef APP-NVUE
|
||||
this.show && this.nvueAnimate()
|
||||
// #endif
|
||||
// #ifdef APP-PLUS
|
||||
this.show && this.addEventListenerToWebview()
|
||||
// #endif
|
||||
}, 20)
|
||||
},
|
||||
// 监听webview的显示与隐藏
|
||||
addEventListenerToWebview() {
|
||||
// webview的堆栈
|
||||
const pages = getCurrentPages()
|
||||
// 当前页面
|
||||
const page = pages[pages.length - 1]
|
||||
// 当前页面的webview实例
|
||||
const currentWebview = page.$getAppWebview()
|
||||
// 监听webview的显示与隐藏,从而停止或者开始动画(为了性能)
|
||||
currentWebview.addEventListener('hide', () => {
|
||||
this.webviewHide = true
|
||||
})
|
||||
currentWebview.addEventListener('show', () => {
|
||||
this.webviewHide = false
|
||||
})
|
||||
},
|
||||
// #ifdef APP-NVUE
|
||||
nvueAnimate() {
|
||||
// nvue下,非spinner类型时才需要旋转,因为nvue的spinner类型,使用了weex的
|
||||
// loading-indicator组件,自带旋转功能
|
||||
this.mode !== 'spinner' && this.startAnimate()
|
||||
},
|
||||
// 执行nvue的animate模块动画
|
||||
startAnimate() {
|
||||
this.loading = true
|
||||
const ani = this.$refs.ani
|
||||
if (!ani) return
|
||||
animation.transition(ani, {
|
||||
// 进行角度旋转
|
||||
styles: {
|
||||
transform: `rotate(${this.aniAngel}deg)`,
|
||||
transformOrigin: 'center center'
|
||||
},
|
||||
duration: this.duration,
|
||||
timingFunction: this.timingFunction,
|
||||
// delay: 10
|
||||
}, () => {
|
||||
// 每次增加360deg,为了让其重新旋转一周
|
||||
this.aniAngel += 360
|
||||
// 动画结束后,继续循环执行动画,需要同时判断webviewHide变量
|
||||
// nvue安卓,页面隐藏后依然会继续执行startAnimate方法
|
||||
this.show && !this.webviewHide ? this.startAnimate() : this.loading = false
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@mixin flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: $direction;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
// 由于uView是基于nvue环境进行开发的,此环境中普通元素默认为flex-direction: column;
|
||||
// 所以在非nvue中,需要对元素进行重置为flex-direction: column; 否则可能会表现异常
|
||||
view,
|
||||
scroll-view,
|
||||
swiper-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
flex-basis: auto;
|
||||
align-items: stretch;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
$u-loading-icon-color: #c8c9cc !default;
|
||||
$u-loading-icon-text-margin-left:4px !default;
|
||||
$u-loading-icon-text-color:$u-content-color !default;
|
||||
$u-loading-icon-text-font-size:14px !default;
|
||||
$u-loading-icon-text-line-height:20px !default;
|
||||
$u-loading-width:30px !default;
|
||||
$u-loading-height:30px !default;
|
||||
$u-loading-max-width:100% !default;
|
||||
$u-loading-max-height:100% !default;
|
||||
$u-loading-semicircle-border-width: 2px !default;
|
||||
$u-loading-semicircle-border-color:transparent !default;
|
||||
$u-loading-semicircle-border-top-right-radius: 100px !default;
|
||||
$u-loading-semicircle-border-top-left-radius: 100px !default;
|
||||
$u-loading-semicircle-border-bottom-left-radius: 100px !default;
|
||||
$u-loading-semicircle-border-bottom-right-radiu: 100px !default;
|
||||
$u-loading-semicircle-border-style: solid !default;
|
||||
$u-loading-circle-border-top-right-radius: 100px !default;
|
||||
$u-loading-circle-border-top-left-radius: 100px !default;
|
||||
$u-loading-circle-border-bottom-left-radius: 100px !default;
|
||||
$u-loading-circle-border-bottom-right-radiu: 100px !default;
|
||||
$u-loading-circle-border-width:2px !default;
|
||||
$u-loading-circle-border-top-color:#e5e5e5 !default;
|
||||
$u-loading-circle-border-right-color:$u-loading-circle-border-top-color !default;
|
||||
$u-loading-circle-border-bottom-color:$u-loading-circle-border-top-color !default;
|
||||
$u-loading-circle-border-left-color:$u-loading-circle-border-top-color !default;
|
||||
$u-loading-circle-border-style:solid !default;
|
||||
$u-loading-icon-host-font-size:0px !default;
|
||||
$u-loading-icon-host-line-height:1 !default;
|
||||
$u-loading-icon-vertical-margin:6px 0 0 !default;
|
||||
$u-loading-icon-dot-top:0 !default;
|
||||
$u-loading-icon-dot-left:0 !default;
|
||||
$u-loading-icon-dot-width:100% !default;
|
||||
$u-loading-icon-dot-height:100% !default;
|
||||
$u-loading-icon-dot-before-width:2px !default;
|
||||
$u-loading-icon-dot-before-height:25% !default;
|
||||
$u-loading-icon-dot-before-margin:0 auto !default;
|
||||
$u-loading-icon-dot-before-background-color:currentColor !default;
|
||||
$u-loading-icon-dot-before-border-radius:40% !default;
|
||||
|
||||
.u-loading-icon {
|
||||
/* #ifndef APP-NVUE */
|
||||
// display: inline-flex;
|
||||
/* #endif */
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: $u-loading-icon-color;
|
||||
|
||||
&__text {
|
||||
margin-left: $u-loading-icon-text-margin-left;
|
||||
color: $u-loading-icon-text-color;
|
||||
font-size: $u-loading-icon-text-font-size;
|
||||
line-height: $u-loading-icon-text-line-height;
|
||||
}
|
||||
|
||||
&__spinner {
|
||||
width: $u-loading-width;
|
||||
height: $u-loading-height;
|
||||
position: relative;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: border-box;
|
||||
max-width: $u-loading-max-width;
|
||||
max-height: $u-loading-max-height;
|
||||
animation: u-rotate 1s linear infinite;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
&__spinner--semicircle {
|
||||
border-width: $u-loading-semicircle-border-width;
|
||||
border-color: $u-loading-semicircle-border-color;
|
||||
border-top-right-radius: $u-loading-semicircle-border-top-right-radius;
|
||||
border-top-left-radius: $u-loading-semicircle-border-top-left-radius;
|
||||
border-bottom-left-radius: $u-loading-semicircle-border-bottom-left-radius;
|
||||
border-bottom-right-radius: $u-loading-semicircle-border-bottom-right-radiu;
|
||||
border-style: $u-loading-semicircle-border-style;
|
||||
}
|
||||
|
||||
&__spinner--circle {
|
||||
border-top-right-radius: $u-loading-circle-border-top-right-radius;
|
||||
border-top-left-radius: $u-loading-circle-border-top-left-radius;
|
||||
border-bottom-left-radius: $u-loading-circle-border-bottom-left-radius;
|
||||
border-bottom-right-radius: $u-loading-circle-border-bottom-right-radiu;
|
||||
border-width: $u-loading-circle-border-width;
|
||||
border-top-color: $u-loading-circle-border-top-color;
|
||||
border-right-color: $u-loading-circle-border-right-color;
|
||||
border-bottom-color: $u-loading-circle-border-bottom-color;
|
||||
border-left-color: $u-loading-circle-border-left-color;
|
||||
border-style: $u-loading-circle-border-style;
|
||||
}
|
||||
|
||||
&--vertical {
|
||||
flex-direction: column
|
||||
}
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
:host {
|
||||
font-size: $u-loading-icon-host-font-size;
|
||||
line-height: $u-loading-icon-host-line-height;
|
||||
}
|
||||
|
||||
.u-loading-icon {
|
||||
&__spinner--spinner {
|
||||
animation-timing-function: steps(12)
|
||||
}
|
||||
|
||||
&__text:empty {
|
||||
display: none
|
||||
}
|
||||
|
||||
&--vertical &__text {
|
||||
margin: $u-loading-icon-vertical-margin;
|
||||
color: $u-content-color;
|
||||
}
|
||||
|
||||
&__dot {
|
||||
position: absolute;
|
||||
top: $u-loading-icon-dot-top;
|
||||
left: $u-loading-icon-dot-left;
|
||||
width: $u-loading-icon-dot-width;
|
||||
height: $u-loading-icon-dot-height;
|
||||
|
||||
&:before {
|
||||
display: block;
|
||||
width: $u-loading-icon-dot-before-width;
|
||||
height: $u-loading-icon-dot-before-height;
|
||||
margin: $u-loading-icon-dot-before-margin;
|
||||
background-color: $u-loading-icon-dot-before-background-color;
|
||||
border-radius: $u-loading-icon-dot-before-border-radius;
|
||||
content: " "
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@for $i from 1 through 12 {
|
||||
.u-loading-icon__dot:nth-of-type(#{$i}) {
|
||||
transform: rotate($i * 30deg);
|
||||
opacity: 1 - 0.0625 * ($i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes u-rotate {
|
||||
0% {
|
||||
transform: rotate(0deg)
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(1turn)
|
||||
}
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
</style>
|
||||
65
components/d-loading-icon/props.js
Normal file
@@ -0,0 +1,65 @@
|
||||
export default {
|
||||
props: {
|
||||
customStyle:{
|
||||
type:Object,
|
||||
default:()=>{
|
||||
return {}
|
||||
}
|
||||
},
|
||||
// 是否显示组件
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 颜色
|
||||
color: {
|
||||
type: String,
|
||||
default: '#909193'
|
||||
},
|
||||
// 提示文字颜色
|
||||
textColor: {
|
||||
type: String,
|
||||
default: '#909193'
|
||||
},
|
||||
// 文字和图标是否垂直排列
|
||||
vertical: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 模式选择,circle-圆形,spinner-花朵形,semicircle-半圆形
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'spinner'
|
||||
},
|
||||
// 图标大小,单位默认px
|
||||
size: {
|
||||
type: [String, Number],
|
||||
default: 32
|
||||
},
|
||||
// 文字大小
|
||||
textSize: {
|
||||
type: [String, Number],
|
||||
default: 15
|
||||
},
|
||||
// 文字内容
|
||||
text: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
// 动画模式
|
||||
timingFunction: {
|
||||
type: String,
|
||||
default: 'ease-in-out'
|
||||
},
|
||||
// 动画执行周期时间
|
||||
duration: {
|
||||
type: [String, Number],
|
||||
default: 1200
|
||||
},
|
||||
// mode=circle时的暗边颜色
|
||||
inactiveColor: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
116
components/d-loading-page/d-loading-page.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<d-transition :show="loading" :custom-style="{
|
||||
position: 'fixed',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
backgroundColor: bgColor,
|
||||
display: 'flex',
|
||||
}">
|
||||
<view class="u-loading-page">
|
||||
<view class="u-loading-page__warpper">
|
||||
<view class="u-loading-page__warpper__loading-icon">
|
||||
<image v-if="image" :src="image" class="u-loading-page__warpper__loading-icon__img" mode="widthFit">
|
||||
</image>
|
||||
<d-loading-icon v-else :mode="loadingMode" :size="$u.addUnit(iconSize)" :color="loadingColor"></d-loading-icon>
|
||||
</view>
|
||||
<slot>
|
||||
<text class="u-loading-page__warpper__text" :style="{
|
||||
fontSize: $u.addUnit(fontSize),
|
||||
color: color,
|
||||
}">{{ loadingText }}</text>
|
||||
</slot>
|
||||
</view>
|
||||
</view>
|
||||
</d-transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import props from "./props.js";
|
||||
/**
|
||||
* loadingPage 加载动画
|
||||
* @description 警此组件为一个小动画,目前用在uView的loadmore加载更多和switch开关等组件的正在加载状态场景。
|
||||
* @tutorial https://www.uviewui.com/components/loading.html
|
||||
* @property {String | Number} loadingText 提示内容 (默认 '正在加载' )
|
||||
* @property {String} image 文字上方用于替换loading动画的图片
|
||||
* @property {String} loadingMode 加载动画的模式,circle-圆形,spinner-花朵形,semicircle-半圆形 (默认 'circle' )
|
||||
* @property {Boolean} loading 是否加载中 (默认 false )
|
||||
* @property {String} bgColor 背景色 (默认 '#ffffff' )
|
||||
* @property {String} color 文字颜色 (默认 '#C8C8C8' )
|
||||
* @property {String | Number} fontSize 文字大小 (默认 19 )
|
||||
* @property {String} loadingColor 加载中图标的颜色,只能rgb或者十六进制颜色值 (默认 '#C8C8C8' )
|
||||
* @property {Object} customStyle 自定义样式
|
||||
* @example <u-loading mode="circle"></u-loading>
|
||||
*/
|
||||
export default {
|
||||
name: "u-loading-page",
|
||||
mixins: [props],
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
methods: {},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@mixin flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: $direction;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
// 由于uView是基于nvue环境进行开发的,此环境中普通元素默认为flex-direction: column;
|
||||
// 所以在非nvue中,需要对元素进行重置为flex-direction: column; 否则可能会表现异常
|
||||
view,
|
||||
scroll-view,
|
||||
swiper-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
flex-basis: auto;
|
||||
align-items: stretch;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
$text-color: rgb(200, 200, 200) !default;
|
||||
$text-size: 19px !default;
|
||||
$u-loading-icon-margin-bottom: 10px !default;
|
||||
|
||||
.u-loading-page {
|
||||
@include flex(column);
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&__warpper {
|
||||
margin-top: -150px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
color: $text-color;
|
||||
font-size: $text-size;
|
||||
/* #endif */
|
||||
@include flex(column);
|
||||
|
||||
&__loading-icon {
|
||||
margin-bottom: $u-loading-icon-margin-bottom;
|
||||
|
||||
&__img {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
&__text {
|
||||
font-size: $text-size;
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
48
components/d-loading-page/props.js
Normal file
@@ -0,0 +1,48 @@
|
||||
export default {
|
||||
props: {
|
||||
iconSize:{
|
||||
type: [String, Number],
|
||||
default: '40'
|
||||
},
|
||||
// 提示内容
|
||||
loadingText: {
|
||||
type: [String, Number],
|
||||
default: '正在加载...'
|
||||
},
|
||||
// 文字上方用于替换loading动画的图片
|
||||
image: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 加载动画的模式,circle-圆形,spinner-花朵形,semicircle-半圆形
|
||||
loadingMode: {
|
||||
type: String,
|
||||
default: 'circle'
|
||||
},
|
||||
// 是否加载中
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 背景色
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: 'rgba(0, 0, 0, 0.40)'
|
||||
},
|
||||
// 文字颜色
|
||||
color: {
|
||||
type: String,
|
||||
default: '#C8C8C8'
|
||||
},
|
||||
// 文字大小
|
||||
fontSize: {
|
||||
type: [String, Number],
|
||||
default: 32
|
||||
},
|
||||
// 加载中图标的颜色,只能rgb或者十六进制颜色值
|
||||
loadingColor: {
|
||||
type: String,
|
||||
default: '#C8C8C8'
|
||||
}
|
||||
}
|
||||
}
|
||||
422
components/d-number-box/d-number-box.vue
Normal file
@@ -0,0 +1,422 @@
|
||||
<template>
|
||||
<view class="u-number-box">
|
||||
<view
|
||||
class="u-number-box__slot"
|
||||
@tap.stop="clickHandler('minus')"
|
||||
@touchstart="onTouchStart('minus')"
|
||||
@touchend.stop="clearTimeout"
|
||||
v-if="showMinus && $slots.minus"
|
||||
>
|
||||
<slot name="minus" />
|
||||
</view>
|
||||
<view
|
||||
v-else-if="showMinus"
|
||||
class="u-number-box__minus"
|
||||
@tap.stop="clickHandler('minus')"
|
||||
@touchstart="onTouchStart('minus')"
|
||||
@touchend.stop="clearTimeout"
|
||||
hover-class="u-number-box__minus--hover"
|
||||
hover-stay-time="150"
|
||||
:class="{ 'u-number-box__minus--disabled': isDisabled('minus') }"
|
||||
:style="[buttonStyle('minus')]"
|
||||
>
|
||||
<u-icon
|
||||
name="minus"
|
||||
:color="isDisabled('minus') ? '#c8c9cc' : '#323233'"
|
||||
size="15"
|
||||
bold
|
||||
:customStyle="iconStyle"
|
||||
></u-icon>
|
||||
</view>
|
||||
|
||||
<slot name="input">
|
||||
<input
|
||||
:disabled="disabledInput || disabled"
|
||||
:cursor-spacing="getCursorSpacing"
|
||||
:class="{ 'u-number-box__input--disabled': disabled || disabledInput }"
|
||||
v-model="currentValue"
|
||||
class="u-number-box__input"
|
||||
@blur="onBlur"
|
||||
@focus="onFocus"
|
||||
@input="onInput"
|
||||
type="number"
|
||||
:style="[inputStyle]"
|
||||
/>
|
||||
</slot>
|
||||
<view
|
||||
class="u-number-box__slot"
|
||||
@tap.stop="clickHandler('plus')"
|
||||
@touchstart="onTouchStart('plus')"
|
||||
@touchend.stop="clearTimeout"
|
||||
v-if="showPlus && $slots.plus"
|
||||
>
|
||||
<slot name="plus" />
|
||||
</view>
|
||||
<view
|
||||
v-else-if="showPlus"
|
||||
class="u-number-box__plus"
|
||||
@tap.stop="clickHandler('plus')"
|
||||
@touchstart="onTouchStart('plus')"
|
||||
@touchend.stop="clearTimeout"
|
||||
hover-class="u-number-box__plus--hover"
|
||||
hover-stay-time="150"
|
||||
:class="{ 'u-number-box__minus--disabled': isDisabled('plus') }"
|
||||
:style="[buttonStyle('plus')]"
|
||||
>
|
||||
<u-icon
|
||||
name="plus"
|
||||
:color="isDisabled('plus') ? '#c8c9cc' : '#323233'"
|
||||
size="15"
|
||||
bold
|
||||
:customStyle="iconStyle"
|
||||
></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import props from './props.js';
|
||||
/**
|
||||
* numberBox 步进器
|
||||
* @description 该组件一般用于商城购物选择物品数量的场景。
|
||||
* @tutorial https://uviewui.com/components/numberBox.html
|
||||
* @property {String | Number} name 步进器标识符,在change回调返回
|
||||
* @property {String | Number} value 用于双向绑定的值,初始化时设置设为默认min值(最小值) (默认 0 )
|
||||
* @property {String | Number} min 最小值 (默认 1 )
|
||||
* @property {String | Number} max 最大值 (默认 Number.MAX_SAFE_INTEGER )
|
||||
* @property {String | Number} step 加减的步长,可为小数 (默认 1 )
|
||||
* @property {Boolean} integer 是否只允许输入整数 (默认 false )
|
||||
* @property {Boolean} disabled 是否禁用,包括输入框,加减按钮 (默认 false )
|
||||
* @property {Boolean} disabledInput 是否禁用输入框 (默认 false )
|
||||
* @property {Boolean} asyncChange 是否开启异步变更,开启后需要手动控制输入值 (默认 false )
|
||||
* @property {String | Number} inputWidth 输入框宽度,单位为px (默认 35 )
|
||||
* @property {Boolean} showMinus 是否显示减少按钮 (默认 true )
|
||||
* @property {Boolean} showPlus 是否显示增加按钮 (默认 true )
|
||||
* @property {String | Number} decimalLength 显示的小数位数
|
||||
* @property {Boolean} longPress 是否开启长按加减手势 (默认 true )
|
||||
* @property {String} color 输入框文字和加减按钮图标的颜色 (默认 '#323233' )
|
||||
* @property {String | Number} buttonSize 按钮大小,宽高等于此值,单位px,输入框高度和此值保持一致 (默认 30 )
|
||||
* @property {String} bgColor 输入框和按钮的背景颜色 (默认 '#EBECEE' )
|
||||
* @property {String | Number} cursorSpacing 指定光标于键盘的距离,避免键盘遮挡输入框,单位px (默认 100 )
|
||||
* @property {Boolean} disablePlus 是否禁用增加按钮 (默认 false )
|
||||
* @property {Boolean} disableMinus 是否禁用减少按钮 (默认 false )
|
||||
* @property {Object | String} iconStyle 加减按钮图标的样式
|
||||
*
|
||||
* @event {Function} onFocus 输入框活动焦点
|
||||
* @event {Function} onBlur 输入框失去焦点
|
||||
* @event {Function} onInput 输入框值发生变化
|
||||
* @event {Function} onChange
|
||||
* @example <u-number-box v-model="value" @change="valChange"></u-number-box>
|
||||
*/
|
||||
export default {
|
||||
name: 'u-number-box',
|
||||
mixins: [props],
|
||||
data() {
|
||||
return {
|
||||
// 输入框实际操作的值
|
||||
currentValue: '',
|
||||
// 定时器
|
||||
longPressTimer: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
// 多个值之间,只要一个值发生变化,都要重新检查check()函数
|
||||
watchChange(n) {
|
||||
this.check()
|
||||
},
|
||||
// 监听v-mode的变化,重新初始化内部的值
|
||||
value(n) {
|
||||
if (n !== this.currentValue) {
|
||||
this.currentValue = this.format(this.value)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
getCursorSpacing() {
|
||||
// 判断传入的单位,如果为px单位,需要转成px
|
||||
const number = parseInt(this.cursorSpacing)
|
||||
return /rpx$/.test(String(this.cursorSpacing)) ? uni.upx2px(number) : number
|
||||
},
|
||||
// 按钮的样式
|
||||
buttonStyle() {
|
||||
return (type) => {
|
||||
const style = {
|
||||
backgroundColor: this.bgColor,
|
||||
height: this.$u.addUnit(this.buttonSize),
|
||||
color: this.color
|
||||
}
|
||||
if (this.isDisabled(type)) {
|
||||
style.backgroundColor = '#f7f8fa'
|
||||
}
|
||||
return style
|
||||
}
|
||||
},
|
||||
// 输入框的样式
|
||||
inputStyle() {
|
||||
const disabled = this.disabled || this.disabledInput
|
||||
const style = {
|
||||
color: this.color,
|
||||
backgroundColor: this.bgColor,
|
||||
height: this.$u.addUnit(this.buttonSize),
|
||||
width: this.$u.addUnit(this.inputWidth)
|
||||
}
|
||||
return style
|
||||
},
|
||||
// 用于监听多个值发生变化
|
||||
watchChange() {
|
||||
return [this.integer, this.decimalLength, this.min, this.max]
|
||||
},
|
||||
isDisabled() {
|
||||
return (type) => {
|
||||
if (type === 'plus') {
|
||||
// 在点击增加按钮情况下,判断整体的disabled,是否单独禁用增加按钮,以及当前值是否大于最大的允许值
|
||||
return (
|
||||
this.disabled ||
|
||||
this.disablePlus ||
|
||||
this.currentValue >= this.max
|
||||
)
|
||||
}
|
||||
// 点击减少按钮同理
|
||||
return (
|
||||
this.disabled ||
|
||||
this.disableMinus ||
|
||||
this.currentValue <= this.min
|
||||
)
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.init()
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.currentValue = this.format(this.value)
|
||||
},
|
||||
// 格式化整理数据,限制范围
|
||||
format(value) {
|
||||
value = this.filter(value)
|
||||
// 如果为空字符串,那么设置为0,同时将值转为Number类型
|
||||
value = value === '' ? 0 : +value
|
||||
// 对比最大最小值,取在min和max之间的值
|
||||
value = Math.max(Math.min(this.max, value), this.min)
|
||||
// 如果设定了最大的小数位数,使用toFixed去进行格式化
|
||||
if (this.decimalLength !== null) {
|
||||
value = value.toFixed(this.decimalLength)
|
||||
}
|
||||
return value
|
||||
},
|
||||
// 过滤非法的字符
|
||||
filter(value) {
|
||||
// 只允许0-9之间的数字,"."为小数点,"-"为负数时候使用
|
||||
value = String(value).replace(/[^0-9.-]/g, '')
|
||||
// 如果只允许输入整数,则过滤掉小数点后的部分
|
||||
if (this.integer && value.indexOf('.') !== -1) {
|
||||
value = value.split('.')[0]
|
||||
}
|
||||
return value;
|
||||
},
|
||||
check() {
|
||||
// 格式化了之后,如果前后的值不相等,那么设置为格式化后的值
|
||||
const val = this.format(this.currentValue);
|
||||
if (val !== this.currentValue) {
|
||||
this.currentValue = val
|
||||
}
|
||||
},
|
||||
// 判断是否出于禁止操作状态
|
||||
// isDisabled(type) {
|
||||
// if (type === 'plus') {
|
||||
// // 在点击增加按钮情况下,判断整体的disabled,是否单独禁用增加按钮,以及当前值是否大于最大的允许值
|
||||
// return (
|
||||
// this.disabled ||
|
||||
// this.disablePlus ||
|
||||
// this.currentValue >= this.max
|
||||
// )
|
||||
// }
|
||||
// // 点击减少按钮同理
|
||||
// return (
|
||||
// this.disabled ||
|
||||
// this.disableMinus ||
|
||||
// this.currentValue <= this.min
|
||||
// )
|
||||
// },
|
||||
// 输入框活动焦点
|
||||
onFocus(event) {
|
||||
this.$emit('focus', {
|
||||
...event.detail,
|
||||
name: this.name,
|
||||
})
|
||||
},
|
||||
// 输入框失去焦点
|
||||
onBlur(event) {
|
||||
// 对输入值进行格式化
|
||||
const value = this.format(event.detail.value)
|
||||
// 发出blur事件
|
||||
this.$emit(
|
||||
'blur',{
|
||||
...event.detail,
|
||||
name: this.name,
|
||||
}
|
||||
)
|
||||
},
|
||||
// 输入框值发生变化
|
||||
onInput(e) {
|
||||
const {
|
||||
value = ''
|
||||
} = e.detail || {}
|
||||
// 为空返回
|
||||
if (value === '') return
|
||||
let formatted = this.filter(value)
|
||||
// 最大允许的小数长度
|
||||
if (this.decimalLength !== null && formatted.indexOf('.') !== -1) {
|
||||
const pair = formatted.split('.');
|
||||
formatted = `${pair[0]}.${pair[1].slice(0, this.decimalLength)}`
|
||||
}
|
||||
formatted = this.format(formatted)
|
||||
this.emitChange(formatted);
|
||||
},
|
||||
// 发出change事件
|
||||
emitChange(value) {
|
||||
// 如果开启了异步变更值,则不修改内部的值,需要用户手动在外部通过v-model变更
|
||||
if (!this.asyncChange) {
|
||||
this.$nextTick(() => {
|
||||
this.$emit('input', value)
|
||||
this.currentValue = value
|
||||
this.$forceUpdate()
|
||||
})
|
||||
}
|
||||
this.$emit('change', {
|
||||
value,
|
||||
name: this.name,
|
||||
});
|
||||
},
|
||||
onChange() {
|
||||
const {
|
||||
type
|
||||
} = this
|
||||
if (this.isDisabled(type)) {
|
||||
return this.$emit('overlimit', type)
|
||||
}
|
||||
const diff = type === 'minus' ? -this.step : +this.step
|
||||
const value = this.format(this.add(+this.currentValue, diff))
|
||||
this.emitChange(value)
|
||||
this.$emit(type)
|
||||
},
|
||||
// 对值扩大后进行四舍五入,再除以扩大因子,避免出现浮点数操作的精度问题
|
||||
add(num1, num2) {
|
||||
const cardinal = Math.pow(10, 10);
|
||||
return Math.round((num1 + num2) * cardinal) / cardinal
|
||||
},
|
||||
// 点击加减按钮
|
||||
clickHandler(type) {
|
||||
this.type = type
|
||||
this.onChange()
|
||||
},
|
||||
longPressStep() {
|
||||
// 每隔一段时间,重新调用longPressStep方法,实现长按加减
|
||||
this.clearTimeout()
|
||||
this.longPressTimer = setTimeout(() => {
|
||||
this.onChange()
|
||||
this.longPressStep()
|
||||
}, 250);
|
||||
},
|
||||
onTouchStart(type) {
|
||||
if (!this.longPress) return
|
||||
this.clearTimeout()
|
||||
this.type = type
|
||||
// 一定时间后,默认达到长按状态
|
||||
this.longPressTimer = setTimeout(() => {
|
||||
this.onChange()
|
||||
this.longPressStep()
|
||||
}, 600)
|
||||
},
|
||||
// 触摸结束,清除定时器,停止长按加减
|
||||
onTouchEnd() {
|
||||
if (!this.longPress) return
|
||||
this.clearTimeout()
|
||||
},
|
||||
// 清除定时器
|
||||
clearTimeout() {
|
||||
clearTimeout(this.longPressTimer)
|
||||
this.longPressTimer = null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@mixin flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: $direction;
|
||||
}
|
||||
|
||||
$u-numberBox-hover-bgColor: #E6E6E6 !default;
|
||||
$u-numberBox-disabled-color: #c8c9cc !default;
|
||||
$u-numberBox-disabled-bgColor: #f7f8fa !default;
|
||||
$u-numberBox-plus-radius: 4px !default;
|
||||
$u-numberBox-minus-radius: 4px !default;
|
||||
$u-numberBox-input-text-align: center !default;
|
||||
$u-numberBox-input-font-size: 15px !default;
|
||||
$u-numberBox-input-padding: 0 !default;
|
||||
$u-numberBox-input-margin: 0 2px !default;
|
||||
$u-numberBox-input-disabled-color: #c8c9cc !default;
|
||||
$u-numberBox-input-disabled-bgColor: #f2f3f5 !default;
|
||||
|
||||
.u-number-box {
|
||||
@include flex(row);
|
||||
align-items: center;
|
||||
|
||||
&__slot {
|
||||
/* #ifndef APP-NVUE */
|
||||
touch-action: none;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
&__plus,
|
||||
&__minus {
|
||||
width: 35px;
|
||||
@include flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
/* #ifndef APP-NVUE */
|
||||
touch-action: none;
|
||||
/* #endif */
|
||||
|
||||
&--hover {
|
||||
background-color: $u-numberBox-hover-bgColor !important;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
color: $u-numberBox-disabled-color;
|
||||
background-color: $u-numberBox-disabled-bgColor;
|
||||
}
|
||||
}
|
||||
|
||||
&__plus {
|
||||
border-top-right-radius: $u-numberBox-plus-radius;
|
||||
border-bottom-right-radius: $u-numberBox-plus-radius;
|
||||
}
|
||||
|
||||
&__minus {
|
||||
border-top-left-radius: $u-numberBox-minus-radius;
|
||||
border-bottom-left-radius: $u-numberBox-minus-radius;
|
||||
}
|
||||
|
||||
&__input {
|
||||
position: relative;
|
||||
text-align: $u-numberBox-input-text-align;
|
||||
font-size: $u-numberBox-input-font-size;
|
||||
padding: $u-numberBox-input-padding;
|
||||
margin: $u-numberBox-input-margin;
|
||||
@include flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&--disabled {
|
||||
color: $u-numberBox-input-disabled-color;
|
||||
background-color: $u-numberBox-input-disabled-bgColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
109
components/d-number-box/props.js
Normal file
@@ -0,0 +1,109 @@
|
||||
export default {
|
||||
props: {
|
||||
// 步进器标识符,在change回调返回
|
||||
name: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
// 用于双向绑定的值,初始化时设置设为默认min值(最小值)
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
// 最小值
|
||||
min: {
|
||||
type: [String, Number],
|
||||
default: 1
|
||||
},
|
||||
// 最大值
|
||||
max: {
|
||||
type: [String, Number],
|
||||
default: Number.MAX_SAFE_INTEGER
|
||||
},
|
||||
// 加减的步长,可为小数
|
||||
step: {
|
||||
type: [String, Number],
|
||||
default: 1
|
||||
},
|
||||
// 是否只允许输入整数
|
||||
integer: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否禁用,包括输入框,加减按钮
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否禁用输入框
|
||||
disabledInput: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否开启异步变更,开启后需要手动控制输入值
|
||||
asyncChange: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 输入框宽度,单位为px
|
||||
inputWidth: {
|
||||
type: [String, Number],
|
||||
default: '80rpx'
|
||||
},
|
||||
// 是否显示减少按钮
|
||||
showMinus: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否显示增加按钮
|
||||
showPlus: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 显示的小数位数
|
||||
decimalLength: {
|
||||
type: [String, Number, null],
|
||||
default: null
|
||||
},
|
||||
// 是否开启长按加减手势
|
||||
longPress: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 输入框文字和加减按钮图标的颜色
|
||||
color: {
|
||||
type: String,
|
||||
default: '#331353D'
|
||||
},
|
||||
// 按钮大小,宽高等于此值,单位px,输入框高度和此值保持一致
|
||||
buttonSize: {
|
||||
type: [String, Number],
|
||||
default: '64rpx'
|
||||
},
|
||||
// 输入框和按钮的背景颜色
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: '#EBECEE'
|
||||
},
|
||||
// 指定光标于键盘的距离,避免键盘遮挡输入框,单位px
|
||||
cursorSpacing: {
|
||||
type: [String, Number],
|
||||
default: 100
|
||||
},
|
||||
// 是否禁用增加按钮
|
||||
disablePlus: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否禁用减少按钮
|
||||
disableMinus: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 加减按钮图标的样式
|
||||
iconStyle: {
|
||||
type: [Object, String],
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
225
components/d-previewImage/d-previewImage.vue
Normal file
@@ -0,0 +1,225 @@
|
||||
<template>
|
||||
<view class="previewImage" :style="{ 'background-color':'rgba(0,0,0,'+opacity+')'}" v-if="show" @tap="close" @touchmove.stop.prevent >
|
||||
<swiper class="swiper" :current="index" @change="change">
|
||||
<swiper-item v-for="(img, i) in urls" :key="i" >
|
||||
<movable-area class="marea" scale-area>
|
||||
<movable-view class="mview" direction="all" :out-of-bounds="false" scale="true" @scale="onScale" :inertia="true" damping="90" friction="0.9" scale-min="0.9" scale-max="4" :scale-value="scale">
|
||||
<image class="image" :src="img" :data-index="i" :data-src="img" mode="widthFix" @touchmove="handletouchmove" @touchstart="handletouchstart" @touchend="handletouchend" />
|
||||
</movable-view>
|
||||
</movable-area>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
<view class="page" v-if="urls.length > 0">
|
||||
<text class="text">{{ index+1 }} / {{ urls.length }}</text>
|
||||
</view>
|
||||
<view class="desc" v-if="descs.length > 0 && descs.length == urls.length&&descs[index].length>0">{{ descs[index] }}</view>
|
||||
|
||||
<view class="left-pre" v-if="index > 0" @tap.native.stop='goPre'>
|
||||
<u-icon name="arrow-right" size="64rpx" color="#fff"></u-icon>>
|
||||
</view>
|
||||
|
||||
<view class="right-next" v-if="urls.length-1-index > 0" @tap.native.stop="goNext">
|
||||
<u-icon name="arrow-right" size="64rpx" color="#fff"></u-icon>>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'd-previewImage', //插件名称
|
||||
props: {
|
||||
imgs: {//图片列表
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
descs: {//描述列表
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
//透明度,0到1之间。
|
||||
opacity: {
|
||||
type: Number,
|
||||
default: 0.8
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false, //显示状态
|
||||
index: 0, //当前页
|
||||
time:0,//定时器
|
||||
interval: 1000, //长按事件
|
||||
scale: 1, //缩放比例
|
||||
old: {
|
||||
scale: 1 //缩放比例
|
||||
},
|
||||
urls:this.imgs
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
goPre(){
|
||||
this.index = this.index-1;
|
||||
},
|
||||
goNext(){
|
||||
this.index = this.index+1;
|
||||
},
|
||||
onScale(e) {
|
||||
this.old.scale = e.detail.scale
|
||||
},
|
||||
//接触开始
|
||||
handletouchstart(e) {
|
||||
var tchs = e.touches.length;
|
||||
if (tchs != 1) {
|
||||
return false;
|
||||
}
|
||||
this.time = setTimeout(() => {
|
||||
this.onLongPress(e);
|
||||
}, this.interval);
|
||||
return false;
|
||||
},
|
||||
//清除定时器
|
||||
handletouchend() {
|
||||
clearTimeout(this.time);
|
||||
if (this.time != 0) {
|
||||
//处理点击时间
|
||||
}
|
||||
return false;
|
||||
},
|
||||
//清除定时器
|
||||
handletouchmove() {
|
||||
clearTimeout(this.time);
|
||||
this.time = 0;
|
||||
},
|
||||
// 处理长按事件
|
||||
onLongPress(e) {
|
||||
var src = e.currentTarget.dataset.src;
|
||||
var index = e.currentTarget.dataset.index;
|
||||
var data={src:src,index:index}
|
||||
this.$emit('longPress', data);
|
||||
},
|
||||
//图片改变
|
||||
change(e) {
|
||||
this.scale = 1;
|
||||
this.index = e.target.current;
|
||||
},
|
||||
//打开
|
||||
open(urls,e=0) {
|
||||
if (e===null||e==="") {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!isNaN(e)){
|
||||
this.index = e;
|
||||
}else{
|
||||
this.index = this.urls.indexOf(e);
|
||||
}
|
||||
this.urls = urls
|
||||
this.show = true;
|
||||
},
|
||||
//关闭
|
||||
close(e) {
|
||||
this.show = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<!--使用scss,只在本组件生效-->
|
||||
<style lang="scss" scoped>
|
||||
.previewImage {
|
||||
z-index: 999;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #000000;
|
||||
user-select: none;
|
||||
.left-pre{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: calc(50% - 78rpx);
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
width: 78rpx;
|
||||
height: 156rpx;
|
||||
border-radius: 0 78rpx 78rpx 0;
|
||||
z-index: 1001;
|
||||
.icon-arrow{
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
margin-top: 46rpx;
|
||||
}
|
||||
}
|
||||
.right-next{
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: calc(50% - 78rpx);
|
||||
width: 78rpx;
|
||||
height: 156rpx;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 78rpx 0 0 78rpx;
|
||||
z-index: 1001;
|
||||
.icon-arrow{
|
||||
margin-top: 46rpx;
|
||||
margin-left: 12rpx;
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
}
|
||||
}
|
||||
.swiper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.marea {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
overflow: hidden;
|
||||
.mview {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
min-height: 100%;
|
||||
.image {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
bottom: 60rpx;
|
||||
text-align: center;
|
||||
.text {
|
||||
color: #fff;
|
||||
font-size: 34rpx;
|
||||
font-size: 500;
|
||||
padding: 3rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
}
|
||||
.desc {
|
||||
position: absolute;
|
||||
top: 51rpx;
|
||||
width: 100%;
|
||||
padding: 5rpx 10rpx;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
// background-color: rgba(0, 0, 0, 0.5);
|
||||
color: #fff;
|
||||
font-size: 46rpx;
|
||||
font-size: 500;
|
||||
letter-spacing: 3rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
191
components/d-steps/d-steps.vue
Normal file
@@ -0,0 +1,191 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<view class="u-steps" :style="{
|
||||
flexDirection: direction
|
||||
}">
|
||||
<view class="u-steps__item" :class="['u-steps__item--' + direction]" v-for="(item, index) in list"
|
||||
:key="index">
|
||||
<view class="u-steps__item__num" v-if="mode == 'number'" :style="{
|
||||
backgroundColor: current < index ? unActiveColor : activeColor
|
||||
}">
|
||||
<u-icon size="20" color="#ffffff" :name="icon"></u-icon>
|
||||
</view>
|
||||
<view class="u-steps__item__dot" v-if="mode == 'dot'" :style="{
|
||||
backgroundColor: index <= current ? activeColor : unActiveColor
|
||||
}"></view>
|
||||
<text class="u-line-1" :style="{
|
||||
color: index <= current ? activeColor : unActiveColor,
|
||||
}" :class="['u-steps__item__text--' + direction]">
|
||||
{{ item.name }}
|
||||
</text>
|
||||
<view class="u-steps__item__line" :style="{width:`calc(calc(100vw - 216rpx - ${(list.length-2)*48}rpx) / ${list.length-1})`}" :class="['u-steps__item__line--' + mode]"
|
||||
v-if="index < list.length - 1">
|
||||
<u-line :direction="direction" length="100%" :hair-line="false"
|
||||
:color="index <= current ? activeColor : unActiveColor"></u-line>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* steps 步骤条
|
||||
* @description 该组件一般用于完成一个任务要分几个步骤,标识目前处于第几步的场景。
|
||||
* @tutorial https://www.uviewui.com/components/steps.html
|
||||
* @property {String} mode 设置模式(默认dot)
|
||||
* @property {Array} list 数轴条数据,数组。具体见上方示例
|
||||
* @property {String} type type主题(默认primary)
|
||||
* @property {String} direction row-横向,column-竖向(默认row)
|
||||
* @property {Number String} current 设置当前处于第几步
|
||||
* @property {String} active-color 已完成步骤的激活颜色,如设置,type值会失效
|
||||
* @property {String} un-active-color 未激活的颜色,用于表示未完成步骤的颜色(默认#606266)
|
||||
* @example <u-steps :list="numList" active-color="#fa3534"></u-steps>
|
||||
*/
|
||||
export default {
|
||||
name: 'u-steps',
|
||||
props: {
|
||||
// 步骤条的类型,dot|number
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'dot'
|
||||
},
|
||||
// 步骤条的数据
|
||||
list: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
// 主题类型, primary|success|info|warning|error
|
||||
type: {
|
||||
type: String,
|
||||
default: 'primary'
|
||||
},
|
||||
// 当前哪一步是激活的
|
||||
current: {
|
||||
type: [Number, String],
|
||||
default: 0
|
||||
},
|
||||
// 激活步骤的颜色
|
||||
activeColor: {
|
||||
type: String,
|
||||
default: '#6ACDBB'
|
||||
},
|
||||
// 未激活的颜色
|
||||
unActiveColor: {
|
||||
type: String,
|
||||
default: '#C4C7CC'
|
||||
},
|
||||
// 自定义图标
|
||||
icon: {
|
||||
type: String,
|
||||
default: 'checkmark'
|
||||
},
|
||||
// step的排列方向,row-横向,column-竖向
|
||||
direction: {
|
||||
type: String,
|
||||
default: 'row'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@mixin vue-flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
flex-direction: $direction;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
$u-steps-item-number-width: 32rpx;
|
||||
$u-steps-item-dot-width: 20rpx;
|
||||
|
||||
.u-steps {
|
||||
@include vue-flex;
|
||||
padding: 0 32rpx;
|
||||
justify-content: space-between;
|
||||
.u-steps__item {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
width: 96rpx;
|
||||
color: #C4C7CC;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
align-items: center !important;
|
||||
&--row {
|
||||
position: relative;
|
||||
@include vue-flex;
|
||||
flex-direction: column;
|
||||
|
||||
.u-steps__item__line {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
left: 77%;
|
||||
|
||||
&--dot {
|
||||
top: calc(#{$u-steps-item-dot-width} / 2);
|
||||
}
|
||||
|
||||
&--number {
|
||||
top: calc(#{$u-steps-item-number-width} / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--column {
|
||||
@include vue-flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
min-height: 120rpx;
|
||||
|
||||
.u-steps__item__line {
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
height: 50%;
|
||||
top: 40vw;
|
||||
|
||||
&--dot {
|
||||
left: calc(#{$u-steps-item-dot-width} / 2);
|
||||
}
|
||||
|
||||
&--number {
|
||||
left: calc(#{$u-steps-item-number-width} / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__num {
|
||||
@include vue-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: $u-steps-item-number-width;
|
||||
height: $u-steps-item-number-width;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&__dot {
|
||||
width: $u-steps-item-dot-width;
|
||||
height: $u-steps-item-dot-width;
|
||||
@include vue-flex;
|
||||
border-radius: $u-steps-item-dot-width;
|
||||
}
|
||||
|
||||
&__text--row {
|
||||
margin-top: 14rpx;
|
||||
}
|
||||
|
||||
&__text--column {
|
||||
margin-left: 14rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
381
components/d-tabbar/d-tabbar.vue
Normal file
@@ -0,0 +1,381 @@
|
||||
<template>
|
||||
<view v-if="show" class="u-tabbar" @touchmove.stop.prevent="() => {}">
|
||||
<view class="u-tabbar__content safe-area-inset-bottom" :style="{
|
||||
height: $u.addUnit(height),
|
||||
backgroundColor: bgColor,
|
||||
}" :class="{
|
||||
'u-border-top': borderTop
|
||||
}">
|
||||
<block v-for="(item, index) in list" :key="index">
|
||||
<view class="u-tabbar__content__item" v-if="item.permissions.includes(parseInt(identity)-1)" :class="{
|
||||
'u-tabbar__content__circle': midButton &&item.midButton
|
||||
}" @tap.stop="clickHandler(index)" :style="{
|
||||
backgroundColor: bgColor
|
||||
}">
|
||||
<view :class="[
|
||||
midButton && item.midButton ? 'u-tabbar__content__circle__button' : 'u-tabbar__content__item__button'
|
||||
]">
|
||||
<image :style="{width: iconSize,height: iconSize}" :src="elIconPath(index)" mode="scaleToFill">
|
||||
</image>
|
||||
<u-badge :count="item.count" :is-dot="item.isDot" v-if="item.count || item.isDot"
|
||||
:offset="[-2, getOffsetRight(item.count, item.isDot)]"></u-badge>
|
||||
</view>
|
||||
<view class="u-tabbar__content__item__text" :style="{
|
||||
color: elColor(index)
|
||||
}">
|
||||
<text class="u-line-1">{{item.text}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view v-if="midButton" class="u-tabbar__content__circle__border" :class="{
|
||||
'u-border': borderTop,
|
||||
}" :style="{
|
||||
backgroundColor: bgColor,
|
||||
left: midButtonLeft
|
||||
}">
|
||||
</view>
|
||||
</view>
|
||||
<!-- 这里加上一个48rpx的高度,是为了增高有凸起按钮时的防塌陷高度(也即按钮凸出来部分的高度) -->
|
||||
<view class="u-fixed-placeholder safe-area-inset-bottom" :style="{
|
||||
height: `calc(${$u.addUnit(height)} + ${midButton ? 48 : 0}rpx)`,
|
||||
}"></view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// 显示与否
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 通过v-model绑定current值
|
||||
value: {
|
||||
type: [String, Number],
|
||||
default: 0
|
||||
},
|
||||
// 整个tabbar的背景颜色
|
||||
bgColor: {
|
||||
type: String,
|
||||
default: '#fff'
|
||||
},
|
||||
// tabbar的高度,默认50px,单位任意,如果为数值,则为rpx单位
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: '104rpx'
|
||||
},
|
||||
// 非凸起图标的大小,单位任意,数值默认rpx
|
||||
iconSize: {
|
||||
type: [String, Number],
|
||||
default: '44rpx'
|
||||
},
|
||||
// 凸起的图标的大小,单位任意,数值默认rpx
|
||||
midButtonSize: {
|
||||
type: [String, Number],
|
||||
default: 90
|
||||
},
|
||||
// 激活时的演示,包括字体图标,提示文字等的演示
|
||||
activeColor: {
|
||||
type: String,
|
||||
default: '#6ACDBB'
|
||||
},
|
||||
// 未激活时的颜色
|
||||
inactiveColor: {
|
||||
type: String,
|
||||
default: '#6C7380'
|
||||
},
|
||||
// 是否显示中部的凸起按钮
|
||||
midButton: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 切换前的回调
|
||||
beforeSwitch: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
// 是否显示顶部的横线
|
||||
borderTop: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否隐藏原生tabbar
|
||||
hideTabBar: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
// 配置参数
|
||||
list: [{
|
||||
iconPath: require("../../static/image/w-gzt.png"),
|
||||
selectedIconPath: require("../../static/image/gzt.png"),
|
||||
text: '工作台',
|
||||
path: 'pages/workbench/index',
|
||||
permissions: [0]
|
||||
},
|
||||
{
|
||||
iconPath: require("../../static/image/w-hz.png"),
|
||||
selectedIconPath: require("../../static/image/hz.png"),
|
||||
text: '患者',
|
||||
path: 'pages/patient/index',
|
||||
permissions: [0]
|
||||
},
|
||||
// {
|
||||
// iconPath: require("../../static/image/w-wdwz.png"),
|
||||
// selectedIconPath: require("../../static/image/wdwz.png"),
|
||||
// text: '文章中心',
|
||||
// path: 'pages/article/index',
|
||||
// permissions: [0]
|
||||
// },
|
||||
// {
|
||||
// iconPath: require("../../static/image/w-sf.png"),
|
||||
// selectedIconPath: require("../../static/image/sf1.png"),
|
||||
// text: '审方',
|
||||
// path: 'pages/pharmacist/index',
|
||||
// permissions: [2]
|
||||
// },
|
||||
{
|
||||
iconPath: require("../../static/image/w-wd.png"),
|
||||
selectedIconPath: require("../../static/image/wd.png"),
|
||||
text: '我的',
|
||||
path: 'pages/my/index',
|
||||
permissions: [0]
|
||||
},
|
||||
// {
|
||||
// iconPath: require("../../static/image/w-huihua.png"),
|
||||
// selectedIconPath: require("../../static/image/huiua.png"),
|
||||
// text: '会话',
|
||||
// path: 'pages/pharmacist/index',
|
||||
// permissions: [2, 3]
|
||||
// },
|
||||
// {
|
||||
// iconPath: require("../../static/image/w-sz.png"),
|
||||
// selectedIconPath: require("../../static/image/sz.png"),
|
||||
// text: '设置',
|
||||
// path: 'pages/my/index',
|
||||
// permissions: [2, 3]
|
||||
// }
|
||||
],
|
||||
// 由于安卓太菜了,通过css居中凸起按钮的外层元素有误差,故通过js计算将其居中
|
||||
midButtonLeft: '50%',
|
||||
pageUrl: '', // 当前页面URL
|
||||
// 身份
|
||||
identity: uni.getStorageSync('role') || 1,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 是否隐藏原生tabbar
|
||||
if (this.hideTabBar) uni.hideTabBar();
|
||||
// 获取引入了u-tabbar页面的路由地址,该地址没有路径前面的"/"
|
||||
let pages = getCurrentPages();
|
||||
// 页面栈中的最后一个即为项为当前页面,route属性为页面路径
|
||||
this.pageUrl = pages[pages.length - 1].route;
|
||||
},
|
||||
computed: {
|
||||
elIconPath() {
|
||||
return (index) => {
|
||||
// 历遍u-tabbar的每一项item时,判断是否传入了pagePath参数,如果传入了
|
||||
// 和data中的pageUrl参数对比,如果相等,即可判断当前的item对应当前的tabbar页面,设置高亮图标
|
||||
// 采用这个方法,可以无需使用v-model绑定的value值
|
||||
let pagePath = this.list[index].path;
|
||||
// 如果定义了pagePath属性,意味着使用系统自带tabbar方案,否则使用一个页面用几个组件模拟tabbar页面的方案
|
||||
// 这两个方案对处理tabbar item的激活与否方式不一样
|
||||
if (pagePath) {
|
||||
if (pagePath == this.pageUrl || pagePath == '/' + this.pageUrl) {
|
||||
return this.list[index].selectedIconPath;
|
||||
} else {
|
||||
return this.list[index].iconPath;
|
||||
}
|
||||
} else {
|
||||
// 普通方案中,索引等于v-model值时,即为激活项
|
||||
return index == this.value ? this.list[index].selectedIconPath : this.list[index].iconPath
|
||||
}
|
||||
}
|
||||
},
|
||||
elColor() {
|
||||
return (index) => {
|
||||
// 判断方法同理于elIconPath
|
||||
let pagePath = this.list[index].path;
|
||||
if (pagePath) {
|
||||
if (pagePath == this.pageUrl || pagePath == '/' + this.pageUrl) return this.activeColor;
|
||||
else return this.inactiveColor;
|
||||
} else {
|
||||
return index == this.value ? this.activeColor : this.inactiveColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.midButton && this.getMidButtonLeft();
|
||||
},
|
||||
methods: {
|
||||
async clickHandler(index) {
|
||||
if (this.beforeSwitch && typeof(this.beforeSwitch) === 'function') {
|
||||
// 执行回调,同时传入索引当作参数
|
||||
// 在微信,支付宝等环境(H5正常),会导致父组件定义的customBack()函数体中的this变成子组件的this
|
||||
// 通过bind()方法,绑定父组件的this,让this.customBack()的this为父组件的上下文
|
||||
let beforeSwitch = this.beforeSwitch.bind(this.$u.$parent.call(this))(index);
|
||||
// 判断是否返回了promise
|
||||
if (!!beforeSwitch && typeof beforeSwitch.then === 'function') {
|
||||
await beforeSwitch.then(res => {
|
||||
// promise返回成功,
|
||||
this.switchTab(index);
|
||||
}).catch(err => {
|
||||
|
||||
})
|
||||
} else if (beforeSwitch === true) {
|
||||
// 如果返回true
|
||||
this.switchTab(index);
|
||||
}
|
||||
} else {
|
||||
this.switchTab(index);
|
||||
}
|
||||
},
|
||||
// 切换tab
|
||||
switchTab(index) {
|
||||
// 发出事件和修改v-model绑定的值
|
||||
this.$emit('change', index);
|
||||
// 如果有配置path属性,使用uni.switchTab进行跳转
|
||||
if (this.list[index].path) {
|
||||
uni.switchTab({
|
||||
url: '../../' + this.list[index].path,
|
||||
fail: (e) => {
|
||||
console.log(e);
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 如果配置了papgePath属性,将不会双向绑定v-model传入的value值
|
||||
// 因为这个模式下,不再需要v-model绑定的value值了,而是通过getCurrentPages()适配
|
||||
this.$emit('input', index);
|
||||
}
|
||||
},
|
||||
// 计算角标的right值
|
||||
getOffsetRight(count, isDot) {
|
||||
// 点类型,count大于9(两位数),分别设置不同的right值,避免位置太挤
|
||||
if (isDot) {
|
||||
return -20;
|
||||
} else if (count > 9) {
|
||||
return -40;
|
||||
} else {
|
||||
return -30;
|
||||
}
|
||||
},
|
||||
// 获取凸起按钮外层元素的left值,让其水平居中
|
||||
getMidButtonLeft() {
|
||||
let windowWidth = this.$u.sys().windowWidth;
|
||||
// 由于安卓中css计算left: 50%的结果不准确,故用js计算
|
||||
this.midButtonLeft = (windowWidth / 2) + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@mixin vue-flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
flex-direction: $direction;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.u-fixed-placeholder {
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: content-box;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.u-tabbar {
|
||||
|
||||
&__content {
|
||||
@include vue-flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 998;
|
||||
/* #ifndef APP-NVUE */
|
||||
box-sizing: content-box;
|
||||
/* #endif */
|
||||
border-top: 2rpx solid #F2F3F5;
|
||||
|
||||
&__circle__border {
|
||||
border-radius: 100%;
|
||||
width: 110rpx;
|
||||
height: 110rpx;
|
||||
top: -48rpx;
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
background-color: #ffffff;
|
||||
// 由于安卓的无能,导致只有3个tabbar item时,此css计算方式有误差
|
||||
// 故使用js计算的形式来定位,此处不注释,是因为js计算有延后,避免出现位置闪动
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
&:after {
|
||||
border-radius: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
&__item {
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
@include vue-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
|
||||
&__button {
|
||||
position: absolute;
|
||||
top: 12rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
&__text {
|
||||
font-size: 20rpx;
|
||||
font-family: PingFang SC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #2979FF;
|
||||
position: absolute;
|
||||
top: 68rpx;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
&__circle {
|
||||
position: relative;
|
||||
@include vue-flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
z-index: 10;
|
||||
/* #ifndef APP-NVUE */
|
||||
height: calc(100% - 1px);
|
||||
/* #endif */
|
||||
|
||||
&__button {
|
||||
width: 90rpx;
|
||||
height: 90rpx;
|
||||
border-radius: 100%;
|
||||
@include vue-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
background-color: #ffffff;
|
||||
top: -40rpx;
|
||||
left: 50%;
|
||||
z-index: 6;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
84
components/d-text/d-text.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<view class="u-text" :class="[{'text-twoline':lines>0},className]" :style="[valueStyle]" @tap="clickHandler">
|
||||
{{text}}
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import value from './value.js';
|
||||
import props from './props.js';
|
||||
/**
|
||||
* Text 文本
|
||||
* @description 文本
|
||||
* @tutorial https://www.uviewui.com/components/loading.html
|
||||
* @property {String | Number} text 显示的值
|
||||
* @property {Boolean} bold 是否粗体,默认normal(默认 false )
|
||||
* @property {Boolean} block 是否块状(默认 false )
|
||||
* @property {String | Number} lines 文本显示的行数,如果设置,超出此行数,将会显示省略号
|
||||
* @property {String} color 文本颜色(默认 '#A7ABB0' )
|
||||
* @property {String | Number} size 字体大小(默认 28rpx )
|
||||
* @property {String | Number} lineHeight 文本行高
|
||||
* @property {String} align 文本对齐方式,可选值left|center|right|justify|start|end(默认 'left' )
|
||||
* @property {String} wordWrap 文字换行,可选值break-word|normal|anywhere(默认 'normal' )
|
||||
* @property {String} decoration 文字装饰,下划线,中划线等,可选值none|underline|line-through(默认 'none' )
|
||||
* @property {String} className 接收自定义类名
|
||||
* @property {String} width 宽度(默认没有)
|
||||
* @event {Function} click 点击触发事件
|
||||
* @example <d-text text="我用十年青春,赴你最后之约"></d-text>
|
||||
*/
|
||||
export default {
|
||||
name: 'd-text',
|
||||
mixins: [value, props],
|
||||
computed: {
|
||||
valueStyle() {
|
||||
const style = {
|
||||
textDecoration: this.decoration,
|
||||
fontWeight: this.bold ? 'bold' : 'normal',
|
||||
textAlignLast: this.align,
|
||||
wordWrap: this.wordWrap,
|
||||
fontSize: uni.$u.addUnit(this.size)
|
||||
};
|
||||
this.width && (style.width = uni.$u.addUnit(this.width))
|
||||
style.color = this.color;
|
||||
this.lines && (style['-webkit-line-clamp'] = this.lines);
|
||||
this.lineHeight && (style.lineHeight = uni.$u.addUnit(this.lineHeight));
|
||||
this.block && (style.display = 'block');
|
||||
return uni.$u.deepMerge(style, uni.$d.addStyle(this.customStyle));
|
||||
},
|
||||
isMp() {
|
||||
let mp = false;
|
||||
// #ifdef MP
|
||||
mp = true;
|
||||
// #endif
|
||||
return mp;
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {};
|
||||
},
|
||||
onShow() {},
|
||||
methods: {
|
||||
addStyle(customStyle) {
|
||||
uni.$d.addStyle(customStyle)
|
||||
},
|
||||
clickHandler() {
|
||||
// 如果为手机号模式,拨打电话
|
||||
if (this.mode === 'phone' && uni.$u.test.mobile(this.text)) {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: this.text
|
||||
});
|
||||
}
|
||||
this.$emit('click');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.text-twoline {
|
||||
display: -webkit-box;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
67
components/d-text/props.js
Normal file
@@ -0,0 +1,67 @@
|
||||
export default {
|
||||
props: {
|
||||
// 显示的值
|
||||
text: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
// 是否粗体,默认normal
|
||||
bold: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 是否块状
|
||||
block: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 文本显示的行数,如果设置,超出此行数,将会显示省略号
|
||||
lines: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
// 文本颜色
|
||||
color: {
|
||||
type: String,
|
||||
default: '#A7ABB0'
|
||||
},
|
||||
// 字体大小
|
||||
size: {
|
||||
type: [String, Number],
|
||||
default: '28rpx'
|
||||
},
|
||||
// 文字装饰,下划线,中划线等,可选值 none|underline|line-through
|
||||
decoration: {
|
||||
tepe: String,
|
||||
default: 'none',
|
||||
},
|
||||
// 外边距,对象、字符串,数值形式均可
|
||||
margin: {
|
||||
type: [Object, String, Number],
|
||||
default: 0
|
||||
},
|
||||
// 文本行高
|
||||
lineHeight: {
|
||||
type: [String, Number],
|
||||
default: ''
|
||||
},
|
||||
// 文本对齐方式,可选值left|center|right
|
||||
align: {
|
||||
type: String,
|
||||
default: 'left'
|
||||
},
|
||||
// 文字换行,可选值break-word|normal|anywhere
|
||||
wordWrap: {
|
||||
type: String,
|
||||
default: 'normal'
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
width: {
|
||||
type: [String,Number],
|
||||
default: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
85
components/d-text/value.js
Normal file
@@ -0,0 +1,85 @@
|
||||
export default {
|
||||
computed: {
|
||||
// 经处理后需要显示的值
|
||||
value() {
|
||||
const {
|
||||
text,
|
||||
mode,
|
||||
format,
|
||||
href
|
||||
} = this
|
||||
// 价格类型
|
||||
if (mode === 'price') {
|
||||
// 如果text不为金额进行提示
|
||||
if (!/^\d+(\.\d+)?$/.test(text)) {
|
||||
uni.$u.error('金额模式下,text参数需要为金额格式');
|
||||
}
|
||||
// 进行格式化,判断用户传入的format参数为正则,或者函数,如果没有传入format,则使用默认的金额格式化处理
|
||||
if (uni.$u.test.func(format)) {
|
||||
// 如果用户传入的是函数,使用函数格式化
|
||||
return format(text)
|
||||
}
|
||||
// 如果format非正则,非函数,则使用默认的金额格式化方法进行操作
|
||||
return uni.$u.priceFormat(text, 2)
|
||||
} if (mode === 'date') {
|
||||
// 判断是否合法的日期或者时间戳
|
||||
!uni.$u.test.date(text) && uni.$u.error('日期模式下,text参数需要为日期或时间戳格式')
|
||||
// 进行格式化,判断用户传入的format参数为正则,或者函数,如果没有传入format,则使用默认的格式化处理
|
||||
if (uni.$u.test.func(format)) {
|
||||
// 如果用户传入的是函数,使用函数格式化
|
||||
return format(text)
|
||||
} if (this.formart) {
|
||||
// 如果format非正则,非函数,则使用默认的时间格式化方法进行操作
|
||||
return uni.$u.timeFormat(text, format)
|
||||
}
|
||||
// 如果没有设置format,则设置为默认的时间格式化形式
|
||||
return uni.$u.timeFormat(text, 'yyyy-mm-dd')
|
||||
} if (mode === 'phone') {
|
||||
// 判断是否合法的手机号
|
||||
!uni.$u.test.mobile(text) && uni.$u.error('手机号模式下,text参数需要为手机号码格式')
|
||||
if (uni.$u.test.func(format)) {
|
||||
// 如果用户传入的是函数,使用函数格式化
|
||||
return format(text)
|
||||
} if (format === 'encrypt') {
|
||||
// 如果format为encrypt,则将手机号进行星号加密处理
|
||||
return `${text.substr(0, 3)}****${text.substr(7)}`
|
||||
}
|
||||
return text
|
||||
} if (mode === 'name') {
|
||||
// 判断是否合法的字符粗
|
||||
!(typeof (text) === 'string') && uni.$u.error('姓名模式下,text参数需要为字符串格式')
|
||||
if (uni.$u.test.func(format)) {
|
||||
// 如果用户传入的是函数,使用函数格式化
|
||||
return format(text)
|
||||
} if (format === 'encrypt') {
|
||||
// 如果format为encrypt,则将姓名进行星号加密处理
|
||||
return this.formatName(text)
|
||||
}
|
||||
return text
|
||||
} if (mode === 'link') {
|
||||
// 判断是否合法的字符粗
|
||||
!uni.$u.test.url(href) && uni.$u.error('超链接模式下,href参数需要为URL格式')
|
||||
return text
|
||||
}
|
||||
return text
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 默认的姓名脱敏规则
|
||||
formatName(name) {
|
||||
let value = ''
|
||||
if (name.length === 2) {
|
||||
value = name.substr(0, 1) + '*'
|
||||
} else if (name.length > 2) {
|
||||
let char = ''
|
||||
for (let i = 0, len = name.length - 2; i < len; i++) {
|
||||
char += '*'
|
||||
}
|
||||
value = name.substr(0, 1) + char + name.substr(-1, 1)
|
||||
} else {
|
||||
value = name
|
||||
}
|
||||
return value
|
||||
}
|
||||
}
|
||||
}
|
||||
114
components/d-transition/d-transition.vue
Normal file
@@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<view
|
||||
v-if="inited"
|
||||
class="u-transition"
|
||||
ref="u-transition"
|
||||
@tap="clickHandler"
|
||||
:class="classes"
|
||||
:style="[mergeStyle]"
|
||||
@touchmove="noop"
|
||||
>
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import props from './props.js';
|
||||
// 组件的methods方法,由于内容较长,写在外部文件中通过mixin引入
|
||||
import transition from "./transition.js";
|
||||
/**
|
||||
* transition 动画组件
|
||||
* @description
|
||||
* @tutorial
|
||||
* @property {String} show 是否展示组件 (默认 false )
|
||||
* @property {String} mode 使用的动画模式 (默认 'fade' )
|
||||
* @property {String | Number} duration 动画的执行时间,单位ms (默认 '300' )
|
||||
* @property {String} timingFunction 使用的动画过渡函数 (默认 'ease-out' )
|
||||
* @property {Object} customStyle 自定义样式
|
||||
* @event {Function} before-enter 进入前触发
|
||||
* @event {Function} enter 进入中触发
|
||||
* @event {Function} after-enter 进入后触发
|
||||
* @event {Function} before-leave 离开前触发
|
||||
* @event {Function} leave 离开中触发
|
||||
* @event {Function} after-leave 离开后触发
|
||||
* @example
|
||||
*/
|
||||
export default {
|
||||
name: 'd-transition',
|
||||
data() {
|
||||
return {
|
||||
inited: false, // 是否显示/隐藏组件
|
||||
viewStyle: {}, // 组件内部的样式
|
||||
status: '', // 记录组件动画的状态
|
||||
transitionEnded: false, // 组件是否结束的标记
|
||||
display: false, // 组件是否展示
|
||||
classes: '', // 应用的类名
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
mergeStyle() {
|
||||
const { viewStyle, customStyle } = this
|
||||
return {
|
||||
// #ifndef APP-NVUE
|
||||
transitionDuration: `${this.duration}ms`,
|
||||
// display: `${this.display ? '' : 'none'}`,
|
||||
transitionTimingFunction: this.timingFunction,
|
||||
// #endif
|
||||
// 避免自定义样式影响到动画属性,所以写在viewStyle前面
|
||||
...uni.$d.addStyle(customStyle),
|
||||
...viewStyle
|
||||
}
|
||||
}
|
||||
},
|
||||
// 将mixin挂在到组件中,uni.$u.mixin实际上为一个vue格式对象
|
||||
mixins: [transition, props],
|
||||
watch: {
|
||||
show: {
|
||||
handler(newVal) {
|
||||
// vue和nvue分别执行不同的方法
|
||||
// #ifdef APP-NVUE
|
||||
newVal ? this.nvueEnter() : this.nvueLeave()
|
||||
// #endif
|
||||
// #ifndef APP-NVUE
|
||||
newVal ? this.vueEnter() : this.vueLeave()
|
||||
// #endif
|
||||
},
|
||||
// 表示同时监听初始化时的props的show的意思
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@mixin flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: $direction;
|
||||
}
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
// 由于uView是基于nvue环境进行开发的,此环境中普通元素默认为flex-direction: column;
|
||||
// 所以在非nvue中,需要对元素进行重置为flex-direction: column; 否则可能会表现异常
|
||||
view,
|
||||
scroll-view,
|
||||
swiper-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
flex-basis: auto;
|
||||
align-items: stretch;
|
||||
align-content: flex-start;
|
||||
}
|
||||
|
||||
/* #endif */
|
||||
|
||||
/* #ifndef APP-NVUE */
|
||||
// vue版本动画相关的样式抽离在外部文件
|
||||
@import './vue.ani-style.scss';
|
||||
/* #endif */
|
||||
|
||||
.u-transition {}
|
||||
</style>
|
||||
68
components/d-transition/nvue.ani-map.js
Normal file
@@ -0,0 +1,68 @@
|
||||
export default {
|
||||
fade: {
|
||||
enter: { opacity: 0 },
|
||||
'enter-to': { opacity: 1 },
|
||||
leave: { opacity: 1 },
|
||||
'leave-to': { opacity: 0 }
|
||||
},
|
||||
'fade-up': {
|
||||
enter: { opacity: 0, transform: 'translateY(100%)' },
|
||||
'enter-to': { opacity: 1, transform: 'translateY(0)' },
|
||||
leave: { opacity: 1, transform: 'translateY(0)' },
|
||||
'leave-to': { opacity: 0, transform: 'translateY(100%)' }
|
||||
},
|
||||
'fade-down': {
|
||||
enter: { opacity: 0, transform: 'translateY(-100%)' },
|
||||
'enter-to': { opacity: 1, transform: 'translateY(0)' },
|
||||
leave: { opacity: 1, transform: 'translateY(0)' },
|
||||
'leave-to': { opacity: 0, transform: 'translateY(-100%)' }
|
||||
},
|
||||
'fade-left': {
|
||||
enter: { opacity: 0, transform: 'translateX(-100%)' },
|
||||
'enter-to': { opacity: 1, transform: 'translateY(0)' },
|
||||
leave: { opacity: 1, transform: 'translateY(0)' },
|
||||
'leave-to': { opacity: 0, transform: 'translateX(-100%)' }
|
||||
},
|
||||
'fade-right': {
|
||||
enter: { opacity: 0, transform: 'translateX(100%)' },
|
||||
'enter-to': { opacity: 1, transform: 'translateY(0)' },
|
||||
leave: { opacity: 1, transform: 'translateY(0)' },
|
||||
'leave-to': { opacity: 0, transform: 'translateX(100%)' }
|
||||
},
|
||||
'slide-up': {
|
||||
enter: { transform: 'translateY(100%)' },
|
||||
'enter-to': { transform: 'translateY(0)' },
|
||||
leave: { transform: 'translateY(0)' },
|
||||
'leave-to': { transform: 'translateY(100%)' }
|
||||
},
|
||||
'slide-down': {
|
||||
enter: { transform: 'translateY(-100%)' },
|
||||
'enter-to': { transform: 'translateY(0)' },
|
||||
leave: { transform: 'translateY(0)' },
|
||||
'leave-to': { transform: 'translateY(-100%)' }
|
||||
},
|
||||
'slide-left': {
|
||||
enter: { transform: 'translateX(-100%)' },
|
||||
'enter-to': { transform: 'translateY(0)' },
|
||||
leave: { transform: 'translateY(0)' },
|
||||
'leave-to': { transform: 'translateX(-100%)' }
|
||||
},
|
||||
'slide-right': {
|
||||
enter: { transform: 'translateX(100%)' },
|
||||
'enter-to': { transform: 'translateY(0)' },
|
||||
leave: { transform: 'translateY(0)' },
|
||||
'leave-to': { transform: 'translateX(100%)' }
|
||||
},
|
||||
zoom: {
|
||||
enter: { transform: 'scale(0.95)' },
|
||||
'enter-to': { transform: 'scale(1)' },
|
||||
leave: { transform: 'scale(1)' },
|
||||
'leave-to': { transform: 'scale(0.95)' }
|
||||
},
|
||||
'fade-zoom': {
|
||||
enter: { opacity: 0, transform: 'scale(0.95)' },
|
||||
'enter-to': { opacity: 1, transform: 'scale(1)' },
|
||||
leave: { opacity: 1, transform: 'scale(1)' },
|
||||
'leave-to': { opacity: 0, transform: 'scale(0.95)' }
|
||||
}
|
||||
}
|
||||
30
components/d-transition/props.js
Normal file
@@ -0,0 +1,30 @@
|
||||
export default {
|
||||
props: {
|
||||
customStyle:{
|
||||
type:Object,
|
||||
default:()=>{
|
||||
return {}
|
||||
}
|
||||
},
|
||||
// 是否展示组件
|
||||
show: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 使用的动画模式
|
||||
mode: {
|
||||
type: String,
|
||||
default: 'fade'
|
||||
},
|
||||
// 动画的执行时间,单位ms
|
||||
duration: {
|
||||
type: [String, Number],
|
||||
default: '300'
|
||||
},
|
||||
// 使用的动画过渡函数
|
||||
timingFunction: {
|
||||
type: String,
|
||||
default: 'ease-out'
|
||||
}
|
||||
}
|
||||
}
|
||||
155
components/d-transition/transition.js
Normal file
@@ -0,0 +1,155 @@
|
||||
// 定义一个一定时间后自动成功的promise,让调用nextTick方法处,进入下一个then方法
|
||||
const nextTick = () => new Promise(resolve => setTimeout(resolve, 1000 / 50))
|
||||
// nvue动画模块实现细节抽离在外部文件
|
||||
import animationMap from './nvue.ani-map.js'
|
||||
|
||||
// #ifndef APP-NVUE
|
||||
// 定义类名,通过给元素动态切换类名,赋予元素一定的css动画样式
|
||||
const getClassNames = (name) => ({
|
||||
enter: `u-${name}-enter u-${name}-enter-active`,
|
||||
'enter-to': `u-${name}-enter-to u-${name}-enter-active`,
|
||||
leave: `u-${name}-leave u-${name}-leave-active`,
|
||||
'leave-to': `u-${name}-leave-to u-${name}-leave-active`
|
||||
})
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
// 引入nvue(weex)的animation动画模块,文档见:
|
||||
// https://weex.apache.org/zh/docs/modules/animation.html#transition
|
||||
const animation = uni.requireNativePlugin('animation')
|
||||
const getStyle = (name) => animationMap[name]
|
||||
// #endif
|
||||
|
||||
export default {
|
||||
methods: {
|
||||
// 组件被点击发出事件
|
||||
clickHandler() {
|
||||
this.$emit('click')
|
||||
},
|
||||
// #ifndef APP-NVUE
|
||||
// vue版本的组件进场处理
|
||||
vueEnter() {
|
||||
// 动画进入时的类名
|
||||
const classNames = getClassNames(this.mode)
|
||||
// 定义状态和发出动画进入前事件
|
||||
this.status = 'enter'
|
||||
this.$emit('beforeEnter')
|
||||
this.inited = true
|
||||
this.display = true
|
||||
this.classes = classNames.enter
|
||||
this.$nextTick(async () => {
|
||||
// #ifdef H5
|
||||
await uni.$u.sleep(20)
|
||||
// #endif
|
||||
// 组件动画进入后触发的事件
|
||||
this.$emit('afterEnter')
|
||||
// 标识动画尚未结束
|
||||
this.transitionEnded = false
|
||||
// 赋予组件enter-to类名
|
||||
this.classes = classNames['enter-to']
|
||||
})
|
||||
},
|
||||
// 动画离场处理
|
||||
vueLeave() {
|
||||
// 如果不是展示状态,无需执行逻辑
|
||||
if (!this.display) return
|
||||
const classNames = getClassNames(this.mode)
|
||||
// 标记离开状态和发出事件
|
||||
this.status = 'leave'
|
||||
this.$emit('beforeLeave')
|
||||
// 获得类名
|
||||
this.classes = classNames.leave
|
||||
|
||||
this.$nextTick(() => {
|
||||
// 标记动画已经结束了
|
||||
this.transitionEnded = false
|
||||
// 组件执行动画,到了执行的执行时间后,执行一些额外处理
|
||||
setTimeout(this.onTransitionEnd, this.duration)
|
||||
this.classes = classNames['leave-to']
|
||||
})
|
||||
},
|
||||
// #endif
|
||||
// #ifdef APP-NVUE
|
||||
// nvue版本动画进场
|
||||
nvueEnter() {
|
||||
// 获得样式的名称
|
||||
const currentStyle = getStyle(this.mode)
|
||||
// 组件动画状态和发出事件
|
||||
this.status = 'enter'
|
||||
this.$emit('beforeEnter')
|
||||
// 展示生成组件元素
|
||||
this.inited = true
|
||||
this.display = true
|
||||
// 在nvue安卓上,由于渲染速度慢,在弹窗,键盘,日历等组件中,渲染其中的内容需要时间
|
||||
// 导致出现弹窗卡顿,这里让其一开始为透明状态,等一定时间渲染完成后,再让其隐藏起来,再让其按正常逻辑出现
|
||||
this.viewStyle = {
|
||||
opacity: 0
|
||||
}
|
||||
// 等待弹窗内容渲染完成
|
||||
this.$nextTick(() => {
|
||||
// 合并样式
|
||||
this.viewStyle = currentStyle.enter
|
||||
Promise.resolve()
|
||||
.then(nextTick)
|
||||
.then(() => {
|
||||
// 组件开始进入前的事件
|
||||
this.$emit('enter')
|
||||
// nvue的transition动画模块需要通过ref调用组件,注意此处的ref不同于vue的this.$refs['u-transition']用法
|
||||
animation.transition(this.$refs['u-transition'].ref, {
|
||||
styles: currentStyle['enter-to'],
|
||||
duration: this.duration,
|
||||
timingFunction: this.timingFunction,
|
||||
needLayout: false,
|
||||
delay: 0
|
||||
}, () => {
|
||||
// 动画执行完毕,发出事件
|
||||
this.$emit('afterEnter')
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
})
|
||||
},
|
||||
nvueLeave() {
|
||||
if (!this.display) {
|
||||
return
|
||||
}
|
||||
const currentStyle = getStyle(this.mode)
|
||||
// 定义状态和事件
|
||||
this.status = 'leave'
|
||||
this.$emit('beforeLeave')
|
||||
// 合并样式
|
||||
this.viewStyle = currentStyle.leave
|
||||
// 放到promise中处理执行过程
|
||||
Promise.resolve()
|
||||
.then(nextTick) // 等待几十ms
|
||||
.then(() => {
|
||||
this.transitionEnded = false
|
||||
// 动画正在离场的状态
|
||||
this.$emit('leave')
|
||||
animation.transition(this.$refs['u-transition'].ref, {
|
||||
styles: currentStyle['leave-to'],
|
||||
duration: this.duration,
|
||||
timingFunction: this.timingFunction,
|
||||
needLayout: false,
|
||||
delay: 0
|
||||
}, () => {
|
||||
this.onTransitionEnd()
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
},
|
||||
// #endif
|
||||
// 完成过渡后触发
|
||||
onTransitionEnd() {
|
||||
// 如果已经是结束的状态,无需再处理
|
||||
if (this.transitionEnded) return
|
||||
this.transitionEnded = true
|
||||
// 发出组件动画执行后的事件
|
||||
this.$emit(this.status === 'leave' ? 'afterLeave' : 'afterEnter')
|
||||
if (!this.show && this.display) {
|
||||
this.display = false
|
||||
this.inited = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
113
components/d-transition/vue.ani-style.scss
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* vue版本动画内置的动画模式有如下:
|
||||
* fade:淡入
|
||||
* zoom:缩放
|
||||
* fade-zoom:缩放淡入
|
||||
* fade-up:上滑淡入
|
||||
* fade-down:下滑淡入
|
||||
* fade-left:左滑淡入
|
||||
* fade-right:右滑淡入
|
||||
* slide-up:上滑进入
|
||||
* slide-down:下滑进入
|
||||
* slide-left:左滑进入
|
||||
* slide-right:右滑进入
|
||||
*/
|
||||
|
||||
$u-zoom-scale: scale(0.95);
|
||||
|
||||
.u-fade-enter-active,
|
||||
.u-fade-leave-active {
|
||||
transition-property: opacity;
|
||||
}
|
||||
|
||||
.u-fade-enter,
|
||||
.u-fade-leave-to {
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.u-fade-zoom-enter,
|
||||
.u-fade-zoom-leave-to {
|
||||
transform: $u-zoom-scale;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.u-fade-zoom-enter-active,
|
||||
.u-fade-zoom-leave-active {
|
||||
transition-property: transform, opacity;
|
||||
}
|
||||
|
||||
.u-fade-down-enter-active,
|
||||
.u-fade-down-leave-active,
|
||||
.u-fade-left-enter-active,
|
||||
.u-fade-left-leave-active,
|
||||
.u-fade-right-enter-active,
|
||||
.u-fade-right-leave-active,
|
||||
.u-fade-up-enter-active,
|
||||
.u-fade-up-leave-active {
|
||||
transition-property: opacity, transform;
|
||||
}
|
||||
|
||||
.u-fade-up-enter,
|
||||
.u-fade-up-leave-to {
|
||||
transform: translate3d(0, 100%, 0);
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.u-fade-down-enter,
|
||||
.u-fade-down-leave-to {
|
||||
transform: translate3d(0, -100%, 0);
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.u-fade-left-enter,
|
||||
.u-fade-left-leave-to {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.u-fade-right-enter,
|
||||
.u-fade-right-leave-to {
|
||||
transform: translate3d(100%, 0, 0);
|
||||
opacity: 0
|
||||
}
|
||||
|
||||
.u-slide-down-enter-active,
|
||||
.u-slide-down-leave-active,
|
||||
.u-slide-left-enter-active,
|
||||
.u-slide-left-leave-active,
|
||||
.u-slide-right-enter-active,
|
||||
.u-slide-right-leave-active,
|
||||
.u-slide-up-enter-active,
|
||||
.u-slide-up-leave-active {
|
||||
transition-property: transform;
|
||||
}
|
||||
|
||||
.u-slide-up-enter,
|
||||
.u-slide-up-leave-to {
|
||||
transform: translate3d(0, 100%, 0)
|
||||
}
|
||||
|
||||
.u-slide-down-enter,
|
||||
.u-slide-down-leave-to {
|
||||
transform: translate3d(0, -100%, 0)
|
||||
}
|
||||
|
||||
.u-slide-left-enter,
|
||||
.u-slide-left-leave-to {
|
||||
transform: translate3d(-100%, 0, 0)
|
||||
}
|
||||
|
||||
.u-slide-right-enter,
|
||||
.u-slide-right-leave-to {
|
||||
transform: translate3d(100%, 0, 0)
|
||||
}
|
||||
|
||||
.u-zoom-enter-active,
|
||||
.u-zoom-leave-active {
|
||||
transition-property: transform
|
||||
}
|
||||
|
||||
.u-zoom-enter,
|
||||
.u-zoom-leave-to {
|
||||
transform: $u-zoom-scale
|
||||
}
|
||||
658
components/d-upload/d-upload.vue
Normal file
@@ -0,0 +1,658 @@
|
||||
<template>
|
||||
<view class="u-upload" v-if="!disabled">
|
||||
<view v-if="showUploadList" class="u-list-item u-preview-wrap" v-for="(item, index) in lists" :key="index"
|
||||
:style="[{
|
||||
width: $u.addUnit(width),
|
||||
height: $u.addUnit(height)
|
||||
},customStyle]">
|
||||
<view v-if="deletable" class="u-delete-icon" @tap.stop="deleteItem(index)" :style="{
|
||||
background: delBgColor
|
||||
}">
|
||||
<u-icon class="u-icon" :name="delIcon" size="20" :color="delColor"></u-icon>
|
||||
</view>
|
||||
<u-line-progress v-if="showProgress && item.progress > 0 && !item.error" :show-percent="false" height="16"
|
||||
class="u-progress" :percent="item.progress" active-color='#2979ff'></u-line-progress>
|
||||
<view @tap.stop="retry(index)" v-if="item.error" class="u-error-btn">点击重试</view>
|
||||
<image @tap.stop="doPreviewImage(item.url || item.path, index)" class="u-preview-image" v-if="!item.isImage"
|
||||
:src="item.url || item.path" :mode="imageMode"></image>
|
||||
</view>
|
||||
<slot name="file" :file="lists"></slot>
|
||||
<view style="display: inline-block;" @tap="selectFile" v-if="maxCount > lists.length">
|
||||
<slot name="addBtn"></slot>
|
||||
<view v-if="!customBtn" class="u-list-item u-add-wrap" hover-class="u-add-wrap__hover" hover-stay-time="150"
|
||||
:style="[{
|
||||
width: $u.addUnit(width),
|
||||
height: $u.addUnit(height)
|
||||
},customStyle]">
|
||||
<u-icon name="plus" class="u-add-btn" size="40"></u-icon>
|
||||
<view class="u-add-tips">{{ uploadText }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* upload 图片上传
|
||||
* @description 该组件用于上传图片场景
|
||||
* @tutorial https://www.uviewui.com/components/upload.html
|
||||
* @property {String} action 服务器上传地址
|
||||
* @property {String Number} max-count 最大选择图片的数量(默认99)
|
||||
* @property {Boolean} custom-btn 如果需要自定义选择图片的按钮,设置为true(默认false)
|
||||
* @property {Boolean} show-progress 是否显示进度条(默认true)
|
||||
* @property {Boolean} disabled 是否启用(显示/移仓)组件(默认false)
|
||||
* @property {String} image-mode 预览图片等显示模式,可选值为uni的image的mode属性值(默认aspectFill)
|
||||
* @property {String} del-icon 右上角删除图标名称,只能为uView内置图标
|
||||
* @property {String} del-bg-color 右上角关闭按钮的背景颜色
|
||||
* @property {String | Number} index 在各个回调事件中的最后一个参数返回,用于区别是哪一个组件的事件
|
||||
* @property {String} del-color 右上角关闭按钮图标的颜色
|
||||
* @property {Object} header 上传携带的头信息,对象形式
|
||||
* @property {Object} form-data 上传额外携带的参数
|
||||
* @property {String} name 上传文件的字段名,供后端获取使用(默认file)
|
||||
* @property {Array<String>} size-type original 原图,compressed 压缩图,默认二者都有(默认['original', 'compressed'])
|
||||
* @property {Array<String>} source-type 选择图片的来源,album-从相册选图,camera-使用相机,默认二者都有(默认['album', 'camera'])
|
||||
* @property {Boolean} preview-full-image 是否可以通过uni.previewImage预览已选择的图片(默认true)
|
||||
* @property {Boolean} multiple 是否开启图片多选,部分安卓机型不支持(默认true)
|
||||
* @property {Boolean} deletable 是否显示删除图片的按钮(默认true)
|
||||
* @property {String Number} max-size 选择单个文件的最大大小,单位B(byte),默认不限制(默认Number.MAX_VALUE)
|
||||
* @property {Array<Object>} file-list 默认显示的图片列表,数组元素为对象,必须提供url属性
|
||||
* @property {Boolean} upload-text 选择图片按钮的提示文字(默认“选择图片”)
|
||||
* @property {Boolean} auto-upload 选择完图片是否自动上传,见上方说明(默认true)
|
||||
* @property {Boolean} show-tips 特殊情况下是否自动提示toast,见上方说明(默认true)
|
||||
* @property {Boolean} show-upload-list 是否显示组件内部的图片预览(默认true)
|
||||
* @event {Function} on-oversize 图片大小超出最大允许大小
|
||||
* @event {Function} on-preview 全屏预览图片时触发
|
||||
* @event {Function} on-remove 移除图片时触发
|
||||
* @event {Function} on-success 图片上传成功时触发
|
||||
* @event {Function} on-change 图片上传后,无论成功或者失败都会触发
|
||||
* @event {Function} on-error 图片上传失败时触发
|
||||
* @event {Function} on-progress 图片上传过程中的进度变化过程触发
|
||||
* @event {Function} on-uploaded 所有图片上传完毕触发
|
||||
* @event {Function} on-choose-complete 每次选择图片后触发,只是让外部可以得知每次选择后,内部的文件列表
|
||||
* @example <u-upload :action="action" :file-list="fileList" ></u-upload>
|
||||
*/
|
||||
export default {
|
||||
name: 'd-upload',
|
||||
props: {
|
||||
//是否显示组件自带的图片预览功能
|
||||
showUploadList: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 后端地址
|
||||
action: {
|
||||
type: String,
|
||||
default: 'https://app.xiaokang88.com/service/v1/attachment/upload'
|
||||
},
|
||||
// 最大上传数量
|
||||
maxCount: {
|
||||
type: [String, Number],
|
||||
default: 52
|
||||
},
|
||||
// 是否显示进度条
|
||||
showProgress: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否启用
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 预览上传的图片时的裁剪模式,和image组件mode属性一致
|
||||
imageMode: {
|
||||
type: String,
|
||||
default: 'aspectFill'
|
||||
},
|
||||
// 头部信息
|
||||
header: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
|
||||
};
|
||||
}
|
||||
},
|
||||
// 额外携带的参数
|
||||
formData: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {
|
||||
store_id: '11001'
|
||||
};
|
||||
}
|
||||
},
|
||||
// 上传的文件字段名
|
||||
name: {
|
||||
type: String,
|
||||
default: 'file'
|
||||
},
|
||||
// 所选的图片的尺寸, 可选值为original compressed
|
||||
sizeType: {
|
||||
type: Array,
|
||||
default () {
|
||||
return ['original', 'compressed'];
|
||||
}
|
||||
},
|
||||
sourceType: {
|
||||
type: Array,
|
||||
default () {
|
||||
return ['album', 'camera'];
|
||||
}
|
||||
},
|
||||
// 是否在点击预览图后展示全屏图片预览
|
||||
previewFullImage: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否开启图片多选,部分安卓机型不支持
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否展示删除按钮
|
||||
deletable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 文件大小限制,单位为byte
|
||||
maxSize: {
|
||||
type: [String, Number],
|
||||
default: Number.MAX_VALUE
|
||||
},
|
||||
// 显示已上传的文件列表
|
||||
fileList: {
|
||||
type: Array,
|
||||
default () {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
// 上传区域的提示文字
|
||||
uploadText: {
|
||||
type: String,
|
||||
default: '选择图片'
|
||||
},
|
||||
// 是否自动上传
|
||||
autoUpload: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否显示toast消息提示
|
||||
showTips: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 是否通过slot自定义传入选择图标的按钮
|
||||
customBtn: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// 内部预览图片区域和选择图片按钮的区域宽度
|
||||
width: {
|
||||
type: [String, Number],
|
||||
default: 200
|
||||
},
|
||||
// 内部预览图片区域和选择图片按钮的区域高度
|
||||
height: {
|
||||
type: [String, Number],
|
||||
default: 200
|
||||
},
|
||||
// 右上角关闭按钮的背景颜色
|
||||
delBgColor: {
|
||||
type: String,
|
||||
default: '#fa3534'
|
||||
},
|
||||
// 右上角关闭按钮的叉号图标的颜色
|
||||
delColor: {
|
||||
type: String,
|
||||
default: '#ffffff'
|
||||
},
|
||||
// 右上角删除图标名称,只能为uView内置图标
|
||||
delIcon: {
|
||||
type: String,
|
||||
default: 'close'
|
||||
},
|
||||
// 如果上传后的返回值为json字符串,是否自动转json
|
||||
toJson: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 上传前的钩子,每个文件上传前都会执行
|
||||
beforeUpload: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
// 移除文件前的钩子
|
||||
beforeRemove: {
|
||||
type: Function,
|
||||
default: null
|
||||
},
|
||||
// 允许上传的图片后缀
|
||||
limitType: {
|
||||
type: Array,
|
||||
default () {
|
||||
// 支付宝小程序真机选择图片的后缀为"image"
|
||||
// https://opendocs.alipay.com/mini/api/media-image
|
||||
return ['png', 'jpg', 'jpeg', 'webp', 'gif', 'image'];
|
||||
}
|
||||
},
|
||||
// 在各个回调事件中的最后一个参数返回,用于区别是哪一个组件的事件
|
||||
index: {
|
||||
type: [Number, String],
|
||||
default: ''
|
||||
},
|
||||
customStyle: {
|
||||
type: Object,
|
||||
default () {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
data() {
|
||||
return {
|
||||
lists: [],
|
||||
isInCount: true,
|
||||
uploading: false
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
fileList: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
val.map(value => {
|
||||
// 首先检查内部是否已经添加过这张图片,因为外部绑定了一个对象给fileList的话(对象引用),进行修改外部fileList
|
||||
// 时,会触发watch,导致重新把原来的图片再次添加到this.lists
|
||||
// 数组的some方法意思是,只要数组元素有任意一个元素条件符合,就返回true,而另一个数组的every方法的意思是数组所有元素都符合条件才返回true
|
||||
let tmp = this.lists.some(val => {
|
||||
return val.url == value.url;
|
||||
})
|
||||
// 如果内部没有这个图片(tmp为false),则添加到内部
|
||||
value && !tmp && this.lists.push({
|
||||
url: value.url,
|
||||
error: false,
|
||||
progress: 100
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
// 监听lists的变化,发出事件
|
||||
lists(n) {
|
||||
this.$emit('on-list-change', n, this.index);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 清除列表
|
||||
clear() {
|
||||
this.lists = [];
|
||||
},
|
||||
// 重新上传队列中上传失败的所有文件
|
||||
reUpload() {
|
||||
this.uploadFile();
|
||||
},
|
||||
// 选择图片
|
||||
selectFile() {
|
||||
if (this.disabled) return;
|
||||
const {
|
||||
name = '', maxCount, multiple, maxSize, sizeType, lists, camera, compressed, maxDuration, sourceType
|
||||
} = this;
|
||||
let chooseFile = null;
|
||||
const newMaxCount = maxCount - lists.length;
|
||||
// 设置为只选择图片的时候使用 chooseImage 来实现
|
||||
chooseFile = new Promise((resolve, reject) => {
|
||||
uni.chooseImage({
|
||||
count: multiple ? (newMaxCount > 9 ? 9 : newMaxCount) : 1,
|
||||
sourceType: sourceType,
|
||||
sizeType,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
chooseFile
|
||||
.then(res => {
|
||||
let file = null;
|
||||
let listOldLength = this.lists.length;
|
||||
res.tempFiles.map((val, index) => {
|
||||
// 检查文件后缀是否允许,如果不在this.limitType内,就会返回false
|
||||
if (!this.checkFileExt(val)) return;
|
||||
|
||||
// 如果是非多选,index大于等于1或者超出最大限制数量时,不处理
|
||||
if (!multiple && index >= 1) return;
|
||||
if (val.size > maxSize) {
|
||||
this.$emit('on-oversize', val, this.lists, this.index);
|
||||
this.showToast('超出允许的文件大小');
|
||||
} else {
|
||||
if (maxCount <= lists.length) {
|
||||
this.$emit('on-exceed', val, this.lists, this.index);
|
||||
this.showToast('超出最大允许的文件个数');
|
||||
return;
|
||||
}
|
||||
lists.push({
|
||||
url: val.path,
|
||||
progress: 0,
|
||||
error: false,
|
||||
file: val
|
||||
});
|
||||
}
|
||||
});
|
||||
// 每次图片选择完,抛出一个事件,并将当前内部选择的图片数组抛出去
|
||||
this.$emit('on-choose-complete', this.lists, this.index);
|
||||
if (this.autoUpload) this.uploadFile(listOldLength);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$emit('on-choose-fail', error);
|
||||
});
|
||||
},
|
||||
// 提示用户消息
|
||||
showToast(message, force = false) {
|
||||
if (this.showTips || force) {
|
||||
this.$toast(message)
|
||||
}
|
||||
},
|
||||
// 该方法供用户通过ref调用,手动上传
|
||||
upload() {
|
||||
this.uploadFile();
|
||||
},
|
||||
// 对失败的图片重新上传
|
||||
retry(index) {
|
||||
this.lists[index].progress = 0;
|
||||
this.lists[index].error = false;
|
||||
this.lists[index].response = null;
|
||||
uni.showLoading({
|
||||
title: '重新上传'
|
||||
});
|
||||
this.uploadFile(index);
|
||||
},
|
||||
// 上传图片
|
||||
async uploadFile(index = 0) {
|
||||
if (this.disabled) return;
|
||||
if (this.uploading) return;
|
||||
// 全部上传完成
|
||||
if (index >= this.lists.length) {
|
||||
this.$emit('on-uploaded', this.lists, this.index);
|
||||
return;
|
||||
}
|
||||
// 检查是否是已上传或者正在上传中
|
||||
if (this.lists[index].progress == 100) {
|
||||
if (this.autoUpload == false) this.uploadFile(index + 1);
|
||||
return;
|
||||
}
|
||||
// 执行before-upload钩子
|
||||
if (this.beforeUpload && typeof(this.beforeUpload) === 'function') {
|
||||
// 执行回调,同时传入索引和文件列表当作参数
|
||||
// 在微信,支付宝等环境(H5正常),会导致父组件定义的customBack()函数体中的this变成子组件的this
|
||||
// 通过bind()方法,绑定父组件的this,让this.customBack()的this为父组件的上下文
|
||||
// 因为upload组件可能会被嵌套在其他组件内,比如u-form,这时this.$parent其实为u-form的this,
|
||||
// 非页面的this,所以这里需要往上历遍,一直寻找到最顶端的$parent,这里用了this.$u.$parent.call(this)
|
||||
// 明白意思即可,无需纠结this.$u.$parent.call(this)的细节
|
||||
let beforeResponse = this.beforeUpload.bind(this.$u.$parent.call(this))(index, this.lists);
|
||||
// 判断是否返回了promise
|
||||
if (!!beforeResponse && typeof beforeResponse.then === 'function') {
|
||||
await beforeResponse.then(res => {
|
||||
// promise返回成功,不进行动作,继续上传
|
||||
}).catch(err => {
|
||||
// 进入catch回调的话,继续下一张
|
||||
return this.uploadFile(index + 1);
|
||||
})
|
||||
} else if (beforeResponse === false) {
|
||||
// 如果返回false,继续下一张图片的上传
|
||||
return this.uploadFile(index + 1);
|
||||
} else {
|
||||
// 此处为返回"true"的情形,这里不写代码,就跳过此处,继续执行当前的上传逻辑
|
||||
}
|
||||
}
|
||||
// 检查上传地址
|
||||
if (!this.action) {
|
||||
this.showToast('请配置上传地址', true);
|
||||
return;
|
||||
}
|
||||
this.lists[index].error = false;
|
||||
this.uploading = true;
|
||||
// 创建上传对象
|
||||
const task = uni.uploadFile({
|
||||
url: this.action,
|
||||
filePath: this.lists[index].url,
|
||||
name: this.name,
|
||||
formData: this.formData,
|
||||
header: {
|
||||
...this.header,
|
||||
authorization: `Bearer ${uni.getStorageSync('token')}`
|
||||
},
|
||||
success: res => {
|
||||
// 判断是否json字符串,将其转为json格式
|
||||
let data = this.toJson && this.$u.test.jsonString(res.data) ? JSON.parse(res
|
||||
.data) : res.data;
|
||||
if (![200, 201, 204].includes(res.statusCode)) {
|
||||
this.uploadError(index, data);
|
||||
} else {
|
||||
// 上传成功
|
||||
this.lists[index].data = data;
|
||||
this.lists[index].progress = 100;
|
||||
this.lists[index].error = false;
|
||||
this.lists[index].url = data.data.url;
|
||||
this.$emit('on-success', data, index, this.lists, this.index);
|
||||
}
|
||||
},
|
||||
fail: e => {
|
||||
this.uploadError(index, e);
|
||||
},
|
||||
complete: res => {
|
||||
uni.hideLoading();
|
||||
this.uploading = false;
|
||||
this.uploadFile(index + 1);
|
||||
this.$emit('on-change', res, index, this.lists, this.index);
|
||||
}
|
||||
});
|
||||
task.onProgressUpdate(res => {
|
||||
if (res.progress > 0) {
|
||||
this.lists[index].progress = res.progress;
|
||||
this.$emit('on-progress', res, index, this.lists, this.index);
|
||||
}
|
||||
});
|
||||
},
|
||||
// 上传失败
|
||||
uploadError(index, err) {
|
||||
this.lists[index].progress = 0;
|
||||
this.lists[index].error = true;
|
||||
this.lists[index].response = null;
|
||||
this.$emit('on-error', err, index, this.lists, this.index);
|
||||
this.showToast('上传失败,请重试');
|
||||
},
|
||||
// 删除一个图片
|
||||
deleteItem(index) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '您确定要删除此项吗?',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
// 先检查是否有定义before-remove移除前钩子
|
||||
// 执行before-remove钩子
|
||||
if (this.beforeRemove && typeof(this.beforeRemove) === 'function') {
|
||||
// 此处钩子执行 原理同before-remove参数,见上方注释
|
||||
let beforeResponse = this.beforeRemove.bind(this.$u.$parent.call(this))(index,
|
||||
this.lists);
|
||||
// 判断是否返回了promise
|
||||
if (!!beforeResponse && typeof beforeResponse.then === 'function') {
|
||||
await beforeResponse.then(res => {
|
||||
// promise返回成功,不进行动作,继续上传
|
||||
this.handlerDeleteItem(index);
|
||||
}).catch(err => {
|
||||
// 如果进入promise的reject,终止删除操作
|
||||
this.showToast('已终止移除');
|
||||
})
|
||||
} else if (beforeResponse === false) {
|
||||
// 返回false,终止删除
|
||||
this.showToast('已终止移除');
|
||||
} else {
|
||||
// 如果返回true,执行删除操作
|
||||
this.handlerDeleteItem(index);
|
||||
}
|
||||
} else {
|
||||
// 如果不存在before-remove钩子,
|
||||
this.handlerDeleteItem(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// 执行移除图片的动作,上方代码只是判断是否可以移除
|
||||
handlerDeleteItem(index) {
|
||||
// 如果文件正在上传中,终止上传任务,进度在0 < progress < 100则意味着正在上传
|
||||
if (this.lists[index].process < 100 && this.lists[index].process > 0) {
|
||||
typeof this.lists[index].uploadTask != 'undefined' && this.lists[index].uploadTask.abort();
|
||||
}
|
||||
this.lists.splice(index, 1);
|
||||
this.$forceUpdate();
|
||||
this.$emit('on-remove', index, this.lists, this.index);
|
||||
this.showToast('移除成功');
|
||||
},
|
||||
// 用户通过ref手动的形式,移除一张图片
|
||||
remove(index) {
|
||||
// 判断索引的合法范围
|
||||
if (index >= 0 && index < this.lists.length) {
|
||||
this.lists.splice(index, 1);
|
||||
this.$emit('on-list-change', this.lists, this.index);
|
||||
}
|
||||
},
|
||||
// 预览图片
|
||||
doPreviewImage(url, index) {
|
||||
if (!this.previewFullImage) return;
|
||||
const images = this.lists.map(item => item.url || item.path);
|
||||
uni.previewImage({
|
||||
urls: images,
|
||||
current: url,
|
||||
success: () => {
|
||||
this.$emit('on-preview', url, this.lists, this.index);
|
||||
},
|
||||
fail: () => {
|
||||
this.$toast('预览图片失败')
|
||||
}
|
||||
});
|
||||
},
|
||||
// 判断文件后缀是否允许
|
||||
checkFileExt(file) {
|
||||
// 检查是否在允许的后缀中
|
||||
let noArrowExt = false;
|
||||
// 获取后缀名
|
||||
let fileExt = '';
|
||||
const reg = /.+\./;
|
||||
// 如果是H5,需要从name中判断
|
||||
// #ifdef H5
|
||||
fileExt = file.name.replace(reg, "").toLowerCase();
|
||||
// #endif
|
||||
// 非H5,需要从path中读取后缀
|
||||
// #ifndef H5
|
||||
fileExt = file.path.replace(reg, "").toLowerCase();
|
||||
// #endif
|
||||
// 使用数组的some方法,只要符合limitType中的一个,就返回true
|
||||
noArrowExt = this.limitType.some(ext => {
|
||||
// 转为小写
|
||||
return ext.toLowerCase() === fileExt;
|
||||
})
|
||||
if (!noArrowExt) this.showToast(`不允许选择${fileExt}格式的文件`);
|
||||
return noArrowExt;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
// 定义混入指令,用于在非nvue环境下的flex定义,因为nvue没有display属性,会报错
|
||||
@mixin vue-flex($direction: row) {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
flex-direction: $direction;
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
.u-upload {
|
||||
@include vue-flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.u-list-item {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
overflow: hidden;
|
||||
margin: 10rpx;
|
||||
background: rgb(244, 245, 246);
|
||||
position: relative;
|
||||
border-radius: 10rpx;
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.u-preview-wrap {
|
||||
border: 1px solid rgb(235, 236, 238);
|
||||
margin-right: 10rpx !important;
|
||||
}
|
||||
|
||||
.u-add-wrap {
|
||||
flex-direction: column;
|
||||
color: $u-content-color;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.u-add-tips {
|
||||
margin-top: 20rpx;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.u-add-wrap__hover {
|
||||
background-color: rgb(235, 236, 238);
|
||||
}
|
||||
|
||||
.u-preview-image {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.u-delete-icon {
|
||||
position: absolute;
|
||||
top: 10rpx;
|
||||
right: 10rpx;
|
||||
z-index: 10;
|
||||
background-color: $u-type-error;
|
||||
border-radius: 100rpx;
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
@include vue-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.u-icon {
|
||||
@include vue-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.u-progress {
|
||||
position: absolute;
|
||||
bottom: 10rpx;
|
||||
left: 8rpx;
|
||||
right: 8rpx;
|
||||
z-index: 9;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.u-error-btn {
|
||||
color: #ffffff;
|
||||
background-color: $u-type-error;
|
||||
font-size: 20rpx;
|
||||
padding: 4px 0;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 9;
|
||||
line-height: 1;
|
||||
}
|
||||
</style>
|
||||
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>
|
||||
91
main.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import App from './App'
|
||||
import {
|
||||
addStyle,
|
||||
navbarHeight,
|
||||
m_by_checkID,
|
||||
getAge
|
||||
} from '@/common/js/util.js'
|
||||
// 引入uView主JS库
|
||||
import uView from "uview-ui";
|
||||
import store from './store';
|
||||
import share from '@/common/share.js'
|
||||
Vue.mixin(share)
|
||||
Vue.use(uView);
|
||||
let systemInfo = uni.getSystemInfoSync();
|
||||
const $d = {
|
||||
addStyle,
|
||||
navbarHeight,
|
||||
sys: systemInfo,
|
||||
getAge
|
||||
}
|
||||
Vue.prototype.$toast = (title='', icon = 'none',duration=1500) => {
|
||||
uni.showToast({
|
||||
icon,
|
||||
title,
|
||||
duration
|
||||
})
|
||||
}
|
||||
Vue.prototype.$go = (url, type = 0) => {
|
||||
let userInfo = uni.getStorageSync('userInfo') || true;
|
||||
const whitelist = ['pages', 'pharmacist_setInfo','workbench_succeed']
|
||||
if (type!=4&&!whitelist.find(item => url.includes(item)) && userInfo && userInfo.status <= 1) {
|
||||
Vue.prototype.$toast('资质审核通过后可开通')
|
||||
return
|
||||
}
|
||||
let way = 'navigateTo';
|
||||
switch (type) {
|
||||
case 0:
|
||||
way = 'navigateTo';
|
||||
break;
|
||||
case 1:
|
||||
way = 'redirectTo';
|
||||
break;
|
||||
case 2:
|
||||
way = 'reLaunch';
|
||||
break;
|
||||
case 3:
|
||||
way = 'switchTab';
|
||||
break;
|
||||
case 4:
|
||||
way = 'navigateBack';
|
||||
break;
|
||||
}
|
||||
type == 4 ? uni.navigateBack(url) : uni[way]({
|
||||
url: url,
|
||||
fail: (e) => {
|
||||
console.log(e);
|
||||
}
|
||||
})
|
||||
}
|
||||
// $d挂载到uni对象上
|
||||
uni.$d = $d
|
||||
Vue.prototype.$statusBarHeight = systemInfo.statusBarHeight
|
||||
Vue.prototype.$d = $d
|
||||
Vue.prototype.$navbarHeight = uni.$d.navbarHeight()
|
||||
Vue.prototype.$windowHeight = systemInfo.windowHeight
|
||||
Vue.prototype.$screenHeight = systemInfo.screenHeight
|
||||
Vue.prototype.$checkID = m_by_checkID
|
||||
Vue.prototype.$male = require('@/static/image/nan.png')
|
||||
Vue.prototype.$girl = require('@/static/image/nv.png')
|
||||
// #ifndef VUE3
|
||||
import Vue from 'vue'
|
||||
Vue.config.productionTip = false
|
||||
App.mpType = 'app'
|
||||
const app = new Vue({
|
||||
store,
|
||||
...App
|
||||
})
|
||||
app.$mount()
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE3
|
||||
import {
|
||||
createSSRApp
|
||||
} from 'vue'
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
return {
|
||||
app
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
80
manifest.json
Normal file
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"name" : "xiaokang_doctor",
|
||||
"appid" : "__UNI__2465184",
|
||||
"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" : {},
|
||||
/* 小程序特有相关wx8e8f04d0cf7831bf */
|
||||
"mp-weixin" : {
|
||||
"appid" : "wx6a823aa229ab67c7",
|
||||
"setting" : {
|
||||
"urlCheck" : true,
|
||||
"es6" : true,
|
||||
"postcss" : true,
|
||||
"minified" : true
|
||||
},
|
||||
"usingComponents" : true,
|
||||
"optimization" : {
|
||||
"subPackages" : true
|
||||
},
|
||||
"lazyCodeLoading" : "requiredComponents",
|
||||
"plugins" : {}
|
||||
},
|
||||
"mp-alipay" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-baidu" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"mp-toutiao" : {
|
||||
"usingComponents" : true
|
||||
},
|
||||
"uniStatistics" : {
|
||||
"enable" : false
|
||||
},
|
||||
"vueVersion" : "2"
|
||||
}
|
||||
12
package.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"id": "cu-editor",
|
||||
"name": "微信小程序富文本编辑器(仿腾讯文档)",
|
||||
"version": "1.0.4",
|
||||
"description": "照着腾讯文档小程序开发了微信小程序富文本编辑器组件,这几天做个整理,如果有这个需求可以前往腾讯文档小程序操作看看实际效果。腾讯文档小程序用的不是原生的组件,当前项目按现有开放api尽可能实现。",
|
||||
"keywords": [
|
||||
"editor"
|
||||
],
|
||||
"dependencies": {
|
||||
"uview-ui": "^1.8.8"
|
||||
}
|
||||
}
|
||||
426
pages.json
Normal file
@@ -0,0 +1,426 @@
|
||||
{
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
|
||||
"^d-(.*)": "@/components/d-$1/d-$1.vue"
|
||||
},
|
||||
"pages": [{
|
||||
"path": "pages/login/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/register",
|
||||
"style": {
|
||||
"navigationBarTitleText": "注册",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/workbench/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "工作台",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/workbench/examine",
|
||||
"style": {
|
||||
"navigationBarTitleText": "账号审核"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/patient/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "患者",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my/prescriptionList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的处方"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/workbench/prescriptionList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "待流转处方"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/workbench/prescriptionDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "处方详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my/prescriptionDetail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "处方详情"
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"path": "pages/pharmacist/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "药师",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pharmacist/pharmacist-my",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [{
|
||||
"root": "subPackages/sub_workbench",
|
||||
"pages": [{
|
||||
"path": "workbench_upInfo/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "上传资料",
|
||||
"enablePullDownRefresh ": false, //此设置 是否开启当前页面下拉刷新。
|
||||
"disableScroll": false //此设置 是否允许页面整体上下滚动。
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_consult",
|
||||
"style": {
|
||||
"navigationBarTitleText": "图文咨询",
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_identity",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择身份",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_reception",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加载中..."
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_succeed",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加载中..."
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_announcement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "停诊公告"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_upInfo/select",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加载中...",
|
||||
"enablePullDownRefresh": true,
|
||||
"backgroundColor": "#000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_evaluation",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的评价",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_reason",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择退诊原因"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_recipe/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "处方详情",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_recipe/add",
|
||||
"style": {
|
||||
"navigationBarTitleText": "添加商品"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_recipe/addType2",
|
||||
"style": {
|
||||
"navigationBarTitleText": "添加商品"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_recipe/common",
|
||||
"style": {
|
||||
"navigationBarTitleText": "常用方"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_recipe/commonDetails",
|
||||
"style": {
|
||||
"navigationBarTitleText": "常用方详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_basicInfo",
|
||||
"style": {
|
||||
"navigationBarTitleText": "基础健康信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_inquiries",
|
||||
"style": {
|
||||
"navigationBarTitleText": "问诊记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_used_language",
|
||||
"style": {
|
||||
"navigationBarTitleText": "常用语管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "workbench_code",
|
||||
"style": {
|
||||
"navigationBarTitleText": "医生码"
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"path": "workbench_infoPatient",
|
||||
"style": {
|
||||
"navigationBarTitleText": "患者详情"
|
||||
}
|
||||
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "subPackages/sub_patient",
|
||||
"pages": [{
|
||||
"path": "patient_label",
|
||||
"style": {
|
||||
"navigationBarTitleText": "消息",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "patient_massInfo",
|
||||
"style": {
|
||||
"navigationBarTitleText": "群发信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "patient_select",
|
||||
"style": {
|
||||
"navigationBarTitleText": "群发信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "article_select",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择文章"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "patient_details",
|
||||
"style": {
|
||||
"navigationBarTitleText": "患者详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "to-store",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加载中...",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "patient_detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "患者详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "subPackages/sub_my",
|
||||
"pages": [{
|
||||
"path": "my_setAct",
|
||||
"style": {
|
||||
"navigationBarTitleText": "加载中...",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "my_revenue/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "挂号费用",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}, {
|
||||
"path": "my_revenue/withdraw",
|
||||
"style": {
|
||||
"navigationBarTitleText": "申请提现"
|
||||
}
|
||||
}, {
|
||||
"path": "my_revenue/record",
|
||||
"style": {
|
||||
"navigationBarTitleText": "提现记录"
|
||||
}
|
||||
}, {
|
||||
"path": "my_revenue/earnings",
|
||||
"style": {
|
||||
"navigationBarTitleText": "收益明细"
|
||||
}
|
||||
}, {
|
||||
"path": "my_service",
|
||||
"style": {
|
||||
"navigationBarTitleText": "服务设置"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "my_diagnose_common",
|
||||
"style": {
|
||||
"navigationBarTitleText": "常用医嘱管理"
|
||||
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "subPackages/sub_pharmacist",
|
||||
"pages": [{
|
||||
"path": "pharmacist_info",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人资料",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "im",
|
||||
"style": {
|
||||
"navigationBarTitleText": "咨询"
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pharmacist_setInfo",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设置",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "change_password",
|
||||
"style": {
|
||||
"navigationBarTitleText": "修改登录密码"
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pharmacist_prescription",
|
||||
"style": {
|
||||
"navigationBarTitleText": "查看处方",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pharmacist_traceability",
|
||||
"style": {
|
||||
"navigationBarTitleText": "处方溯源",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pharmacist_access",
|
||||
"style": {
|
||||
"navigationBarTitleText": "待接入用户"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pharmacist_triage",
|
||||
"style": {
|
||||
"navigationBarTitleText": "选择医生",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
"path": "myrecord-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "处方详情"
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
]
|
||||
}, {
|
||||
"root": "subPackages/sub_agreement",
|
||||
"pages": [{
|
||||
"path": "agreement",
|
||||
"style": {
|
||||
"navigationBarTitleText": "协议"
|
||||
}
|
||||
}, {
|
||||
"path": "web-view",
|
||||
"style": {
|
||||
"navigationBarTitleText": "视频"
|
||||
}
|
||||
}]
|
||||
}
|
||||
],
|
||||
"tabBar": {
|
||||
"color": "#fff",
|
||||
"selectedColor": "#fff",
|
||||
"backgroundColor": "#fff",
|
||||
"borderStyle": "white",
|
||||
"list": [{
|
||||
"pagePath": "pages/workbench/index",
|
||||
"text": "工作台"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/patient/index",
|
||||
"text": "患者"
|
||||
},
|
||||
// {
|
||||
// "pagePath": "pages/article/index",
|
||||
// "text": "我的文章"
|
||||
// },
|
||||
{
|
||||
"pagePath": "pages/my/index",
|
||||
"text": "我的"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/pharmacist/index",
|
||||
"text": "审方"
|
||||
}
|
||||
]
|
||||
},
|
||||
"globalStyle": {
|
||||
"navigationBarTitleText": "萧康互联网医院",
|
||||
"navigationBarBackgroundColor": "#fff",
|
||||
"navigationBarTextStyle": "black",
|
||||
"backgroundColor": "#f7f8fa"
|
||||
}
|
||||
}
|
||||
396
pages/login/index.vue
Normal file
@@ -0,0 +1,396 @@
|
||||
<template>
|
||||
<view class="container safe-area-inset-bottom">
|
||||
|
||||
<view class="title">
|
||||
欢迎登录
|
||||
</view>
|
||||
|
||||
<view class="box">
|
||||
<view class="info">
|
||||
<view class="pwd">
|
||||
<d-input :maxlength="11" height="96" v-model="form['mobile']"
|
||||
:prefixIcon="require('../../static/image/act.png')" borderRadius="96rpx" prefixIconSize="40rpx"
|
||||
placeholder="请输入手机号" @input="is_d=false" :placeholder-style="{fontSize:'32rpx'}"
|
||||
:custom-style="{fontSize:'32rpx',paddingLeft:'60rpx'}" />
|
||||
</view>
|
||||
|
||||
<view class="pwd">
|
||||
<u-field v-model="smsCode" placeholder="请填写验证码" :placeholder-style="{fontSize:'32rpx'}">
|
||||
<u-button size="mini" slot="right" @click="getCode">{{codeText}}</u-button>
|
||||
</u-field>
|
||||
<u-verification-code ref="uCode" @change="codeChange" class="code">
|
||||
</u-verification-code>
|
||||
</view>
|
||||
|
||||
<view class="flex-row" style="margin-top: 88rpx;">
|
||||
<u-icon size="35" :color="form['check']?'#6ACDBB':'#e0fdff'" name="checkmark-circle-fill"
|
||||
@click="form['check']=!form['check']"></u-icon>
|
||||
<view class="agreement">
|
||||
我已阅读并同意
|
||||
<text
|
||||
@click="$go('/subPackages/sub_agreement/agreement?type=service_user_agreement')">《用户服务协议》</text>
|
||||
和
|
||||
<text
|
||||
@click="$go('/subPackages/sub_agreement/agreement?type=service_privacy_agreement')">《隐私权政策》</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- :disabled="!form['mobile']||!form['pwd']" -->
|
||||
<view class="btn">
|
||||
<u-button :throttle-time="20" shape="circle" @click="register" :ripple="true" :loading="loading">
|
||||
登录</u-button>
|
||||
</view>
|
||||
|
||||
<view class="register">
|
||||
<text @click="$go('../../subPackages/sub_workbench/workbench_identity')">手机号注册</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
login,
|
||||
register,
|
||||
agreement,
|
||||
getUserInfo,
|
||||
loginOrRe
|
||||
} from '../../api/all';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
form: {
|
||||
check: false
|
||||
},
|
||||
switchVal: false,
|
||||
is_d: false,
|
||||
statusBarHeight: this.$statusBarHeight,
|
||||
navbarHeight: this.$navbarHeight,
|
||||
mobile: '',
|
||||
codeText: '',
|
||||
smsCode: '',
|
||||
code: ''
|
||||
};
|
||||
},
|
||||
onLoad(e) {
|
||||
|
||||
|
||||
},
|
||||
mounted() {
|
||||
const token = uni.getStorageSync('token')
|
||||
const info = uni.getStorageSync('loginInfo')
|
||||
if (token&&info) {
|
||||
// 药师
|
||||
if (info.role == 2 && info.status > 0 && info!= 3) {
|
||||
setTimeout(() => {
|
||||
this.$go('/pages/pharmacist/index', 3)
|
||||
}, 200)
|
||||
return
|
||||
}
|
||||
|
||||
// 医生
|
||||
if (info.role == 1 && info.status > 0 && info.status != 3) {
|
||||
setTimeout(() => {
|
||||
this.$go('/pages/workbench/index', 2)
|
||||
}, 200)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toLogin() {
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: (loginRes) => {
|
||||
this.code = loginRes.code
|
||||
}
|
||||
})
|
||||
},
|
||||
//登录或者注册接口
|
||||
register() {
|
||||
//修改1
|
||||
if (!uni.$u.test.mobile(this.form['mobile'])) {
|
||||
this.$toast('请输入正确的手机号')
|
||||
return
|
||||
}
|
||||
if (!this.smsCode) {
|
||||
this.$toast('请输入验证码')
|
||||
return
|
||||
}
|
||||
|
||||
if (!this.form['check']) {
|
||||
this.$toast('请勾选协议')
|
||||
return
|
||||
}
|
||||
|
||||
const data = {
|
||||
store_id: '11001',
|
||||
mobile: this.form['mobile'],
|
||||
status: 3,
|
||||
smsCode: this.smsCode,
|
||||
code: this.code
|
||||
}
|
||||
|
||||
loginOrRe(data).then(res => {
|
||||
if (res.errcode != -1) {
|
||||
this.$toast(res.data[0])
|
||||
uni.setStorageSync('token', res.data['token'])
|
||||
// console.log(res);
|
||||
uni.setStorageSync('identity', res.data['ServiceUser']['role'])
|
||||
uni.setStorageSync('logInfo', res.data['ServiceUser'])
|
||||
|
||||
const data = {
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
}
|
||||
getUserInfo(data).then(res => {
|
||||
if (res.errcode != -1) {
|
||||
uni.setStorageSync('loginInfo', res.data)
|
||||
uni.setStorageSync('role', res.data.role)
|
||||
uni.setStorageSync('login_id', res.data['id'])
|
||||
uni.setStorageSync('login_status', res.data['status'])
|
||||
}
|
||||
// 未完善信息
|
||||
if (res.data.status == 0 ) {
|
||||
this.$toast('您还没有完善信息,请先完善信息')
|
||||
// this.$go('../../subPackages/sub_workbench/workbench_upInfo/index')
|
||||
uni.navigateTo({
|
||||
url:'../../subPackages/sub_workbench/workbench_upInfo/index'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
this.$toast(res.msg)
|
||||
})
|
||||
|
||||
|
||||
// 药师
|
||||
if (res.data.ServiceUser.role == 2 && res.data.ServiceUser.status ==2 ) {
|
||||
setTimeout(() => {
|
||||
this.$go('/pages/pharmacist/index', 3)
|
||||
}, 600)
|
||||
return
|
||||
}
|
||||
|
||||
// 医生 res.data.ServiceUser.status > 0 && res.data .ServiceUser.status != 3
|
||||
if (res.data.ServiceUser.role == 1 && res.data.ServiceUser.status==2 ) {
|
||||
setTimeout(() => {
|
||||
this.$go('/pages/workbench/index', 2)
|
||||
}, 600)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 医生未通过审核
|
||||
if (res.data.ServiceUser.role == 1 && res.data.ServiceUser.status == 3) {
|
||||
// this.$toast(res.data.ServiceUser.reason)
|
||||
setTimeout(() => {
|
||||
this.$go('/pages/workbench/examine')
|
||||
}, 2000)
|
||||
return
|
||||
}
|
||||
|
||||
// 医生审核中
|
||||
if (res.data.ServiceUser.role == 1 && res.data.ServiceUser.status == 1) {
|
||||
this.$toast('您的账号还在审核中')
|
||||
setTimeout(() => {
|
||||
this.$go('/pages/workbench/examine')
|
||||
}, 2000)
|
||||
return
|
||||
}
|
||||
|
||||
// 药师未通过审核
|
||||
if (res.data.ServiceUser.role == 2 && res.data.ServiceUser.status == 3) {
|
||||
// this.$toast(res.data.ServiceUser.reason)
|
||||
setTimeout(() => {
|
||||
this.$go('/pages/workbench/examine')
|
||||
}, 2000)
|
||||
return
|
||||
}
|
||||
|
||||
// 药师审核中
|
||||
if (res.data.ServiceUser.role == 2 && res.data.ServiceUser.status == 1) {
|
||||
this.$toast('您的账号还在审核中')
|
||||
setTimeout(() => {
|
||||
this.$go('/pages/workbench/examine')
|
||||
}, 2000)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (res.errcode == -1) {
|
||||
// this.$toast('您还没有账号,请先注册')
|
||||
// setTimeout(() => {
|
||||
// this.$go('../../subPackages/sub_workbench/workbench_identity')
|
||||
// }, 600)
|
||||
|
||||
this.$toast(res.msg)
|
||||
return
|
||||
}
|
||||
})
|
||||
},
|
||||
checkboxChange(val) {
|
||||
// console.log(val);
|
||||
},
|
||||
codeChange(text) {
|
||||
this.codeText = text;
|
||||
},
|
||||
getCode() {
|
||||
if (this.$refs.uCode.canGetCode) {
|
||||
// 模拟向后端请求验证码
|
||||
uni.showLoading({
|
||||
title: '正在获取验证码'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.hideLoading();
|
||||
// 通知验证码组件内部开始倒计时
|
||||
//发送验证码接口
|
||||
const data = {
|
||||
store_id: '11001',
|
||||
mobile: this.form['mobile']
|
||||
}
|
||||
register(data).then(res => {
|
||||
// console.log(res);
|
||||
if (res.errcode != -1) {
|
||||
// this.code = res.data.code
|
||||
uni.setStorageSync('smsCode', res.data['smsCode'])
|
||||
// if(this.code==res.data.smsCode){
|
||||
// this.$go('../../subPackages/sub_workbench/workbench_upInfo/index')
|
||||
// }else{
|
||||
// this.$u.toast('验证码错误')
|
||||
// return
|
||||
// }
|
||||
}
|
||||
})
|
||||
this.$refs.uCode.start();
|
||||
}, 1000);
|
||||
} else {
|
||||
this.$u.toast('倒计时结束后再发送');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 750rpx;
|
||||
padding-top: 200rpx;
|
||||
text-align: center;
|
||||
font-size: 48rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #0D111A;
|
||||
background: linear-gradient(180deg, #EAF2FF 0%, #FFFFFF 100%);
|
||||
margin-bottom: 60rpx;
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-bottom: 34rpx;
|
||||
|
||||
.agreement {
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
margin-left: 16rpx;
|
||||
|
||||
text {
|
||||
color: #2979FF;
|
||||
size: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
box-sizing: border-box;
|
||||
padding: 0 52rpx;
|
||||
}
|
||||
|
||||
.code {
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #1777FF;
|
||||
background: #F9FAFB;
|
||||
}
|
||||
|
||||
.agreement {
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
.pwd {
|
||||
width: 646rpx;
|
||||
height: 96rpx;
|
||||
background: #F9FAFB;
|
||||
border-radius: 48rpx 48rpx 48rpx 48rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #CCCCCC;
|
||||
margin: 0rpx 0 30rpx;
|
||||
|
||||
::v-deep button {
|
||||
color: #1777FF;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin-top: 80rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
}
|
||||
|
||||
.btn {
|
||||
::v-deep button {
|
||||
width: 648rpx;
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
background: #6ACDBB;
|
||||
border: 0;
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.register {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 15px;
|
||||
|
||||
text {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
word-spacing: 3px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
299
pages/login/register.vue
Normal file
@@ -0,0 +1,299 @@
|
||||
<template>
|
||||
<view class="container safe-area-inset-bottom">
|
||||
|
||||
<view class="title">
|
||||
欢迎注册
|
||||
</view>
|
||||
|
||||
<view class="box">
|
||||
<view class="info">
|
||||
<view class="pwd">
|
||||
<d-input :maxlength="11" height="96" v-model="form['mobile']"
|
||||
:prefixIcon="require('../../static/image/act.png')" borderRadius="96rpx" prefixIconSize="40rpx"
|
||||
placeholder="请输入手机号" @input="is_d=false" :placeholder-style="{fontSize:'32rpx'}"
|
||||
:custom-style="{fontSize:'32rpx',paddingLeft:'60rpx'}" />
|
||||
</view>
|
||||
|
||||
<view class="pwd">
|
||||
<u-field v-model="smsCode" placeholder="请填写验证码" :placeholder-style="{fontSize:'32rpx'}">
|
||||
<u-button size="mini" slot="right" @click="getCode">{{codeText}}</u-button>
|
||||
</u-field>
|
||||
<u-verification-code ref="uCode" @change="codeChange" class="code">
|
||||
</u-verification-code>
|
||||
</view>
|
||||
|
||||
<view class="flex-row" style="margin-top: 88rpx;">
|
||||
<u-icon size="35" :color="form['check']?'#6ACDBB':'#e0fdff'" name="checkmark-circle-fill"
|
||||
@click="form['check']=!form['check']"></u-icon>
|
||||
<view class="agreement">
|
||||
我已阅读并同意
|
||||
<text
|
||||
@click="$go('/subPackages/sub_agreement/agreement?type=service_user_agreement')">《用户服务协议》</text>
|
||||
和
|
||||
<text
|
||||
@click="$go('/subPackages/sub_agreement/agreement?type=service_privacy_agreement')">《隐私权政策》</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- :disabled="!form['mobile']||!form['pwd']" -->
|
||||
<view class="btn">
|
||||
<u-button :throttle-time="20" shape="circle" @click="register" :ripple="true" :loading="loading">
|
||||
注册</u-button>
|
||||
</view>
|
||||
<view class="register" @click="$go('/pages/login/index')">
|
||||
<text>手机号登录</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
login,
|
||||
register,
|
||||
agreement,
|
||||
getUserInfo,
|
||||
loginOrRe
|
||||
} from '../../api/all';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
form: {
|
||||
check: false
|
||||
},
|
||||
switchVal: false,
|
||||
is_d: false,
|
||||
statusBarHeight: this.$statusBarHeight,
|
||||
navbarHeight: this.$navbarHeight,
|
||||
mobile: '',
|
||||
codeText: '',
|
||||
smsCode: '',
|
||||
code: '',
|
||||
role: 1,
|
||||
};
|
||||
},
|
||||
onLoad(e) {
|
||||
// console.log(e, 'role');
|
||||
this.role = e.role
|
||||
|
||||
},
|
||||
mounted() {
|
||||
uni.login({
|
||||
provider: 'weixin',
|
||||
success: (loginRes) => {
|
||||
this.code = loginRes.code
|
||||
// console.log(loginRes);
|
||||
uni.setStorageSync('code', loginRes.code)
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
//登录或者注册接口
|
||||
register() {
|
||||
if (!uni.$u.test.mobile(this.form['mobile'])) {
|
||||
this.$toast('请输入正确的手机号')
|
||||
return
|
||||
}
|
||||
if (!this.smsCode) {
|
||||
this.$toast('请输入验证码')
|
||||
return
|
||||
}
|
||||
if (!this.form['check']) {
|
||||
this.$toast('请勾选协议')
|
||||
return
|
||||
}
|
||||
|
||||
const data = {
|
||||
store_id: '11001',
|
||||
role: this.role,
|
||||
plate_type: 2,
|
||||
mobile: this.form['mobile'],
|
||||
status: 4,
|
||||
smsCode: this.smsCode,
|
||||
code: uni.getStorageSync('code')
|
||||
}
|
||||
|
||||
loginOrRe(data).then(res => {
|
||||
if (res.errcode != -1) {
|
||||
uni.setStorageSync('token', res.data['token'])
|
||||
uni.setStorageSync('logInfo', res.data['user'])
|
||||
|
||||
setTimeout(() => {
|
||||
uni.showToast({
|
||||
title: '开始注册',
|
||||
icon: 'success'
|
||||
})
|
||||
}, 1000)
|
||||
//跳转到激活页面
|
||||
setTimeout(() => {
|
||||
this.$go('../../subPackages/sub_workbench/workbench_succeed')
|
||||
}, 800)
|
||||
|
||||
} else {
|
||||
this.$toast(res.msg)
|
||||
//跳转到激活页面
|
||||
// setTimeout(() => {
|
||||
// this.$go('../../subPackages/sub_workbench/workbench_succeed')
|
||||
// }, 900)
|
||||
|
||||
}
|
||||
// console.log(res);
|
||||
})
|
||||
},
|
||||
checkboxChange(val) {
|
||||
console.log(val);
|
||||
},
|
||||
codeChange(text) {
|
||||
this.codeText = text;
|
||||
},
|
||||
getCode() {
|
||||
if (this.$refs.uCode.canGetCode) {
|
||||
// 模拟向后端请求验证码
|
||||
uni.showLoading({
|
||||
title: '正在获取验证码'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.hideLoading();
|
||||
// 通知验证码组件内部开始倒计时
|
||||
//发送验证码接口
|
||||
const data = {
|
||||
store_id: '11001',
|
||||
mobile: this.form['mobile']
|
||||
}
|
||||
register(data).then(res => {
|
||||
console.log(res);
|
||||
if (res.errcode != -1) {
|
||||
// this.code = res.data.code
|
||||
uni.setStorageSync('smsCode', res.data['smsCode'])
|
||||
// if(this.code==res.data.smsCode){
|
||||
// this.$go('../../subPackages/sub_workbench/workbench_upInfo/index')
|
||||
// }else{
|
||||
// this.$u.toast('验证码错误')
|
||||
// return
|
||||
// }
|
||||
}
|
||||
})
|
||||
this.$refs.uCode.start();
|
||||
}, 1000);
|
||||
} else {
|
||||
this.$u.toast('倒计时结束后再发送');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.title {
|
||||
width: 750rpx;
|
||||
padding-top: 200rpx;
|
||||
text-align: center;
|
||||
font-size: 48rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #0D111A;
|
||||
background: linear-gradient(180deg, #EAF2FF 0%, #FFFFFF 100%);
|
||||
margin-bottom: 60rpx;
|
||||
}
|
||||
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin-bottom: 34rpx;
|
||||
|
||||
.agreement {
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
margin-left: 16rpx;
|
||||
|
||||
text {
|
||||
color: #2979FF;
|
||||
size: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
box-sizing: border-box;
|
||||
padding: 0 52rpx;
|
||||
}
|
||||
|
||||
.code {
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #1777FF;
|
||||
background: #F9FAFB;
|
||||
}
|
||||
|
||||
.agreement {
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
|
||||
.pwd {
|
||||
width: 646rpx;
|
||||
height: 96rpx;
|
||||
background: #F9FAFB;
|
||||
border-radius: 48rpx 48rpx 48rpx 48rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #CCCCCC;
|
||||
margin: 0rpx 0 30rpx;
|
||||
|
||||
::v-deep button {
|
||||
color: #1777FF;
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.hint {
|
||||
margin-top: 80rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
}
|
||||
|
||||
.btn {
|
||||
::v-deep button {
|
||||
width: 648rpx;
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
background: #6ACDBB;
|
||||
border: 0;
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
.register {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 15px;
|
||||
|
||||
text {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
word-spacing: 3px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
226
pages/my/index.vue
Normal file
@@ -0,0 +1,226 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<u-navbar title="我的" :is-back="false" title-size="34" :title-color="parseInt(identity)>1?'#EAF2FF':'#000'"
|
||||
:border-bottom="false"></u-navbar>
|
||||
<view v-if="parseInt(identity)==1">
|
||||
<view class="info flex-row flex-jus-sp flex-ali-center">
|
||||
<view class="flex-row flex-a">
|
||||
<image class="avatar" :src="doctorInfo.DoctorInfo.avatar">
|
||||
</image>
|
||||
<view class="flex-col flex-jus-se m-l-32">
|
||||
<view class="flex-row flex-ali-center">
|
||||
<d-text :text="doctorInfo.DoctorInfo.name || '微信用户'"
|
||||
className="m-r-16 main-c fs-36"></d-text>
|
||||
<u-tag text="审核中" type="warning" size="mini" shape="circle" border-color="#6A77CD"
|
||||
bgColor="#6A77CD" color="#fff" v-if="doctorInfo.DoctorInfo.user.status==1" />
|
||||
<u-tag text="已认证" type="warning" size="mini" shape="circle" border-color="#6A77CD"
|
||||
bgColor="#6A77CD" color="#fff" v-if="doctorInfo.DoctorInfo.user.status==2" />
|
||||
<u-tag v-if="doctorInfo.DoctorInfo.user.status==3" text="审核未通过" type="warning" size="mini"
|
||||
border-color="#A7ABB0" bgColor="#A7ABB0" color="#fff" />
|
||||
</view>
|
||||
<view class="flex-row" @click="$go('../../subPackages/sub_my/my_setAct')">
|
||||
<d-text text="个人主页" color="#6C7380"></d-text>
|
||||
<u-icon name="arrow-right" size="24" color="#A7ABB0"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="button" @click="$go('../../subPackages/sub_pharmacist/pharmacist_info')">
|
||||
编辑资料
|
||||
</view>
|
||||
</view>
|
||||
<view class="p-row-2">
|
||||
<!-- <view class="p-32 white b-r-16">
|
||||
<view class="flex-row" @click="$go('../../subPackages/sub_my/my_revenue/index')">
|
||||
<d-text text="我的收入" className="main-c fs-32 m-r-16"></d-text>
|
||||
<u-icon :name="eye?'eye':'eye-off'" color="#000" @click="eye=!eye" size="32"></u-icon>
|
||||
</view>
|
||||
<view class="flex-row m-t-32">
|
||||
<view class="flex-1 flex-col">
|
||||
<d-text className="tips-c fs-24" text="累计收入(元)"></d-text>
|
||||
<d-text className="content-c fs-4" text="0.00" :bold="true"></d-text>
|
||||
</view>
|
||||
<view class="flex-1 flex-col m-l-24">
|
||||
<d-text className="tips-c fs-24" text="本月预估收入(元)"></d-text>
|
||||
<d-text className="content-c fs-4" text="0.00" :bold="true"></d-text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="grid-tem-col-3 m-t-2 white p-col-32">
|
||||
<view class="flex-col flex-jus-sp flex-ali-center" v-for="(item,i) in functions"
|
||||
@click="$go(item.url)" :key="i">
|
||||
<image class="fun" :src="item.icon"></image>
|
||||
<d-text color="#31353D" :text="item.name"></d-text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-col m-t-2 white p-row-32">
|
||||
<view class="flex-row bottom-border flex-jus-sp p-col-32 flex-ali-center" v-for="(item,i) in items"
|
||||
:key="i" @click="$go(item.url)">
|
||||
<view class="flex-row flex-ali-center">
|
||||
<image class="item" :src="item.icon" mode="aspectFit"></image>
|
||||
<d-text :text="item.name" className="content-c m-l-16"></d-text>
|
||||
</view>
|
||||
<u-icon name="arrow-right" color="#bcbcbc"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<my-pharmacist v-if="parseInt(identity)==2" :info="userInfo" :avatar="getAvatar"></my-pharmacist>
|
||||
<my-service v-if="parseInt(identity)>2" :info="userInfo" :avatar="getAvatar"></my-service>
|
||||
<d-tabbar></d-tabbar>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
info,
|
||||
personalData,
|
||||
leadInfo,
|
||||
servInfo
|
||||
} from "@/api/all.js"
|
||||
import myPharmacist from './my-pharmacist.vue'
|
||||
import myService from './my-service.vue'
|
||||
export default {
|
||||
components: {
|
||||
myService,
|
||||
myPharmacist
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
userInfo: uni.getStorageSync('userInfo') || {},
|
||||
functions: [{
|
||||
// name: '我的评价 我的常用方',
|
||||
// icon: '../../static/image/wdpj.png',
|
||||
// url: '../../subPackages/sub_workbench/workbench_evaluation'
|
||||
// }, {
|
||||
name: '我的处方',
|
||||
icon: '../../static/image/wd-cf.png',
|
||||
url: '/pages/my/prescriptionList'
|
||||
},
|
||||
{
|
||||
name: '我的常用方',
|
||||
icon: '../../static/image/wd-cyf.png',
|
||||
url: '../../subPackages/sub_workbench/workbench_recipe/common?type=0'
|
||||
},
|
||||
// {
|
||||
// name: '挂号费用',
|
||||
// icon: '../../static/image/wd-ghfy.png',
|
||||
// url: '../../subPackages/sub_my/my_revenue/index'
|
||||
// },
|
||||
{
|
||||
name: '服务设置',
|
||||
icon: '../../static/image/fwsz.png',
|
||||
url: '../../subPackages/sub_my/my_service'
|
||||
}
|
||||
],
|
||||
items: [
|
||||
// {
|
||||
// name: '常用语管理',
|
||||
// icon: '../../static/image/wj.png',
|
||||
// url: '../../subPackages/sub_my/my_commonReply/index'
|
||||
// }, {
|
||||
// name: '账号设置我的评价',
|
||||
// icon: '../../static/image/set.png',
|
||||
// url: '../../subPackages/sub_pharmacist/pharmacist_setInfo'
|
||||
// },
|
||||
// {
|
||||
// name: '我的评价',
|
||||
// icon: '../../static/image/wj.png',
|
||||
// url: '../../subPackages/sub_workbench/workbench_evaluation'
|
||||
// },
|
||||
{
|
||||
name: '常用医嘱管理',
|
||||
icon: '../../static/image/i1.png',
|
||||
url: '../../subPackages/sub_my/my_diagnose_common'
|
||||
}
|
||||
],
|
||||
eye: false,
|
||||
identity: uni.getStorageSync('identity') || (uni.getStorageSync('userInfo') || {}).role || 1,
|
||||
userInfo: uni.getStorageSync('userInfo') || {},
|
||||
is_req: false,
|
||||
doctorInfo: []
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
// getAvatar() {
|
||||
// let doctorInfo = uni.getStorageSync('doctorInfo')
|
||||
// let url = require(`@/static/image/${doctorInfo.DoctorInfo.user.role%2==0?'nv':'nan'}.png`);
|
||||
// // console.log(info, 'ddd')
|
||||
// return doctorInfo.DoctorInfo['avatar'] ? doctorInfo.DoctorInfo['avatar'] : doctorInfo
|
||||
// .DoctorInfo.user.role == 1 ? url : url
|
||||
// }
|
||||
},
|
||||
created() {
|
||||
this.getInfo()
|
||||
},
|
||||
onHide() {
|
||||
|
||||
},
|
||||
onShow() {
|
||||
this.getInfo()
|
||||
},
|
||||
methods: {
|
||||
async getInfo() {
|
||||
let res = {}
|
||||
this.identity == 1 && (res = await info({
|
||||
store_id: uni.getStorageSync('store_id') || '11001'
|
||||
}));
|
||||
if (res.errcode == 0) {
|
||||
this.doctorInfo = res.data
|
||||
uni.setStorageSync('userInfo', res.data.DoctorInfo)
|
||||
} else {
|
||||
this.$toast(res.msg);
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getInfo()
|
||||
},
|
||||
onShow() {
|
||||
this.getInfo()
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #F9FAFB;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.info {
|
||||
background: linear-gradient(180deg, #EAF2FF 0%, rgba(238, 245, 255, 0) 100%);
|
||||
padding: 32rpx 20rpx;
|
||||
|
||||
.button {
|
||||
width: 128rpx;
|
||||
height: 50rpx;
|
||||
border-radius: 198rpx;
|
||||
border: 1rpx solid #6ACDBB;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6ACDBB;
|
||||
text-align: center;
|
||||
line-height: 50rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.fun {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
margin-bottom: 10rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.item {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 128rpx;
|
||||
height: 128rpx;
|
||||
background: #D9D9D9;
|
||||
border: 4rpx solid #FFFFFF;
|
||||
border-radius: 128rpx;
|
||||
}
|
||||
</style>
|
||||
76
pages/my/my-pharmacist.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<view class="p-2">
|
||||
<view class="p-32 white">
|
||||
<view class="flex-row">
|
||||
<u-image width="96rpx" height="96rpx" shape="circle" :src="avatar">
|
||||
<u-loading slot="loading"></u-loading>
|
||||
</u-image>
|
||||
<view class="flex-col flex-jus-sp m-l-32">
|
||||
<d-text :text="info.name" :bold="true"></d-text>
|
||||
<d-text :text="info.idcard.replace(/\d{4}$/, '****')" >
|
||||
</d-text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="organization m-t-32">
|
||||
<d-text text="执业机构" color="#31353D" :bold="true"></d-text>
|
||||
<d-text className="content-c m-t08" :text="`${info.idcard.replace(/^\d{2}/, '**')} (${info.yardes[0].name})`">
|
||||
</d-text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="p-32 white m-t-12" @click="$go('../../subPackages/sub_pharmacist/pharmacist_info?avatar='+avatar+'&info='+JSON.stringify(info))">
|
||||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||||
<u-icon margin-left="20" label-size="32" label-color="#31353D"
|
||||
:name="require('../../static/image/grzl.png')" label="个人资料" size="30"></u-icon>
|
||||
<u-icon name="arrow-right" size="32" color="#A7ABB0"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="p-32 white m-t-2" @click="$go('../../subPackages/sub_pharmacist/pharmacist_setInfo')">
|
||||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||||
<u-icon margin-left="20" label-size="32" label-color="#31353D"
|
||||
:name="require('../../static/image/set.png')" label="设置" size="30"></u-icon>
|
||||
<u-icon name="arrow-right" size="32" color="#A7ABB0"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props:{
|
||||
avatar:{
|
||||
type:String,
|
||||
default:''
|
||||
},
|
||||
info:{
|
||||
type:Object,
|
||||
default:()=>{
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #F9FAFB;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.organization {
|
||||
background-color: #F9FAFB;
|
||||
padding: 16rpx;
|
||||
}
|
||||
</style>
|
||||
85
pages/my/my-service.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<view class="p-2">
|
||||
<view class="p-32 white">
|
||||
<view class="flex-row">
|
||||
<u-image width="128rpx" height="128rpx" shape="circle" :src="avatar">
|
||||
<u-loading slot="loading"></u-loading>
|
||||
</u-image>
|
||||
<view class="flex-col flex-jus-sp m-l-32">
|
||||
<d-text :text="info.name||''" className="fs-36" :bold="true"></d-text>
|
||||
<d-text :text="identity==3?'导医':'客服'" :bold="true"></d-text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="p-row-32 b-r-8 white m-t-2">
|
||||
<view class="p-col-32" @click="$go('../../subPackages/sub_my/my_commonReply/index')">
|
||||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||||
<u-icon margin-left="20" label-size="32" label-color="#31353D" name="chat" label="快捷回复" size="40"
|
||||
color="#6C7380"></u-icon>
|
||||
<u-icon name="arrow-right" size="32" color="#A7ABB0"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="p-row-32 b-r-8 white m-t-2">
|
||||
<view class="p-col-32 flex-jus-sp flex-row flex-ali-center bottom-border" @click="$go()">
|
||||
<u-icon margin-left="20" label-size="32" label-color="#31353D" name="kefu-ermai" label="联系客服" size="40"
|
||||
color="#6C7380"></u-icon>
|
||||
<view class="flex-row flex-ali-center">
|
||||
<view class="m-r-16 flex-row flex-jus-center flex-ali-center badge">
|
||||
<u-badge type="error" count="7" :absolute="false"></u-badge>
|
||||
</view>
|
||||
<u-icon name="arrow-right" size="32" color="#A7ABB0"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
<view class="p-col-32" @click="$go('../../subPackages/sub_pharmacist/pharmacist_setInfo')">
|
||||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||||
<u-icon margin-left="20" label-size="32" label-color="#31353D" name="setting" label="设置" size="40"
|
||||
color="#6C7380"></u-icon>
|
||||
<u-icon name="arrow-right" size="32" color="#A7ABB0"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
avatar: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
info: {
|
||||
type: Object,
|
||||
default: () => {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
identity: (uni.getStorageSync('userInfo') || {}).role || 3,
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
options: {
|
||||
styleIsolation: 'shared'
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #F9FAFB;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
::v-deep .u-badge {
|
||||
display: flex !important;
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
777
pages/my/prescriptionDetail.vue
Normal file
@@ -0,0 +1,777 @@
|
||||
<template>
|
||||
<view class="container safe-area-inset-bottom">
|
||||
<!-- 处方 -->
|
||||
<view class="head">
|
||||
<view class="head_record_top">
|
||||
<view class="record">
|
||||
处方编号:{{infoList.prescription_no}}
|
||||
</view>
|
||||
<view class="record_state">
|
||||
{{lists.type==1 ? '普通':'常用'}}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 医院 -->
|
||||
<view class="head_record">
|
||||
<image :src="lists.store.offical_seal||'/static/group/xkyard.png'" mode=""></image>
|
||||
<view class="record_yard">
|
||||
<view class="yard">
|
||||
{{lists.store.name}}
|
||||
</view>
|
||||
<view class="state">
|
||||
处方笺
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 时间 -->
|
||||
<view class="head_record_time">
|
||||
<text style="text-align: right;">开具日期:{{infoList.created_at}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 信息 -->
|
||||
<view class="my_info">
|
||||
<view class="info">
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
姓名:
|
||||
<text>{{infoList.patient.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
性别:
|
||||
<text>{{infoList.patient.sex%2==0?'女':'男'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
年龄:
|
||||
<text>{{infoList.patient.age}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
类别:
|
||||
<text>{{infoList.category}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info">
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
科室:
|
||||
<text>{{infoList.doctor.depart.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
电话:
|
||||
<text>{{infoList.patient.mobile}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info">
|
||||
<view class="info_item">
|
||||
<view class="names">
|
||||
诊断:
|
||||
<text>{{infoList.clinical_diagnose}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bg">
|
||||
<!-- 药品 -->
|
||||
<view class="my_medical">
|
||||
<view class="title">
|
||||
Rp
|
||||
</view>
|
||||
|
||||
<block v-if="lists.prescription_type==1||lists.prescription_type==3">
|
||||
<view class="items" v-for="(item,index) in infoList.repice" :key="item.id">
|
||||
<!-- v-for="(it,index) in item.content" :key="it.id" -->
|
||||
<view class="name">
|
||||
<view class="_name" v-for="(it,index) in item.content" :key="it.id">
|
||||
<view class="text">
|
||||
<text>{{ it.name}}</text>
|
||||
<text class="_abbr" v-if="it.order">[{{useWay[it.order]}}]</text>
|
||||
</view>
|
||||
<text class="name_num">{{ it.number}}{{it.unit?it.unit.name:'g'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="details">
|
||||
<view class="text">
|
||||
<text>用法:煎服,每天 {{item.consumption}} 次 ,</text>
|
||||
<!-- <text v-if="item.deployment==2">{{' 每次 '+item.volume+' ml '}} , </text> -->
|
||||
<text> 共 {{item.dosage}} 剂 </text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
|
||||
<block v-if="lists.prescription_type==2">
|
||||
<view class="item" v-for="(it,index) in infoList.repice" :key="item.id">
|
||||
<!-- v-for="(it,index) in item.content" :key="it.id" -->
|
||||
<view class="name" style="justify-content: space-between;">
|
||||
<view class="yp_name">
|
||||
<text>{{ it.content.drug_name}} </text>
|
||||
<text style="font-size: 24rpx;margin-left: 10rpx;">{{ it.content.specification }}</text>
|
||||
</view>
|
||||
<text>x{{ it.number}}</text>
|
||||
</view>
|
||||
<view class="details">
|
||||
<text>用法:{{ it.instruction }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- 医嘱 -->
|
||||
<view class="doctor_order">
|
||||
<view class="yz">
|
||||
<text class="order_info_left">医嘱:</text>
|
||||
<view class="order_info">
|
||||
<view class="info" v-for="(item ,index) in lists.doctor_order" :key="index">
|
||||
{{item}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="titles">
|
||||
处方开具已完毕
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<!-- 医生 -->
|
||||
<view class="my_doctor">
|
||||
<view class="doctor_info">
|
||||
<view class="info">
|
||||
<text>医师</text>
|
||||
<!-- <text class="name">{{infoList.doctor.name || ''}}</text> -->
|
||||
<image :src="'data:image/jpeg;base64,'+lists.doctor_sign_image" mode="aspectFit"></image>
|
||||
<image v-if="lists.doctor_second_sign == 1" :src="'data:image/jpeg;base64,'+lists.doctor_sign_image" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="info">
|
||||
<text>审核药师</text>
|
||||
<!-- <text class="name">{{rpList.name || ' '}}</text> -->
|
||||
<image :src="'data:image/jpeg;base64,'+lists.Pharmacist_sign_image" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="info">
|
||||
<text>发药人</text>
|
||||
<image :src="'data:image/jpeg;base64,'+lists.Pharmacist_sign_image" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="info">
|
||||
<text>核对人</text>
|
||||
<image :src="'data:image/jpeg;base64,'+lists.Pharmacist_sign_image" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="info">
|
||||
<text>调配人</text>
|
||||
<image :src="'data:image/jpeg;base64,'+lists.Pharmacist_sign_image" mode="aspectFit"></image>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="price">
|
||||
价格 ¥{{infoList.total_pay_price}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 温馨提示 -->
|
||||
<view class="my_prompt">
|
||||
<view class="title">
|
||||
温馨提示:请遵医嘱服药!处方{{lists.valid_hours}}小时有效!
|
||||
</view>
|
||||
<image src="/static/group/img-yzf.png" mode="" v-if="status==2"></image>
|
||||
</view>
|
||||
<view v-if="notice_id" class="rotation" @click.stop="rotation">转 方</view>
|
||||
<!-- 状态 -->
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
rotationApi,
|
||||
prescripDetail,
|
||||
getUseWay
|
||||
} from "@/api/all.js";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
statusName: {
|
||||
0: '待审核',
|
||||
1: '已通过',
|
||||
2: '未通过',
|
||||
3: '待使用',
|
||||
4: '已使用',
|
||||
5: '未使用',
|
||||
6: '已失效',
|
||||
7: '已初审'
|
||||
},
|
||||
// status:flase,
|
||||
status: true,
|
||||
// status: "", // 处方状态
|
||||
status: "", // 处方状态
|
||||
id: "",
|
||||
infoList: [],
|
||||
num: 1,
|
||||
rpList: [],
|
||||
order_id: "",
|
||||
lists: [],
|
||||
useWay: [],
|
||||
notice_id: ''
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
// console.log('12')
|
||||
// console.log(e, "id");
|
||||
this.id = e.id
|
||||
this.notice_id = e.notice_id
|
||||
this.getInfo()
|
||||
getUseWay({
|
||||
store_id: uni.getStorageSync('store_id') || 11001,
|
||||
}).then((res) => {
|
||||
if (res.errcode == 0) {
|
||||
const useWay = ["无", ...(res.data.map(it => it.name))]
|
||||
uni.setStorageSync('useWay', JSON.stringify(useWay))
|
||||
this.useWay = useWay
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
async rotation() {
|
||||
rotationApi({
|
||||
notice_id: this.notice_id,
|
||||
store_id: uni.getStorageSync('store_id') || '11001'
|
||||
}).then(res => {
|
||||
uni.showToast({
|
||||
title: '转方成功',
|
||||
icon: 'success',
|
||||
mask: true
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}, 1500)
|
||||
})
|
||||
},
|
||||
// 数量
|
||||
getnum(obj) {
|
||||
let list = obj
|
||||
let num = 0
|
||||
list.map((it) => {
|
||||
num += it.number
|
||||
})
|
||||
return num
|
||||
},
|
||||
getInfo() {
|
||||
prescripDetail({
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
prescription_id: this.id
|
||||
}).then((res) => {
|
||||
// console.log(res, 'deta');
|
||||
if (res.errcode == 0) {
|
||||
this.infoList = res.data.content
|
||||
this.rpList = res.data.pharmacistInfo
|
||||
this.lists = res.data
|
||||
this.status = res.data.status
|
||||
|
||||
// console.log(this.rpList, 'info');
|
||||
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
// getDrug(obj) {
|
||||
// console.log(obj, 'obj')
|
||||
// if (!obj) {
|
||||
// return
|
||||
// }
|
||||
// let list = (obj.chinese.length > 0 ? obj.chinese : obj.west) || []
|
||||
// let drugs = []
|
||||
// // console.log(list);
|
||||
// for (let i = 0; i < list.length; i++) {
|
||||
// if (obj.chinese.length > 0) {
|
||||
// for (let j = 0; j < JSON.parse(list[i].content).length; j++) {
|
||||
// drugs.push(JSON.parse(list[i].content)[j]['name'])
|
||||
// }
|
||||
// } else {
|
||||
// drugs.push(JSON.parse(list[i].content)['name'])
|
||||
// }
|
||||
// }
|
||||
// return drugs.join()
|
||||
// },
|
||||
},
|
||||
mounted() {
|
||||
// this.getInfo()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
width: 750rpx;
|
||||
min-height: 100vh;
|
||||
max-height: 100%;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.bg {
|
||||
min-height: calc(100vh - 600rpx);
|
||||
}
|
||||
|
||||
.head {
|
||||
.head_record_top {
|
||||
width: 710rpx;
|
||||
margin: 14rpx auto 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.record {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
}
|
||||
|
||||
.record_state {
|
||||
width: 80rpx;
|
||||
height: 42rpx;
|
||||
line-height: 42rpx;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #A7ABB0;
|
||||
border: 1rpx solid #C4C7CC;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.head_record_time {
|
||||
text-align: right;
|
||||
width: 750rpx;
|
||||
padding: 0 32rpx;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
}
|
||||
|
||||
.head_record {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
image {
|
||||
width: 160rpx;
|
||||
height: 150rpx;
|
||||
position: absolute;
|
||||
left: 40%;
|
||||
top: -8rpx;
|
||||
}
|
||||
|
||||
.record_yard {
|
||||
text-align: center;
|
||||
|
||||
.yard {
|
||||
font-size: 46rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
}
|
||||
|
||||
.state {
|
||||
height: 44rpx;
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.head_record_time {
|
||||
text-align: right;
|
||||
margin-top: 20rpx;
|
||||
width: 750rpx;
|
||||
padding-right: 32rpx;
|
||||
height: 34rpx;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
line-height: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 信息
|
||||
.my_info {
|
||||
width: 710rpx;
|
||||
margin: 4rpx auto;
|
||||
border-top: 1rpx solid #31353D;
|
||||
border-bottom: 1rpx solid #31353D;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
padding: 4rpx 4rpx;
|
||||
|
||||
.info {
|
||||
width: 710rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.info_item {
|
||||
|
||||
.names {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
|
||||
text {
|
||||
flex: 1;
|
||||
display: block;
|
||||
height: 40rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
line-height: 40rpx;
|
||||
margin: 0 0rpx 0 8rpx;
|
||||
// flex-wrap: nowrap;
|
||||
// display: -webkit-box;
|
||||
// -webkit-line-clamp: 1;
|
||||
// -webkit-box-orient: vertical;
|
||||
// text-overflow: ellipsis;
|
||||
// overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
|
||||
text {
|
||||
flex: 1;
|
||||
display: block;
|
||||
height: 40rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
line-height: 40rpx;
|
||||
margin: 0 26rpx 0 6rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 药品
|
||||
.my_medical {
|
||||
width: 710rpx;
|
||||
margin: 4rpx auto;
|
||||
padding: 1rpx 10rpx;
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Semibold, PingFang SC;
|
||||
font-weight: 600;
|
||||
color: #31353D;
|
||||
margin-bottom: 2rpx;
|
||||
}
|
||||
|
||||
.item {
|
||||
width: 710rpx;
|
||||
padding: 1rpx 0;
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
display: flex;
|
||||
// justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
._name {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 2rpx 80rpx 2rpx 0;
|
||||
|
||||
.text {
|
||||
margin-right: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
._abbr {
|
||||
color: #A7ABB0;
|
||||
font-size: 20rpx;
|
||||
margin-top: 2rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
|
||||
.text {
|
||||
|
||||
text {
|
||||
word-spacing: 1rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.items {
|
||||
width: 710rpx;
|
||||
padding: 1rpx 0;
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
display: flex;
|
||||
// justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
._name {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 2rpx 80rpx 2rpx 0;
|
||||
|
||||
.text {
|
||||
margin-right: 26rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
._abbr {
|
||||
color: #A7ABB0;
|
||||
font-size: 20rpx;
|
||||
margin-top: 2rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
|
||||
.text {
|
||||
|
||||
text {
|
||||
word-spacing: 1rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 医嘱
|
||||
.doctor_order {
|
||||
width: 710rpx;
|
||||
margin: 2rpx auto;
|
||||
padding: 0 10rpx;
|
||||
word-spacing: 2rpx;
|
||||
|
||||
.yz {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
color: #6C7380;
|
||||
|
||||
.order_info_left {
|
||||
margin-right: 3rpx;
|
||||
}
|
||||
|
||||
.order_info {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
line-height: 40rpx;
|
||||
margin-bottom: 2rpx;
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.titles {
|
||||
width: 710rpx;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #A7ABB0;
|
||||
margin: 8rpx 0 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 医生
|
||||
.my_doctor {
|
||||
width: 710rpx;
|
||||
margin: 2rpx auto;
|
||||
border-top: 1rpx solid #31353D;
|
||||
border-bottom: 1rpx solid #31353D;
|
||||
padding: 2rpx 4rpx;
|
||||
|
||||
.doctor_info {
|
||||
width: 710rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 4rpx;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.info {
|
||||
min-width: 222rpx;
|
||||
max-width: 400rpx;
|
||||
margin: 5rpx 0 8rpx;
|
||||
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 82rpx;
|
||||
height: 62rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 106rpx;
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
line-height: 38rpx;
|
||||
border-bottom: 2rpx solid #000000;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.price {
|
||||
width: 710rpx;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
}
|
||||
}
|
||||
|
||||
// 温馨提示
|
||||
.my_prompt {
|
||||
width: 710rpx;
|
||||
height: 304rpx;
|
||||
margin: 0 auto;
|
||||
padding: 0 4rpx;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
width: 710rpx;
|
||||
height: 40rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #A7ABB0;
|
||||
line-height: 40rpx;
|
||||
margin: 32rpx 0;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 159rpx;
|
||||
height: 100rpx;
|
||||
position: absolute;
|
||||
left: 60%;
|
||||
top: 0%;
|
||||
}
|
||||
|
||||
.prompt {
|
||||
width: 710rpx;
|
||||
height: 200rpx;
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #A7ABB0;
|
||||
}
|
||||
|
||||
ol {
|
||||
padding: 0 0 0 32rpx;
|
||||
|
||||
li {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #A7ABB0;
|
||||
margin: 4rpx 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 状态
|
||||
.my_state {
|
||||
width: 710rpx;
|
||||
height: 40rpx;
|
||||
margin: 12rpx auto;
|
||||
padding-bottom: 110rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #F44336;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.line {
|
||||
border-bottom: 2rpx solid #31353D;
|
||||
}
|
||||
}
|
||||
.rotation {
|
||||
position: fixed;
|
||||
bottom: 30rpx;
|
||||
right: 24rpx;
|
||||
left: 24rpx;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
font-size: 30rpx;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #5792f9;
|
||||
color: #fff;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
</style>
|
||||
192
pages/my/prescriptionList.vue
Normal file
@@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<view class="box safe-area-inset-bottom">
|
||||
<!-- tabs -->
|
||||
<view class="tabs">
|
||||
<u-tabs bar-width="30" :height="59" :list="tabs" :current="current" :is-scroll="false" @change="change"
|
||||
active-color="#6ACDBB"></u-tabs>
|
||||
</view>
|
||||
<!-- -->
|
||||
<view class="p-row-2 m-t-2">
|
||||
<block v-if="!loading && list.length > 0">
|
||||
<view class="p-32 b-r-8 white m-b-2" v-for="(item, i) in list" :key="item.id"
|
||||
@click="$go('/pages/my/prescriptionDetail?id=' +item.id)">
|
||||
<view class="flex-row flex-ali-center flex-jus-sp m-t-2">
|
||||
<u-icon margin-left="8" label-size="32" label-color="#6C7380"
|
||||
:name="require('../../static/image/ys.png')" :label="item.prescription_no"
|
||||
color="#6ACDBB" size="32"></u-icon>
|
||||
<d-text :text="statusName[item.status]"></d-text>
|
||||
</view>
|
||||
<view class="flex-row flex-ali-center flex-jus-sp m-t-2">
|
||||
<d-text className="content-c fs-32" :text="getInfo(item.patient)"></d-text>
|
||||
</view>
|
||||
<view class="flex-row flex-ali-center flex-jus-sp m-t-2">
|
||||
<d-text :text="$u.timeFormat(item.created_at, 'yyyy-mm-dd')"></d-text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<view class="flex-row flex-jus-center" v-if="!loading && list.length == 0">
|
||||
<d-empty text="暂无信息" mode="search"></d-empty>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<d-loading-page :loading="loading"></d-loading-page>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
prescripDetailList
|
||||
} from "@/api/all.js";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
page: 1,
|
||||
loading: true,
|
||||
loading2: true,
|
||||
status: "loading",
|
||||
totalPage: 1,
|
||||
loadText: {
|
||||
loadmore: "轻轻上拉",
|
||||
loading: "努力加载中",
|
||||
nomore: "已加载全部",
|
||||
},
|
||||
statusName: [
|
||||
"待审核",
|
||||
"已通过",
|
||||
"未通过",
|
||||
"待使用",
|
||||
"已使用",
|
||||
"未使用",
|
||||
"已失效",
|
||||
],
|
||||
tabs: [{
|
||||
name: "全部"
|
||||
},
|
||||
{
|
||||
name: "待审核"
|
||||
},
|
||||
{
|
||||
name: "未通过"
|
||||
},
|
||||
{
|
||||
name: "已通过"
|
||||
},
|
||||
],
|
||||
current: 0,
|
||||
status: ""
|
||||
};
|
||||
},
|
||||
|
||||
created() {},
|
||||
onShow() {
|
||||
this.getList();
|
||||
},
|
||||
onHide() {},
|
||||
onReachBottom() {
|
||||
if (this.loading2) {
|
||||
return;
|
||||
}
|
||||
if (this.page >= this.totalPage) {
|
||||
this.$toast("数据已全部加载");
|
||||
return;
|
||||
}
|
||||
|
||||
this.page++;
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
getInfo(user) {
|
||||
return `${user.name} ${user.sex == 1 ? "男" : "女"} ${user.age}岁`;
|
||||
},
|
||||
|
||||
change(index) {
|
||||
// console.log(index);
|
||||
this.current = index;
|
||||
if (this.current == 0) {
|
||||
this.status = ''
|
||||
}
|
||||
if (this.current == 1) {
|
||||
this.status = 0
|
||||
}
|
||||
if (this.current == 2) {
|
||||
this.status = 2
|
||||
}
|
||||
if (this.current == 3) {
|
||||
this.status = 1
|
||||
}
|
||||
this.getList()
|
||||
},
|
||||
|
||||
async getList() {
|
||||
try {
|
||||
this.loading2 = true;
|
||||
const res = await prescripDetailList({
|
||||
page: this.page,
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
status: this.status
|
||||
});
|
||||
|
||||
if (res.errcode === 0) {
|
||||
this.list =
|
||||
this.page === 1 ? res.data.list : [...this.list, ...res.data.list];
|
||||
this.totalPage = res.data.pagination.totalPage;
|
||||
} else {
|
||||
this.$toast(res.msg);
|
||||
}
|
||||
this.loading = false;
|
||||
this.loading2 = false;
|
||||
} catch (error) {
|
||||
this.loading = false;
|
||||
this.loading2 = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.tabs{
|
||||
background-color: #fff;
|
||||
width: 750rpx;
|
||||
position: sticky;
|
||||
top: 0rpx;
|
||||
z-index: 9999999;
|
||||
padding-top: 12rpx;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: relative;
|
||||
z-index: 982;
|
||||
|
||||
image {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .box {
|
||||
.u-tab-item {
|
||||
line-height: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.state {
|
||||
margin-top: 160rpx;
|
||||
|
||||
image {
|
||||
width: 300rpx;
|
||||
height: 223rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
padding: 16rpx 32rpx;
|
||||
}
|
||||
</style>
|
||||
237
pages/patient/index.vue
Normal file
@@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<u-navbar height="66" title="患者中心" :is-back="false" title-size="34" title-color="#fff"
|
||||
:background="{background:'linear-gradient(90deg, #6ACDBB 0%, #6ACDBB 93%)'}">
|
||||
</u-navbar>
|
||||
<view class="bg" :style="{top:`${statusBarHeight+navbarHeight-1}px`}"></view>
|
||||
<view class="search p-row-32">
|
||||
<u-search placeholder="请输入患者姓名" @input="handleSearch" v-model="keyword" :show-action="false"></u-search>
|
||||
</view>
|
||||
<view class="box p-row-2 m-t-2">
|
||||
<view class="flex-row flex-jus-sp">
|
||||
<view class="function white b-r-8 flex-row p-32 flex-1"
|
||||
@click="$go('../../subPackages/sub_patient/to-store?id='+1)">
|
||||
<image src="../../static/image/hz_xsjz.png"></image>
|
||||
<view class="m-l-16 l-19">
|
||||
<d-text text="到店接诊" size="32" color="#31353D"></d-text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="function white b-r-8 flex-row p-32 flex-1 m-l-2"
|
||||
@click="$go('../../subPackages/sub_patient/to-store?id='+2)">
|
||||
<image src="../../static/image/hz_ddjz.png"></image>
|
||||
<view class="m-l-16 l-19">
|
||||
<d-text text="线上接诊" size="32" color="#31353D"></d-text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="list-new" @click="$go('../../subPackages/sub_patient/patient_massInfo')">
|
||||
<view class="l-l-row">
|
||||
<image src="/static/image/hz-qfxx.png" mode=""></image>
|
||||
<d-text text="群发消息" className="main-c m-r-16 fs-32"></d-text>
|
||||
</view>
|
||||
<u-icon name="arrow-right" color="#333333"></u-icon>
|
||||
</view>
|
||||
<view class="flex-col b-r-8 white p-32 m-t-2">
|
||||
<view class="title flex-row flex-jus-sp">
|
||||
<d-text text="患者管理" className="main-c m-r-16 fs-32"></d-text>
|
||||
<!-- <u-icon label="筛选" size="40" label-size="28" margin-right="10" label-color="#6C7380" :name="require('@/static/image/sx.png')">
|
||||
</u-icon> -->
|
||||
<!-- <u-icon v-if="!isSearch" @click="isSearch = true" name="search" size="40rpx" color="#333"></u-icon> -->
|
||||
<!-- <view v-else class="flex-row flex-con flex-jus-sp flex-ali-center">
|
||||
<d-input @input="handleSearch" class="flex-con m-r08" v-model="keyword"
|
||||
:custom-style="{fontSize:'28rpx'}" placeholder="请输入搜索内容" />
|
||||
<u-icon @click="isSearch = false" name="close-circle-fill" size="40rpx" color="#999"></u-icon>
|
||||
</view> -->
|
||||
</view>
|
||||
<view v-for="(item, index) in list" :key="index" class="flex-row flex-ali-center m-t-50"
|
||||
@click="toDetail(item.id)">
|
||||
<u-image width="80rpx" height="80rpx" shape="circle"
|
||||
:src="item.avatar || require(`../../static/image/${item.sex%2==0?'nv':'nan'}.png`)">
|
||||
<u-loading slot="loading"></u-loading>
|
||||
</u-image>
|
||||
<view class="flex-col m-l-2 flex-jus-sp">
|
||||
<view class="flex-row flex-ali-end">
|
||||
<d-text :text="item.patient" className="content-c fs-32"></d-text>
|
||||
<d-text :text="item.age + '岁'" className="fs-28 tips-c m-l-2"></d-text>
|
||||
</view>
|
||||
<!-- <view class="flex-row flex-ali-center">
|
||||
<view class="m-r08">
|
||||
<u-tag text="高血糖" size="mini" border-color="rgba(41,121,255,0.08)"
|
||||
bg-color="rgba(41,121,255,0.08)" color="#6ACDBB" />
|
||||
</view>
|
||||
<view class="m-r08">
|
||||
<u-tag text="高血压" size="mini" border-color="rgba(41,121,255,0.08)"
|
||||
bg-color="rgba(41,121,255,0.08)" color="#6ACDBB" />
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<d-tabbar></d-tabbar>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getPatientListApi
|
||||
} from "@/api/all.js";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
male: this.$male,
|
||||
girl: this.$girl,
|
||||
keyword: '',
|
||||
navbarHeight: this.$navbarHeight,
|
||||
statusBarHeight: this.$statusBarHeight,
|
||||
list: [],
|
||||
page: 1,
|
||||
loading: true,
|
||||
loading2: false,
|
||||
status: "loading",
|
||||
loadText: {
|
||||
loadmore: "轻轻上拉",
|
||||
loading: "努力加载中",
|
||||
nomore: "已加载全部",
|
||||
},
|
||||
totalPage: 1,
|
||||
};
|
||||
},
|
||||
onShow() {
|
||||
this.init();
|
||||
},
|
||||
onPullDownRefresh() {
|
||||
this.init();
|
||||
},
|
||||
onReachBottom() {
|
||||
if (this.page >= this.totalPage) {
|
||||
this.$toast("数据已全部加载");
|
||||
return;
|
||||
}
|
||||
this.page++;
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
this.list = [];
|
||||
this.page = 1;
|
||||
this.keyword = '';
|
||||
this.loading = true;
|
||||
this.getList(true);
|
||||
},
|
||||
handleSearch() {
|
||||
this.page = 1
|
||||
this.getList()
|
||||
},
|
||||
getList(is_stop = false) {
|
||||
if (this.loading2) {
|
||||
return;
|
||||
}
|
||||
this.loading2 = true;
|
||||
getPatientListApi({
|
||||
page: this.page,
|
||||
name: this.keyword,
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
status: 1
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.errcode == 0) {
|
||||
this.list = this.page === 1 ? res.data.list : [...this.list, ...res.data.list];
|
||||
this.totalPage = res.data.pagination.totalPage;
|
||||
if (this.page >= this.totalPage) {
|
||||
this.status = "nomore";
|
||||
} else {
|
||||
this.status = "loadmore";
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.loading = false;
|
||||
is_stop && uni.stopPullDownRefresh();
|
||||
});
|
||||
} else {
|
||||
this.$toast(res.msg);
|
||||
is_stop && uni.stopPullDownRefresh();
|
||||
this.loading = false;
|
||||
if (this.page >= this.totalPage) {
|
||||
this.status = "nomore";
|
||||
} else {
|
||||
this.status = "loadmore";
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading2 = false;
|
||||
});
|
||||
},
|
||||
toDetail(id) {
|
||||
uni.navigateTo({
|
||||
url: '/subPackages/sub_patient/patient_detail?id=' + id
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
page {
|
||||
background-color: #eeeeef;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.bg {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
width: 750rpx;
|
||||
height: 204rpx;
|
||||
background: linear-gradient(90deg, #6ACDBB 0%, #6ACDBB 93%);
|
||||
z-index: 981;
|
||||
}
|
||||
|
||||
.search {
|
||||
position: relative;
|
||||
z-index: 982;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: relative;
|
||||
z-index: 982;
|
||||
}
|
||||
|
||||
.function {
|
||||
image {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.l-19 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.list-new {
|
||||
width: 710rpx;
|
||||
height: 108rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 20rpx 0;
|
||||
padding: 0 32rpx;
|
||||
color: #333333;
|
||||
|
||||
.l-l-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
image {
|
||||
width: 56rpx;
|
||||
height: 56rpx;
|
||||
margin-right: 12rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
332
pages/pharmacist/index.vue
Normal file
@@ -0,0 +1,332 @@
|
||||
<template>
|
||||
<view class="safe-area-inset-bottom">
|
||||
<u-navbar title="审方" :is-back="false" title-size="34" title-color="#fff" :background="{
|
||||
background:'linear-gradient(90deg, #00BFA6 0%, #6ACDBB 93%)'}">
|
||||
</u-navbar>
|
||||
|
||||
<!-- 头部 tabs -->
|
||||
<view class="head">
|
||||
<u-tabs :list="lists" :is-scroll="false" :current="currents" @change="change" active-color="#6ACDBB"
|
||||
:height="99">
|
||||
</u-tabs>
|
||||
</view>
|
||||
|
||||
<!-- 空页 -->
|
||||
<view class="empty" v-if="listInfo.length==0 ||status!=2">
|
||||
<image src="/static/image/none.png" mode="aspectFit"></image>
|
||||
<text v-if="status!=2">您还没有通过审核,请稍后再试~</text>
|
||||
</view>
|
||||
|
||||
<!-- 列表 -->
|
||||
<block v-if="status==2">
|
||||
<!-- 西药 -->
|
||||
<!-- <view class="lists" v-for="(item,index) in listWest" :key="item.id"
|
||||
@click="toDetail(item.id,item.prescription_no)">
|
||||
<view class="info">
|
||||
<view class="bh">
|
||||
<image src="/static/image/tubiao1.png" mode=""></image>
|
||||
{{item.prescription_no}}
|
||||
</view>
|
||||
<view class="name">
|
||||
{{item.patients.name}} {{(item.patients.sex)%2==0?'女':'男'}} {{item.patients.age}}
|
||||
</view>
|
||||
<view class="time">
|
||||
{{item.created_at | dateFormat}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="states" :class="item.status==1?'tg':'wtg'">
|
||||
<view class="tag_states">
|
||||
<u-tag text="西药" type="primary" />
|
||||
</view>
|
||||
{{item.status==0&&'待审核' || item.status==1&&'已通过' || item.status==2&&'未通过'}}
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 中药 -->
|
||||
<!-- <view class="lists" v-for="(item,index) in listChinese" :key="item.id"
|
||||
@click="toDetail(item.id,item.prescription_no)">
|
||||
<view class="info">
|
||||
<view class="bh">
|
||||
<image src="/static/image/tubiao1.png" mode=""></image>
|
||||
{{item.prescription_no}}
|
||||
</view>
|
||||
<view class="name">
|
||||
{{item.patients.name}} {{(item.patients.sex)%2==0?'女':'男'}} {{item.patients.age}}
|
||||
</view>
|
||||
<view class="time">
|
||||
{{item.created_at | dateFormat}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="states" :class="item.status==1?'tg':'wtg'">
|
||||
<view class="tag_states">
|
||||
<u-tag text="中药" type="success" />
|
||||
</view>
|
||||
{{item.status==0&&'待审核' || item.status==1&&'已通过' || item.status==2&&'未通过'}}
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- 颗粒 -->
|
||||
<view class="lists" v-for="(item,index) in listInfo" :key="item.id"
|
||||
@click="toDetail(item.id,item.prescription_no)">
|
||||
<view class="info">
|
||||
<view class="bh">
|
||||
<image src="/static/image/tubiao1.png" mode=""></image>
|
||||
{{item.prescription_no}}
|
||||
</view>
|
||||
<view class="name">
|
||||
{{item.patients.name}} {{(item.patients.sex)%2==0?'女':'男'}} {{item.patients.age}}
|
||||
</view>
|
||||
<view class="time">
|
||||
{{item.created_at | dateFormat}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="states" :class="item.status==1?'tg':'wtg'">
|
||||
<view class="tag_states">
|
||||
<u-tag text="颗粒" type="warning" v-if="item.prescription_type==3" />
|
||||
<u-tag text="中药" type="success" v-if="item.prescription_type==1" />
|
||||
<u-tag text="西药" type="primary" v-if="item.prescription_type==2" />
|
||||
</view>
|
||||
{{item.status==0&&'待审核' || item.status==1&&'已通过' || item.status==2&&'未通过'}}
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
<d-loading-page :loading="loading"></d-loading-page>
|
||||
|
||||
<u-tabbar v-model="current" :list="listed" active-color="#6ACDBB" @change="changed"></u-tabbar>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getUserInfo,
|
||||
prescripRecord
|
||||
} from "@/api/all.js";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
status: uni.getStorageSync('login_status'),
|
||||
keyword: "",
|
||||
show: false,
|
||||
identity: uni.getStorageSync("identity") || 2,
|
||||
index: 0,
|
||||
loading: true,
|
||||
userInfo: uni.getStorageSync("userInfo") || {},
|
||||
listInfo: [], // 中药
|
||||
// listWest: [], // 西药
|
||||
// listGranular: [], // 颗粒
|
||||
waitList: [],
|
||||
// is_req: false,
|
||||
listed: '',
|
||||
current: 0,
|
||||
lists: [{
|
||||
name: '待审核'
|
||||
},
|
||||
{
|
||||
name: '已通过',
|
||||
},
|
||||
{
|
||||
name: '未通过',
|
||||
}
|
||||
],
|
||||
currents: 0, // 审核状态
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
onLoad() {
|
||||
this.listed = [{
|
||||
iconPath: require("../../static/image/w-sf.png"),
|
||||
selectedIconPath: require("../../static/image/sf.png"),
|
||||
text: '审方',
|
||||
// pagePath: '/pages/pharmacist/index',
|
||||
current: 0
|
||||
},
|
||||
{
|
||||
iconPath: require("../../static/image/w-wd.png"),
|
||||
selectedIconPath: require("../../static/image/wd.png"),
|
||||
text: '我的',
|
||||
// pagePath: '/pages/pharmacist/pharmacist-my',
|
||||
}
|
||||
]
|
||||
},
|
||||
onHide() {
|
||||
// this.is_req = true;
|
||||
},
|
||||
onShow() {
|
||||
this.current = 0
|
||||
this.getList()
|
||||
if (this.status != 2) {
|
||||
this.getKnow()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
change(index) {
|
||||
this.currents = index;
|
||||
this.getList()
|
||||
},
|
||||
changed(index) {
|
||||
this.current = index;
|
||||
|
||||
if (this.current == 1) {
|
||||
this.$go('/pages/pharmacist/pharmacist-my')
|
||||
}
|
||||
},
|
||||
async getList() {
|
||||
let res = {};
|
||||
res = await prescripRecord({
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
status: this.currents
|
||||
})
|
||||
|
||||
// this.listChinese = [], this.listWest = [], this.listGranular = [];
|
||||
if (res.errcode == 0) {
|
||||
// console.log(res, 'lb');
|
||||
|
||||
this.listInfo = res.data.prescription
|
||||
// this.listWest = (res.data.west).reverse();
|
||||
// this.listGranular = (res.data.granular).reverse()
|
||||
this.$nextTick(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
} else {
|
||||
this.$toast(res.msg);
|
||||
this.loading = false;
|
||||
this.listInfo = []
|
||||
}
|
||||
},
|
||||
|
||||
// 详情
|
||||
toDetail(id, no) {
|
||||
uni.navigateTo({
|
||||
url: '../../subPackages/sub_pharmacist/myrecord-detail?id=' + id + '&prescription_no=' + no
|
||||
})
|
||||
},
|
||||
|
||||
getKnow() {
|
||||
const data = {
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
}
|
||||
getUserInfo(data).then(res => {
|
||||
if (res.errcode != -1) {
|
||||
uni.setStorageSync('loginInfo', res.data)
|
||||
uni.setStorageSync('role', res.data.role)
|
||||
uni.setStorageSync('login_id', res.data['id'])
|
||||
uni.setStorageSync('login_status', res.data['status'])
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.status != 2) {
|
||||
this.$go('/pages/workbench/examine')
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
//过滤器 用于格式化时间
|
||||
dateFormat: function(value) {
|
||||
var date = new Date(value * 1000); //时间戳为10位需*1000,时间戳为13位的话不需乘1000
|
||||
var year = date.getFullYear();
|
||||
var month = ("0" + (date.getMonth() + 1)).slice(-2);
|
||||
var sdate = ("0" + date.getDate()).slice(-2);
|
||||
var hour = ("0" + date.getHours()).slice(-2);
|
||||
var minute = ("0" + date.getMinutes()).slice(-2);
|
||||
var second = ("0" + date.getSeconds()).slice(-2);
|
||||
// 拼接
|
||||
var result = year + '-' + month + '-' + sdate + ' ' + hour + ":" + minute //+ ":" + second;
|
||||
// 返回
|
||||
return result;
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.u-tabbar {
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.head {
|
||||
background-color: #fff;
|
||||
width: 750rpx;
|
||||
height: 99rpx;
|
||||
position: sticky;
|
||||
top: 180rpx;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.empty {
|
||||
width: 440rpx;
|
||||
height: 393rpx;
|
||||
margin: 200rpx auto;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
.lists {
|
||||
width: 750rpx;
|
||||
padding: 24rpx 36rpx;
|
||||
background: #FFFFFF;
|
||||
margin: 30rpx auto 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
|
||||
.info {
|
||||
.bh {
|
||||
font-weight: 400;
|
||||
color: #666666;
|
||||
|
||||
image {
|
||||
width: 38rpx;
|
||||
height: 38rpx;
|
||||
vertical-align: middle;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
margin: 18rpx 0;
|
||||
}
|
||||
|
||||
.time {
|
||||
width: 100%;
|
||||
font-weight: 400;
|
||||
color: #999999;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.states {
|
||||
font-weight: 400;
|
||||
color: #6A6DCD;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.tag_states {
|
||||
margin-bottom: 44rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.wtg {
|
||||
color: #FF477E;
|
||||
}
|
||||
|
||||
.tg {
|
||||
color: #6ACDBB;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
207
pages/pharmacist/pharmacist-my.vue
Normal file
@@ -0,0 +1,207 @@
|
||||
<template>
|
||||
<view class="safe-area-inset-bottom">
|
||||
<u-navbar title="我的" :is-back="false" title-size="34" title-color="#fff" :background="{
|
||||
background:'linear-gradient(90deg, #00BFA6 0%, #6ACDBB 93%)'}">
|
||||
</u-navbar>
|
||||
|
||||
<view class="head">
|
||||
<view class="info">
|
||||
<image :src="list.avatar || '/static/image/nv.png'" mode=""></image>
|
||||
<view class="name">
|
||||
<text>{{list.name}}</text>
|
||||
<text>药师</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="store">
|
||||
职业机构
|
||||
</view>
|
||||
<view class="store">
|
||||
{{list.store.name || ' '}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<view class="card">
|
||||
<view class="setup" @click="toInfo">
|
||||
个人资料
|
||||
<u-icon name="arrow-right" color="#A7ABB0"></u-icon>
|
||||
</view>
|
||||
<view class="setup" @click="toSetup">
|
||||
设置
|
||||
<u-icon name="arrow-right" color="#A7ABB0"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<u-tabbar v-model="current" :list="listed" active-color="#6ACDBB" @change="changed"></u-tabbar>
|
||||
<d-loading-page :loading="loading"></d-loading-page>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
my
|
||||
} from "@/api/all.js";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
keyword: "",
|
||||
show: false,
|
||||
identity: uni.getStorageSync("identity") || 2,
|
||||
index: 0,
|
||||
navbarHeight: this.$navbarHeight,
|
||||
statusBarHeight: this.$statusBarHeight,
|
||||
loading: true,
|
||||
userInfo: uni.getStorageSync("userInfo") || {},
|
||||
list: [],
|
||||
waitList: [],
|
||||
is_req: false,
|
||||
current: 1,
|
||||
listed: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
|
||||
},
|
||||
created() {
|
||||
|
||||
},
|
||||
onShow() {
|
||||
|
||||
},
|
||||
onLoad() {
|
||||
this.listed = [{
|
||||
iconPath: require("../../static/image/w-sf.png"),
|
||||
selectedIconPath: require("../../static/image/sf.png"),
|
||||
text: '审方',
|
||||
// pagePath: '/pages/pharmacist/index',
|
||||
current: 0
|
||||
},
|
||||
{
|
||||
iconPath: require("../../static/image/w-wd.png"),
|
||||
selectedIconPath: require("../../static/image/wd.png"),
|
||||
text: '我的',
|
||||
// pagePath: '/pages/pharmacist/pharmacist-my',
|
||||
current: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
methods: {
|
||||
changed(index) {
|
||||
this.current = index;
|
||||
// console.log(this.current);
|
||||
|
||||
if (this.current == 0) {
|
||||
uni.switchTab({
|
||||
url: '/pages/pharmacist/index',
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
async getList() {
|
||||
let res = {};
|
||||
res = await my({
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
})
|
||||
this.list = [];
|
||||
if (res.errcode == 0) {
|
||||
// console.log(res, 'wd');
|
||||
this.list = res.data;
|
||||
this.$nextTick(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
} else {
|
||||
this.$toast(res.msg);
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
toInfo() {
|
||||
this.$go('../../subPackages/sub_pharmacist/pharmacist_info')
|
||||
},
|
||||
|
||||
toSetup() {
|
||||
this.$go('../../subPackages/sub_pharmacist/pharmacist_setInfo')
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getList()
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.bg {
|
||||
position: fixed;
|
||||
width: 750rpx;
|
||||
height: 400rpx;
|
||||
// background: linear-gradient(
|
||||
// 180deg,
|
||||
// #00BFA6 0%,
|
||||
// #6ACDBB 0%,
|
||||
// rgba(41, 121, 255, 0) 100%
|
||||
// );
|
||||
z-index: 981;
|
||||
}
|
||||
|
||||
.head {
|
||||
font-family: PingFang SC-Bold, PingFang SC;
|
||||
font-weight: bold;
|
||||
color: #232323;
|
||||
width: 710rpx;
|
||||
height: 304rpx;
|
||||
background: #FFFFFF;
|
||||
margin: 0 auto;
|
||||
padding: 18rpx 20rpx;
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
image {
|
||||
border-radius: 50%;
|
||||
width: 116rpx;
|
||||
height: 116rpx;
|
||||
}
|
||||
|
||||
.name {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
text {
|
||||
margin: 10rpx 20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.store {
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 710rpx;
|
||||
height: 176rpx;
|
||||
background: #FFFFFF;
|
||||
margin: 30rpx auto;
|
||||
font-family: PingFang SC-Bold, PingFang SC;
|
||||
font-weight: bold;
|
||||
color: #232323;
|
||||
|
||||
.setup {
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
267
pages/workbench/examine.vue
Normal file
@@ -0,0 +1,267 @@
|
||||
<template>
|
||||
<view class="container safe-area-inset-bottom" :style="{ height: screenHeight }">
|
||||
<image class="image" src="/static/login/bg_shh.png" mode=""></image>
|
||||
<view class="bg">
|
||||
<view class="img">
|
||||
<image :src="doctorInfo.DoctorInfo.avatar || doctorInfo.avatar" mode=""></image>
|
||||
</view>
|
||||
|
||||
<view class="box">
|
||||
<view class="name">
|
||||
<text>{{doctorInfo.DoctorInfo.name || doctorInfo.name}}</text>{{doctorInfo.DoctorInfo.title.name || doctorInfo.titles.name}}
|
||||
</view>
|
||||
<view class="store">
|
||||
{{doctorInfo.store.store.name || doctorInfo.store.name}}
|
||||
{{doctorInfo.DoctorInfo.depart.name || doctorInfo.depart.name || ''}}
|
||||
</view>
|
||||
<image src="/static/login/bg_shhz.png" mode=""></image>
|
||||
<!-- doctorInfo.DoctorInfo.user.status<=1 -->
|
||||
<view class="state" v-if="role==1">
|
||||
{{ doctorInfo.DoctorInfo.user.status<=1&&'您的申请已提交,请耐心等待!感谢您的配合!' ||doctorInfo.DoctorInfo.user.status==3&&'抱歉您的申请已被驳回!'}}
|
||||
</view>
|
||||
<view class="state" v-if="role==2">
|
||||
{{ doctorInfo.user.status<=1&&'您的申请已提交,请耐心等待!感谢您的配合!' ||doctorInfo.user.status==3&&'抱歉您的申请已被驳回!'}}
|
||||
</view>
|
||||
<view class="store" v-if="role==1">
|
||||
<text v-if="doctorInfo.DoctorInfo.user.status<=1">申请提交后预计1~2个工作日返回结果!</text>
|
||||
<view class="_bx" v-if="doctorInfo.DoctorInfo.user.status==3">
|
||||
<text style="color: #FF0000;">驳回原因:</text>
|
||||
<text>{{doctorInfo.ServiceUser.reason}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="store" v-if="role==2">
|
||||
<text v-if="doctorInfo.user.status<=1">申请提交后预计1~2个工作日返回结果!</text>
|
||||
<view class="_bx" v-if="doctorInfo.user.status==3">
|
||||
<text style="color: #FF0000;">驳回原因:</text>
|
||||
<text>{{doctorInfo.user.reason}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<button class="btn" v-if="doctorInfo.DoctorInfo.user.status==3 && role==1"
|
||||
@click="toNew(doctorInfo.DoctorInfo.su_id)">重新申请</button>
|
||||
|
||||
<button class="btn" v-if="doctorInfo.user.status==3 && role==2" @click="toNew(doctorInfo.su_id)">重新申请</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
failNew,
|
||||
getUserInfo,
|
||||
info,
|
||||
personalData
|
||||
} from '@/api/all.js'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
doctorInfo: [],
|
||||
screenHeight: 0,
|
||||
role: uni.getStorageSync('role'),
|
||||
// status: 1,
|
||||
reason: "",
|
||||
};
|
||||
},
|
||||
onLoad() {
|
||||
// this.$go('../../subPackages/sub_workbench/workbench_recipe/index')
|
||||
// console.log(1);
|
||||
this.screenHeight = uni.getSystemInfoSync().windowHeight
|
||||
},
|
||||
onShow() {
|
||||
if (this.role == 1) {
|
||||
this.getInfo()
|
||||
}
|
||||
|
||||
if (this.role == 2) {
|
||||
this.getPerInfo()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 医生详情
|
||||
getInfo() {
|
||||
info({
|
||||
store_id: uni.getStorageSync('store_id') || '11001'
|
||||
}).then((res) => {
|
||||
if (res.errcode == 0) {
|
||||
this.doctorInfo = res.data
|
||||
if (res.data.user.status == 2) {
|
||||
setTimeout(() => {
|
||||
this.$go('/pages/workbench/index', 2)
|
||||
}, 20000)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
// 药师详情
|
||||
getPerInfo() {
|
||||
personalData({
|
||||
store_id: uni.getStorageSync('store_id') || '11001'
|
||||
}).then((res) => {
|
||||
if (res.errcode == 0) {
|
||||
this.doctorInfo = res.data
|
||||
if (res.data.user.status == 2) {
|
||||
setTimeout(() => {
|
||||
this.$go('/pages/pharmacist/index', 2)
|
||||
}, 20000)
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
// // 状态
|
||||
// getStatus() {
|
||||
// getUserInfo({
|
||||
// store_id: uni.getStorageSync('store_id') || '11001',
|
||||
// }).then((res) => {
|
||||
// if (res.errcode ==0) {
|
||||
// uni.setStorageSync('loginInfo', res.data)
|
||||
// this.status=res.data.status
|
||||
// this.reason = res.data.reason
|
||||
// }
|
||||
// })
|
||||
// },
|
||||
toNew(e) {
|
||||
failNew({
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
id: e
|
||||
}).then((res) => {
|
||||
if (res.errcode == 0) {
|
||||
this.$toast('申请成功,请重新注册')
|
||||
setTimeout(() => {
|
||||
uni.navigateTo({
|
||||
url:'../../subPackages/sub_workbench/workbench_upInfo/index'
|
||||
})
|
||||
}, 100)
|
||||
}
|
||||
})
|
||||
},
|
||||
getNewinfo() {
|
||||
if (this.role == 1 && uni.getStorageSync('login_status') != 2) {
|
||||
setTimeout(() => {
|
||||
this.getInfo()
|
||||
}, 100000)
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this.getPerInfo()
|
||||
}, 100000)
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getNewinfo()
|
||||
// this.getStatus()
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #eeeeef;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
width: 100vw;
|
||||
min-height: 100vh;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
position: relative;
|
||||
|
||||
.image {
|
||||
width: 100vw;
|
||||
min-height: 100vh;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.bg {
|
||||
z-index: 9999999999 !important;
|
||||
position: absolute;
|
||||
left: 13%;
|
||||
top: 120rpx;
|
||||
text-align: center;
|
||||
border-radius: 36rpx;
|
||||
background: #F8FAFF;
|
||||
|
||||
.img {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
margin: -80rpx auto 20rpx;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
z-index: 9999999;
|
||||
width: 560rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
color: #1E293B;
|
||||
padding: 20rpx 28rpx;
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 400;
|
||||
|
||||
text {
|
||||
font-size: 36rpx;
|
||||
margin-right: 10rpx;
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
margin: 8rpx 0;
|
||||
}
|
||||
|
||||
.store {
|
||||
font-size: 24rpx;
|
||||
font-weight: 400;
|
||||
color: #666666;
|
||||
line-height: 48rpx;
|
||||
margin: 5rpx auto;
|
||||
|
||||
._bx {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.state {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
line-height: 48rpx;
|
||||
margin: 0 auto 50rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 215rpx;
|
||||
height: 241rpx;
|
||||
vertical-align: middle;
|
||||
margin: 68rpx 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.btn {
|
||||
width: 380rpx;
|
||||
height: 84rpx;
|
||||
background: #FFFFFF;
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #333333;
|
||||
border: 0;
|
||||
border-radius: 64rpx;
|
||||
text-align: center;
|
||||
line-height: 80rpx;
|
||||
position: absolute;
|
||||
left: 40%;
|
||||
margin-left: -130rpx;
|
||||
bottom: 13%;
|
||||
}
|
||||
</style>
|
||||
750
pages/workbench/index.vue
Normal file
@@ -0,0 +1,750 @@
|
||||
<template>
|
||||
<view>
|
||||
<view class="bg" :style="{height:`calc(${navbarHeight}px + ${navbarHeight}px + 394rpx)`}">
|
||||
</view>
|
||||
<view class="navbar" :style="{ height: statusBarHeight+navbarHeight + 'px' }">
|
||||
<view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
|
||||
<view class="text-align-cen" :style="{ height:navbarHeight + 'px' ,lineHeight: navbarHeight + 'px'}">
|
||||
工作台
|
||||
</view>
|
||||
</view>
|
||||
<view class="box" :style="{marginTop: statusBarHeight+navbarHeight + 'px'}">
|
||||
<view class="store_" @click="openShow=true">
|
||||
{{doctorInfo.store.store.name || '默认门店'}}
|
||||
<u-icon name="map-fill" color="#fff" size="28" margin-left="12"></u-icon>
|
||||
</view>
|
||||
<view class="box_info">
|
||||
<view class="box_info_left">
|
||||
<image :src="doctorInfo.DoctorInfo.avatar" style="width: 116rpx;height:116rpx ;border-radius: 50%;"
|
||||
mode="aspectFill">
|
||||
</image>
|
||||
<view class="flex-col flex-jus-sp" style="height: 106rpx;margin-left: 32rpx;">
|
||||
<view class="flex-row flex-ali-center">
|
||||
<text class="box_info_left_name">{{doctorInfo.DoctorInfo.name}}</text>
|
||||
<text class="m-r-16">{{doctorInfo.DoctorInfo.title['name']}}</text>
|
||||
<u-tag text="审核中" type="warning" size="mini" shape="circle" border-color="#FB8C00"
|
||||
bgColor="#FB8C00" color="#fff" v-if="doctorInfo.DoctorInfo.user.status<=1" />
|
||||
<u-tag text="已认证" type="warning" size="mini" shape="circle" border-color="#FB8C00"
|
||||
bgColor="#FB8C00" color="#fff" v-if="doctorInfo.DoctorInfo.user.status==2" />
|
||||
<u-tag v-if="doctorInfo.DoctorInfo.user.status==3" text="审核未通过" type="warning" size="mini"
|
||||
border-color="#A7ABB0" bgColor="#A7ABB0" color="#fff" />
|
||||
</view>
|
||||
<text>
|
||||
{{`${doctorInfo.store.store.name}(${doctorInfo.DoctorInfo.depart['name']})`}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box_info_right flex-col flex-jus-sp flex-ali-center"
|
||||
@click="$go('../../subPackages/sub_workbench/workbench_code')">
|
||||
<image src="../../static/image/mp.png"></image>
|
||||
<d-text text="我的名片" className="w-c fs-2"></d-text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="box_data flex-row flex-jus-sp flex-ali-center">
|
||||
<view class="flex-col flex-jus-sp flex-ali-center">
|
||||
<text class="box_data_nub">{{doctorInfo.wait_accept || '0'}}</text>
|
||||
<label>待接诊</label>
|
||||
</view>
|
||||
<view class="flex-col flex-jus-sp flex-ali-center">
|
||||
<text class="box_data_nub">{{doctorInfo.accepting || '0'}}</text>
|
||||
<label>已接诊</label>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="content">
|
||||
<view class="function p-32">
|
||||
<view class="function_grid">
|
||||
<view class="function_item flex-col flex-ali-center flex-jus-sp"
|
||||
@click="doctorInfo.DoctorInfo.user.status==3?$go('../../subPackages/sub_workbench/workbench_upInfo/index'):$go(item.url)"
|
||||
v-for="(item,i) in functions" :key="i">
|
||||
<image :src="item.icon"></image>
|
||||
<view>{{item.name}}</view>
|
||||
<u-badge :count="i===0?doctorInfo.wait_accept:0" v-if="i===0" :offset="[-6,98]"
|
||||
bgColor="#F44336"></u-badge>
|
||||
</view>
|
||||
<view class="function_item flex-col flex-ali-center flex-jus-sp" @click="toNext">
|
||||
<image src="/static/image/xsfz.png"></image>
|
||||
<view>复诊开药</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<block>
|
||||
<view class="news b-r-8">
|
||||
<view class="news_title flex-row">
|
||||
<view class="m-t-32">消息通知</view>
|
||||
</view>
|
||||
<!-- height:calc(100vh - 282rpx) -->
|
||||
<scroll-view scroll-y="true" style="padding: 20rpx 0rpx;" @scrolltolower="scrolltolower"
|
||||
@refresherrefresh="page=1;status = 'loading';loading = true;infoList=[];$store.dispatch('getDocSession')"
|
||||
:refresher-triggered="loading" :refresher-enabled="true" v-if="!loading">
|
||||
|
||||
<!-- <view class="news_item flex-row flex-jus-sp flex-ali-center" v-for="(item) in infoList"
|
||||
:key="item.id"
|
||||
@click="$go(`../../subPackages/sub_workbench/workbench_infoPatient?id=`+item.user_patient_id)">
|
||||
<view style="width: 80rpx;position: relative;">
|
||||
<u-image width="80rpx" height="80rpx" shape="circle"
|
||||
:src="item.avatar||require(`../../static/image/${item.sex%2==0?'nv':'nan'}.png`)">
|
||||
<u-loading slot="loading"></u-loading>
|
||||
</u-image>
|
||||
<u-badge :count="item.message.no_read" v-if="item.message.no_read>0" :offset="[0,0]"
|
||||
bgColor="#F44336" :overflow-count="9999"></u-badge>
|
||||
</view>
|
||||
<view class="news_item_info flex-col flex-jus-sp">
|
||||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||||
<view class="flex-row flex-ali-center">
|
||||
<d-text :text="item.patient" className="content-c fs-32 m-r-16"></d-text>
|
||||
</view>
|
||||
<d-text :text="item.created_at" size="24"></d-text>
|
||||
</view>
|
||||
<view class="flex-row flex-jus-sp">
|
||||
<view class="news_item_info_msg text-hide">
|
||||
<text
|
||||
style="font-size: 24rpx;margin-right: 20rpx;">{{item.sex %2 != 0 ? '男' : '女'}}</text>
|
||||
<text style="font-size: 22rpx;">{{item.age + '岁'}}</text>
|
||||
</view>
|
||||
<d-text :text="states[item.status].name" :color="states[item.status].color"
|
||||
size="24"></d-text>
|
||||
</view>
|
||||
</view>
|
||||
</view> -->
|
||||
<!-- 系统消息 评论我的 患者消息 -->
|
||||
<view class="news_item flex-row flex-jus-sp flex-ali-center"
|
||||
@click="$go('../../subPackages/sub_patient/patient_label?type=1')" v-if="systemList.num>0">
|
||||
<view style="width: 80rpx;position: relative;">
|
||||
<u-image width="80rpx" height="80rpx" shape="circle" src="/static/image/home1.png">
|
||||
<u-loading slot="loading"></u-loading>
|
||||
</u-image>
|
||||
<u-badge :count="systemList.num" v-if="systemList.num>0" :offset="[0,0]"
|
||||
bgColor="#F44336" :overflow-count="9999"></u-badge>
|
||||
</view>
|
||||
<view class="news_item_info flex-col flex-jus-sp">
|
||||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||||
<view class="flex-row flex-ali-center">
|
||||
<d-text text="系统消息" className="content-c fs-32 m-r-16"></d-text>
|
||||
</view>
|
||||
<d-text :text="systemList.time" size="24"></d-text>
|
||||
</view>
|
||||
<view class="flex-row flex-jus-sp">
|
||||
<view class="news_item_info_msg text-hide">
|
||||
<text style="font-size: 24rpx;margin-right: 20rpx;"
|
||||
v-if="systemList.num>0">你有{{systemList.num}}条未读消息</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="news_item flex-row flex-jus-sp flex-ali-center"
|
||||
@click="$go('../../subPackages/sub_patient/patient_label?type=2')" v-if="infoList.num>0">
|
||||
<view style="width: 80rpx;position: relative;">
|
||||
<u-image width="80rpx" height="80rpx" shape="circle" :src="'/static/image/home2.png'">
|
||||
<u-loading slot="loading"></u-loading>
|
||||
</u-image>
|
||||
<u-badge :count="infoList.num" v-if="infoList.num>0" :offset="[0,0]" bgColor="#F44336"
|
||||
:overflow-count="9999"></u-badge>
|
||||
</view>
|
||||
<view class="news_item_info flex-col flex-jus-sp">
|
||||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||||
<view class="flex-row flex-ali-center">
|
||||
<d-text text="患者消息" className="content-c fs-32 m-r-16"></d-text>
|
||||
</view>
|
||||
<d-text :text="infoList.time" size="24"></d-text>
|
||||
</view>
|
||||
<view class="flex-row flex-jus-sp">
|
||||
<view class="news_item_info_msg text-hide">
|
||||
<text style="font-size: 24rpx;margin-right: 20rpx;"
|
||||
v-if="infoList.num>0">你有{{infoList.num}}名患者待接诊</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <u-loadmore :status="status" :load-text="loadText"
|
||||
v-if="loading&&infoList.length!=0||!loading" /> -->
|
||||
|
||||
<view class="news_item flex-row flex-jus-sp flex-ali-center"
|
||||
v-if="!loading&&systemList.length==0"
|
||||
@click="$go('../../subPackages/sub_patient/patient_label?type=1')">
|
||||
<view style="width: 80rpx;position: relative;">
|
||||
<u-image width="80rpx" height="80rpx" shape="circle" src="/static/image/home1.png">
|
||||
<u-loading slot="loading"></u-loading>
|
||||
</u-image>
|
||||
</view>
|
||||
<view class="news_item_info flex-col flex-jus-sp">
|
||||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||||
<view class="flex-row flex-ali-center">
|
||||
<d-text text="系统消息" size="34" color="#000"></d-text>
|
||||
</view>
|
||||
<d-text :text="systemList.time" size="24"></d-text>
|
||||
</view>
|
||||
<view class="flex-row flex-jus-sp">
|
||||
<view class="news_item_info_msg text-hide">
|
||||
<text style="font-size: 28rpx;margin-right: 20rpx;">点击查看历史消息</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 患者 -->
|
||||
<view class="news_item flex-row flex-jus-sp flex-ali-center" v-if="!loading&&infoList.length==0"
|
||||
@click="$go('../../subPackages/sub_patient/patient_label?type=2')">
|
||||
<view style="width: 80rpx;position: relative;">
|
||||
<u-image width="80rpx" height="80rpx" shape="circle" :src="'/static/image/home2.png'">
|
||||
<u-loading slot="loading"></u-loading>
|
||||
</u-image>
|
||||
</view>
|
||||
<view class="news_item_info flex-col flex-jus-sp">
|
||||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||||
<view class="flex-row flex-ali-center">
|
||||
<d-text text="患者消息" size="34" color="#000"></d-text>
|
||||
</view>
|
||||
<d-text :text="infoList.time" size="24"></d-text>
|
||||
</view>
|
||||
<view class="flex-row flex-jus-sp">
|
||||
<view class="news_item_info_msg text-hide">
|
||||
<text style="font-size: 28rpx;margin-right: 20rpx;">点击查看历史消息</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 处方 -->
|
||||
<view v-if="noticeList.length" class="news_item flex-row flex-jus-sp flex-ali-center"
|
||||
@click="$go('./prescriptionList')">
|
||||
<view style="width: 80rpx;position: relative;">
|
||||
<u-image width="80rpx" height="80rpx" shape="circle" src="/static/image/home1.png">
|
||||
<u-loading slot="loading"></u-loading>
|
||||
</u-image>
|
||||
<u-badge :count="noticeList.length" :offset="[0,0]"
|
||||
bgColor="#F44336" :overflow-count="9999"></u-badge>
|
||||
</view>
|
||||
<view class="news_item_info flex-col flex-jus-sp">
|
||||
<view class="flex-row flex-jus-sp flex-ali-center">
|
||||
<view class="flex-row flex-ali-center">
|
||||
<d-text text="待流转处方消息" className="content-c fs-32 m-r-16"></d-text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex-row flex-jus-sp">
|
||||
<view class="news_item_info_msg text-hide">
|
||||
<text style="font-size: 24rpx;margin-right: 20rpx;">你有{{noticeList.length}}条未读消息</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<!-- 暂无信息 -->
|
||||
<!-- <view class="flex-row flex-jus-center" v-if="!loading&&infoList.length==0&&systemList.length==0">
|
||||
<d-empty text="暂无信息" mode="search"></d-empty>
|
||||
</view> -->
|
||||
</view>
|
||||
<view @click="call" class="phone">咨询客服</view>
|
||||
<view class="m-b-32 p-t-32"></view>
|
||||
</block>
|
||||
</view>
|
||||
|
||||
<!-- 切换门店 -->
|
||||
<u-popup v-model="openShow" mode="bottom" border-radius="24" length="65%" :safe-area-inset-bottom="true">
|
||||
<view class="content_popup">
|
||||
<view class="top">
|
||||
<view class="title">选择诊所</view>
|
||||
<view class="search p-row-32">
|
||||
<u-search placeholder="请输入诊所名称" @input="handleSearch" v-model="keyword"
|
||||
:show-action="false"></u-search>
|
||||
</view>
|
||||
</view>
|
||||
<scroll-view scroll-y="true" style="height: 600rpx;">
|
||||
<view>
|
||||
<view class="store_list" v-for="(item,index) in storeList" :key="item.id"
|
||||
@click="changeStore(item.id)">
|
||||
{{item.name}}
|
||||
<u-icon size="35" color="#6ACDBB" name="checkmark-circle-fill"
|
||||
v-if="store_id==item.id"></u-icon>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="confrim-btn">
|
||||
<view class="u-btn qx" @click="openShow=false">取消</view>
|
||||
<view class="u-btn qd" @click="sure">确定</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
|
||||
<d-tabbar></d-tabbar>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
chooseList,
|
||||
hospitalList,
|
||||
info,
|
||||
noticeApi,
|
||||
currentList,
|
||||
homeSession,
|
||||
getNotice
|
||||
} from '@/api/all.js'
|
||||
import {
|
||||
registerList
|
||||
} from '../../api/consult';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
noticeList: [],
|
||||
loading: false,
|
||||
status: 'loading',
|
||||
loadText: {
|
||||
loadmore: '轻轻上拉',
|
||||
loading: '努力加载中',
|
||||
nomore: '实在没有了'
|
||||
},
|
||||
functions: [{
|
||||
name: '到店接诊',
|
||||
icon: '../../static/image/zxzx.png',
|
||||
url: '../../subPackages/sub_workbench/workbench_consult?type=1'
|
||||
}],
|
||||
states: {
|
||||
1: {
|
||||
name: '待接诊',
|
||||
color: '#F44336'
|
||||
},
|
||||
2: {
|
||||
name: '接诊中',
|
||||
color: '#00C853'
|
||||
},
|
||||
3: {
|
||||
name: '已结束',
|
||||
color: '#C4C7CC'
|
||||
},
|
||||
3: {
|
||||
name: '已取消',
|
||||
color: '#C4C7CC'
|
||||
}
|
||||
},
|
||||
state: true,
|
||||
doctorInfo: [],
|
||||
current: 0,
|
||||
navbarHeight: this.$navbarHeight,
|
||||
statusBarHeight: this.$statusBarHeight,
|
||||
list: [],
|
||||
page: 1,
|
||||
totalPage: 1,
|
||||
openShow: false,
|
||||
keyword: "",
|
||||
store: "",
|
||||
storeList: [],
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
infoList: [],
|
||||
systemList: [],
|
||||
see_rate: "",
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
docSession: {
|
||||
deep: true,
|
||||
immediate: false,
|
||||
handler(e) {
|
||||
this.list = e.list;
|
||||
this.totalPage = e.pagination.totalPage;
|
||||
if (this.page >= this.totalPage) {
|
||||
this.status = 'nomore'
|
||||
} else {
|
||||
this.status = 'loadmore'
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
},
|
||||
onLoad() {
|
||||
// this.$go('../../subPackages/sub_workbench/workbench_recipe/index')
|
||||
// console.log(1);
|
||||
},
|
||||
onShow() {
|
||||
this.getNotice()
|
||||
this.getInfo()
|
||||
this.getStore()
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
call () {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: '18157126670',
|
||||
success: (result) => {},
|
||||
fail: (error) => {}
|
||||
})
|
||||
},
|
||||
scrolltolower() {
|
||||
if (this.loading) {
|
||||
this.loading = false
|
||||
return
|
||||
}
|
||||
if (this.page >= this.totalPage) {
|
||||
this.status = 'nomore'
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
this.status = 'loading'
|
||||
this.page++
|
||||
},
|
||||
getNotice() {
|
||||
getNotice({
|
||||
page_size: 9999,
|
||||
store_id: uni.getStorageSync('store_id') || '11001'
|
||||
}).then(res => {
|
||||
if (res.errcode === 401) {
|
||||
uni.clearStorageSync()
|
||||
uni.reLaunch({ url: '/pages/login/index' })
|
||||
}
|
||||
this.noticeList = res.data.list
|
||||
})
|
||||
},
|
||||
|
||||
// 医生详情
|
||||
getInfo() {
|
||||
info({
|
||||
store_id: uni.getStorageSync('store_id') || '11001'
|
||||
}).then((res) => {
|
||||
// console.log(res.data, 'work-res');
|
||||
if (res.errcode == 0) {
|
||||
this.doctorInfo = res.data
|
||||
this.see_rate = res.data.store.store.see_rate
|
||||
// console.log(this.see_rate,'sssss');
|
||||
uni.setStorageSync('see_rate', this.see_rate)
|
||||
uni.setStorageSync('doctorInfo', this.doctorInfo)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 搜索门店
|
||||
handleSearch() {
|
||||
this.getStore()
|
||||
},
|
||||
|
||||
// 门店列表
|
||||
getStore() {
|
||||
currentList({
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
keyword: this.keyword
|
||||
}).then((res) => {
|
||||
// console.log(res, 'store');
|
||||
if (res.errcode == 0) {
|
||||
this.storeList = res.data.list
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 切换门店
|
||||
changeStore(id) {
|
||||
this.store_id = id
|
||||
},
|
||||
sure() {
|
||||
chooseList({
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
store: this.store_id
|
||||
}).then((res) => {
|
||||
// console.log(res, 'changstore');
|
||||
if (res.errcode == 0) {
|
||||
this.$toast(res.data[0])
|
||||
uni.setStorageSync('store_id', this.store_id)
|
||||
} else {
|
||||
this.$toast(res.msg || res.data[0])
|
||||
this.store_id = uni.getStorageSync('store_id')
|
||||
}
|
||||
|
||||
this.openShow = false
|
||||
this.getInfo()
|
||||
})
|
||||
},
|
||||
// 消息列表
|
||||
getList() {
|
||||
homeSession({
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
}).then((res) => {
|
||||
if (res.errcode == 0) {
|
||||
this.systemList = (res.data.system) || []
|
||||
this.infoList = (res.data.patient) || []
|
||||
|
||||
} else {
|
||||
this.$toast(res.msg);
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.loading = false
|
||||
})
|
||||
});
|
||||
},
|
||||
// 跳转到小程序
|
||||
toNext() {
|
||||
uni.navigateToMiniProgram({
|
||||
appId: 'wx8e8f04d0cf7831bf',
|
||||
path: 'pages/login/index?id=',
|
||||
envVersion: "release",
|
||||
extraData: {
|
||||
'data1': 'test'
|
||||
},
|
||||
success: res => {
|
||||
// 打开成功
|
||||
console.log("打开成功", res);
|
||||
},
|
||||
fail: err => {
|
||||
console.log(err);
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
// this.getInfo()
|
||||
// this.getStore()
|
||||
// this.getList()
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #eeeeef;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.bg {
|
||||
width: 100vw;
|
||||
background: linear-gradient(90deg, #6ACDBB 0%, #6ACDBB 93%);
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background: linear-gradient(90deg, #6ACDBB 0%, #6ACDBB 93%);
|
||||
width: 100vw;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
font-size: 34rpx;
|
||||
font-family: PingFang SC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #FFFFFF;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 0 20rpx;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
margin-top: 30rpx;
|
||||
}
|
||||
|
||||
.content_popup {
|
||||
padding: 24rpx;
|
||||
|
||||
.top {
|
||||
height: 200rpx;
|
||||
|
||||
.search {
|
||||
position: relative;
|
||||
z-index: 982;
|
||||
}
|
||||
|
||||
.title {
|
||||
height: 54rpx;
|
||||
line-height: 54rpx;
|
||||
font-size: 32rpx;
|
||||
text-align: center;
|
||||
font-family: PingFang SC-Bold, PingFang SC;
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.store_list {
|
||||
padding: 0 30rpx;
|
||||
height: 100rpx;
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Bold, PingFang SC;
|
||||
font-weight: bold;
|
||||
color: #333333;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.confrim-btn {
|
||||
width: 100%;
|
||||
height: 100rpx;
|
||||
padding: 0 30rpx;
|
||||
margin-top: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.u-btn {
|
||||
width: 300rpx;
|
||||
height: 84rpx;
|
||||
line-height: 80rpx;
|
||||
text-align: center;
|
||||
border-radius: 44rpx 44rpx 44rpx 44rpx;
|
||||
}
|
||||
|
||||
.qx {
|
||||
border: 2rpx solid #6ACDBB;
|
||||
color: #6ACDBB;
|
||||
}
|
||||
|
||||
.qd {
|
||||
background: #6ACDBB;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.box {
|
||||
position: relative;
|
||||
padding: 0 32rpx;
|
||||
height: 318rpx;
|
||||
|
||||
&_info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
|
||||
&_left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-content: flex-start;
|
||||
flex-wrap: nowrap;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #FFFFFF;
|
||||
font-size: 28rpx;
|
||||
|
||||
&_name {
|
||||
font-size: 36rpx;
|
||||
font-family: PingFang SC-Medium, PingFang SC;
|
||||
font-weight: 500;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
&_right {
|
||||
height: 106rpx;
|
||||
|
||||
image {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&_data {
|
||||
width: 686rpx;
|
||||
height: 116rpx;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Semibold, PingFang SC;
|
||||
font-weight: 600;
|
||||
color: #FFFFFF;
|
||||
margin-top: 50rpx;
|
||||
padding: 0 32rpx;
|
||||
|
||||
view {
|
||||
height: 84rpx;
|
||||
min-width: 120rpx;
|
||||
}
|
||||
|
||||
&_nub {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.store_ {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Semibold, PingFang SC;
|
||||
font-weight: 500;
|
||||
color: #FFFFFF;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.u-icon {
|
||||
margin-left: 30rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.function {
|
||||
background-color: #fff;
|
||||
border-radius: 16rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #323233;
|
||||
|
||||
&_grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-column-gap: 86rpx;
|
||||
}
|
||||
|
||||
&_item {
|
||||
position: relative;
|
||||
width: 292rpx;
|
||||
height: 144rpx;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 96rpx;
|
||||
height: 96rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.news {
|
||||
background-color: #fff;
|
||||
margin-top: 20rpx;
|
||||
max-height: 100vh;
|
||||
|
||||
|
||||
&_title {
|
||||
height: 82rpx;
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Semibold, PingFang SC;
|
||||
font-weight: 600;
|
||||
color: #0D111A;
|
||||
padding: 0 26rpx;
|
||||
box-sizing: border-box;
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
}
|
||||
}
|
||||
|
||||
&_item {
|
||||
margin-top: 12rpx;
|
||||
padding: 26rpx 20rpx;
|
||||
position: relative;
|
||||
|
||||
&_info {
|
||||
height: 92rpx;
|
||||
width: 562rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
font-size: 32rpx;
|
||||
|
||||
&_msg {
|
||||
font-size: 28rpx;
|
||||
width: 462rpx;
|
||||
color: #6C7380;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.phone {
|
||||
color: #999;
|
||||
text-align: center;
|
||||
padding-top: 20rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
</style>
|
||||
764
pages/workbench/prescriptionDetail.vue
Normal file
@@ -0,0 +1,764 @@
|
||||
<template>
|
||||
<view class="container safe-area-inset-bottom">
|
||||
<!-- 处方 -->
|
||||
<view class="head">
|
||||
<view class="head_record_top">
|
||||
<view class="record">
|
||||
处方编号:{{infoList.prescription_no}}
|
||||
</view>
|
||||
<view class="record_state">
|
||||
{{lists.type==1 ? '普通':'常用'}}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 医院 -->
|
||||
<view class="head_record">
|
||||
<image src="@/static/image/hlwyy.png" mode=""></image>
|
||||
<view class="record_yard">
|
||||
<view class="yard">
|
||||
银川慧疗互联网医院
|
||||
</view>
|
||||
<view class="state">
|
||||
处方笺
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 时间 -->
|
||||
<view class="head_record_time">
|
||||
<text style="text-align: right;">开具日期:{{infoList.created_at}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 信息 -->
|
||||
<view class="my_info">
|
||||
<view class="info">
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
姓名:
|
||||
<text>{{infoList.patient.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
性别:
|
||||
<text>{{infoList.patient.sex%2==0?'女':'男'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
年龄:
|
||||
<text>{{infoList.patient.age}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
类别:
|
||||
<text>{{infoList.category}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info">
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
科室:
|
||||
<text>{{infoList.doctor.depart.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info_item">
|
||||
<view class="name">
|
||||
电话:
|
||||
<text>{{infoList.patient.mobile}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info">
|
||||
<view class="info_item">
|
||||
<view class="names">
|
||||
诊断:
|
||||
<text>{{infoList.clinical_diagnose}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bg">
|
||||
<!-- 药品 -->
|
||||
<view class="my_medical">
|
||||
<view class="title">
|
||||
Rp
|
||||
</view>
|
||||
|
||||
<block v-if="lists.prescription_type==1||lists.prescription_type==3">
|
||||
<view class="items" v-for="(item,index) in infoList.repice" :key="item.id">
|
||||
<!-- v-for="(it,index) in item.content" :key="it.id" -->
|
||||
<view class="name">
|
||||
<view class="_name" v-for="(it,index) in item.content" :key="it.id">
|
||||
<view class="text">
|
||||
<text>{{ it.name}}</text>
|
||||
<text class="_abbr" v-if="it.order">[{{useWay[it.order]}}]</text>
|
||||
</view>
|
||||
<text class="name_num">{{ it.number}}{{it.unit?it.unit.name:'g'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="details">
|
||||
<view class="text">
|
||||
<text>用法:煎服,每天 {{item.consumption}} 次 ,</text>
|
||||
<!-- <text v-if="item.deployment==2">{{' 每次 '+item.volume+' ml '}} , </text> -->
|
||||
<text> 共 {{item.dosage}} 剂 </text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
|
||||
<block v-if="lists.prescription_type==2">
|
||||
<view class="item" v-for="(it,index) in infoList.repice" :key="item.id">
|
||||
<!-- v-for="(it,index) in item.content" :key="it.id" -->
|
||||
<view class="name" style="justify-content: space-between;">
|
||||
<view class="yp_name">
|
||||
<text>{{ it.content.drug_name}} </text>
|
||||
<text style="font-size: 24rpx;margin-left: 10rpx;">{{ it.content.specification }}</text>
|
||||
</view>
|
||||
<text>x{{ it.number}}</text>
|
||||
</view>
|
||||
<view class="details">
|
||||
<text>用法:{{ it.instruction }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
</view>
|
||||
|
||||
<!-- 医嘱 -->
|
||||
<view class="doctor_order">
|
||||
<view class="yz">
|
||||
<text class="order_info_left">医嘱:</text>
|
||||
<view class="order_info">
|
||||
<view class="info" v-for="(item ,index) in lists.doctor_order" :key="index">
|
||||
{{item}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="titles">
|
||||
处方开具已完毕
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
<view class="my_doctor">
|
||||
<view class="doctor_info">
|
||||
<view class="info">
|
||||
<text>医师</text>
|
||||
<text class="name">{{infoList.doctor.name}}</text>
|
||||
</view>
|
||||
<view class="info">
|
||||
<text>初审药师</text>
|
||||
<text class="name">{{infoList.first_view||''}}</text>
|
||||
</view>
|
||||
<view class="info">
|
||||
<text>复审药师</text>
|
||||
<text class="name">{{infoList.again_view||''}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="price">
|
||||
价格:¥{{ infoList.total_pay_price }}
|
||||
</view>
|
||||
</view>
|
||||
<!-- 温馨提示 -->
|
||||
<view class="my_prompt">
|
||||
<view class="title">
|
||||
温馨提示:请遵医嘱服药!处方{{lists.valid_hours}}小时有效!
|
||||
</view>
|
||||
<image src="/static/group/img-yzf.png" mode="" v-if="status==2"></image>
|
||||
</view>
|
||||
<view v-if="notice_id" class="rotation" @click.stop="rotation">转 方</view>
|
||||
<!-- 状态 -->
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
rotationApi,
|
||||
prescripDetail,
|
||||
getUseWay
|
||||
} from "@/api/all.js";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
statusName: {
|
||||
0: '待审核',
|
||||
1: '已通过',
|
||||
2: '未通过',
|
||||
3: '待使用',
|
||||
4: '已使用',
|
||||
5: '未使用',
|
||||
6: '已失效',
|
||||
7: '已初审'
|
||||
},
|
||||
// status:flase,
|
||||
status: true,
|
||||
// status: "", // 处方状态
|
||||
status: "", // 处方状态
|
||||
id: "",
|
||||
infoList: [],
|
||||
num: 1,
|
||||
rpList: [],
|
||||
order_id: "",
|
||||
lists: [],
|
||||
useWay: [],
|
||||
notice_id: ''
|
||||
}
|
||||
},
|
||||
onLoad(e) {
|
||||
// console.log('12')
|
||||
// console.log(e, "id");
|
||||
this.id = e.id
|
||||
this.notice_id = e.notice_id
|
||||
this.getInfo()
|
||||
getUseWay({
|
||||
store_id: uni.getStorageSync('store_id') || 11001,
|
||||
}).then((res) => {
|
||||
if (res.errcode == 0) {
|
||||
const useWay = ["无", ...(res.data.map(it => it.name))]
|
||||
uni.setStorageSync('useWay', JSON.stringify(useWay))
|
||||
this.useWay = useWay
|
||||
}
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
async rotation() {
|
||||
rotationApi({
|
||||
notice_id: this.notice_id,
|
||||
store_id: uni.getStorageSync('store_id') || '11001'
|
||||
}).then(res => {
|
||||
uni.showToast({
|
||||
title: '转方成功',
|
||||
icon: 'success',
|
||||
mask: true
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack({ delta: 1 })
|
||||
}, 1500)
|
||||
})
|
||||
},
|
||||
// 数量
|
||||
getnum(obj) {
|
||||
let list = obj
|
||||
let num = 0
|
||||
list.map((it) => {
|
||||
num += it.number
|
||||
})
|
||||
return num
|
||||
},
|
||||
getInfo() {
|
||||
prescripDetail({
|
||||
store_id: uni.getStorageSync('store_id') || '11001',
|
||||
prescription_id: this.id
|
||||
}).then((res) => {
|
||||
// console.log(res, 'deta');
|
||||
if (res.errcode == 0) {
|
||||
this.infoList = res.data.content
|
||||
this.rpList = res.data.pharmacistInfo
|
||||
this.lists = res.data
|
||||
this.status = res.data.status
|
||||
|
||||
// console.log(this.rpList, 'info');
|
||||
|
||||
|
||||
}
|
||||
})
|
||||
},
|
||||
// getDrug(obj) {
|
||||
// console.log(obj, 'obj')
|
||||
// if (!obj) {
|
||||
// return
|
||||
// }
|
||||
// let list = (obj.chinese.length > 0 ? obj.chinese : obj.west) || []
|
||||
// let drugs = []
|
||||
// // console.log(list);
|
||||
// for (let i = 0; i < list.length; i++) {
|
||||
// if (obj.chinese.length > 0) {
|
||||
// for (let j = 0; j < JSON.parse(list[i].content).length; j++) {
|
||||
// drugs.push(JSON.parse(list[i].content)[j]['name'])
|
||||
// }
|
||||
// } else {
|
||||
// drugs.push(JSON.parse(list[i].content)['name'])
|
||||
// }
|
||||
// }
|
||||
// return drugs.join()
|
||||
// },
|
||||
},
|
||||
mounted() {
|
||||
// this.getInfo()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.container {
|
||||
width: 750rpx;
|
||||
min-height: 100vh;
|
||||
max-height: 100%;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
|
||||
.bg {
|
||||
min-height: calc(100vh - 600rpx);
|
||||
}
|
||||
|
||||
.head {
|
||||
.head_record_top {
|
||||
width: 710rpx;
|
||||
margin: 14rpx auto 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.record {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
}
|
||||
|
||||
.record_state {
|
||||
width: 80rpx;
|
||||
height: 42rpx;
|
||||
line-height: 42rpx;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #A7ABB0;
|
||||
border: 1rpx solid #C4C7CC;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.head_record_time {
|
||||
text-align: right;
|
||||
width: 750rpx;
|
||||
padding: 0 32rpx;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
}
|
||||
|
||||
.head_record {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
image {
|
||||
width: 160rpx;
|
||||
height: 150rpx;
|
||||
position: absolute;
|
||||
left: 40%;
|
||||
top: -8rpx;
|
||||
}
|
||||
|
||||
.record_yard {
|
||||
text-align: center;
|
||||
|
||||
.yard {
|
||||
font-size: 46rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
}
|
||||
|
||||
.state {
|
||||
height: 44rpx;
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.head_record_time {
|
||||
text-align: right;
|
||||
margin-top: 20rpx;
|
||||
width: 750rpx;
|
||||
padding-right: 32rpx;
|
||||
height: 34rpx;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
line-height: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 信息
|
||||
.my_info {
|
||||
width: 710rpx;
|
||||
margin: 4rpx auto;
|
||||
border-top: 1rpx solid #31353D;
|
||||
border-bottom: 1rpx solid #31353D;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
padding: 4rpx 4rpx;
|
||||
|
||||
.info {
|
||||
width: 710rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.info_item {
|
||||
|
||||
.names {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
|
||||
text {
|
||||
flex: 1;
|
||||
display: block;
|
||||
height: 40rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
line-height: 40rpx;
|
||||
margin: 0 0rpx 0 8rpx;
|
||||
// flex-wrap: nowrap;
|
||||
// display: -webkit-box;
|
||||
// -webkit-line-clamp: 1;
|
||||
// -webkit-box-orient: vertical;
|
||||
// text-overflow: ellipsis;
|
||||
// overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
|
||||
text {
|
||||
flex: 1;
|
||||
display: block;
|
||||
height: 40rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
line-height: 40rpx;
|
||||
margin: 0 26rpx 0 6rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 药品
|
||||
.my_medical {
|
||||
width: 710rpx;
|
||||
margin: 4rpx auto;
|
||||
padding: 1rpx 10rpx;
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Semibold, PingFang SC;
|
||||
font-weight: 600;
|
||||
color: #31353D;
|
||||
margin-bottom: 2rpx;
|
||||
}
|
||||
|
||||
.item {
|
||||
width: 710rpx;
|
||||
padding: 1rpx 0;
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
display: flex;
|
||||
// justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
._name {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 2rpx 80rpx 2rpx 0;
|
||||
|
||||
.text {
|
||||
margin-right: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
._abbr {
|
||||
color: #A7ABB0;
|
||||
font-size: 20rpx;
|
||||
margin-top: 2rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
|
||||
.text {
|
||||
|
||||
text {
|
||||
word-spacing: 1rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.items {
|
||||
width: 710rpx;
|
||||
padding: 1rpx 0;
|
||||
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
display: flex;
|
||||
// justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
|
||||
._name {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 2rpx 80rpx 2rpx 0;
|
||||
|
||||
.text {
|
||||
margin-right: 26rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
._abbr {
|
||||
color: #A7ABB0;
|
||||
font-size: 20rpx;
|
||||
margin-top: 2rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.details {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #6C7380;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-around;
|
||||
|
||||
.text {
|
||||
|
||||
text {
|
||||
word-spacing: 1rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 医嘱
|
||||
.doctor_order {
|
||||
width: 710rpx;
|
||||
margin: 2rpx auto;
|
||||
padding: 0 10rpx;
|
||||
word-spacing: 2rpx;
|
||||
|
||||
.yz {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
color: #6C7380;
|
||||
|
||||
.order_info_left {
|
||||
margin-right: 3rpx;
|
||||
}
|
||||
|
||||
.order_info {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
line-height: 40rpx;
|
||||
margin-bottom: 2rpx;
|
||||
|
||||
.info {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.titles {
|
||||
width: 710rpx;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #A7ABB0;
|
||||
margin: 8rpx 0 20rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 医生
|
||||
.my_doctor {
|
||||
width: 710rpx;
|
||||
margin: 2rpx auto;
|
||||
border-top: 1rpx solid #31353D;
|
||||
border-bottom: 1rpx solid #31353D;
|
||||
padding: 2rpx 4rpx;
|
||||
|
||||
.doctor_info {
|
||||
width: 710rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 4rpx;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.info {
|
||||
min-width: 222rpx;
|
||||
max-width: 400rpx;
|
||||
margin: 5rpx 0 8rpx;
|
||||
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 82rpx;
|
||||
height: 62rpx;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 106rpx;
|
||||
font-size: 32rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
line-height: 38rpx;
|
||||
border-bottom: 2rpx solid #000000;
|
||||
margin-left: 16rpx;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.price {
|
||||
width: 710rpx;
|
||||
font-size: 24rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #31353D;
|
||||
}
|
||||
}
|
||||
|
||||
// 温馨提示
|
||||
.my_prompt {
|
||||
width: 710rpx;
|
||||
height: 304rpx;
|
||||
margin: 0 auto;
|
||||
padding: 0 4rpx;
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
width: 710rpx;
|
||||
height: 40rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #A7ABB0;
|
||||
line-height: 40rpx;
|
||||
margin: 32rpx 0;
|
||||
}
|
||||
|
||||
image {
|
||||
width: 159rpx;
|
||||
height: 100rpx;
|
||||
position: absolute;
|
||||
left: 60%;
|
||||
top: 0%;
|
||||
}
|
||||
|
||||
.prompt {
|
||||
width: 710rpx;
|
||||
height: 200rpx;
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #A7ABB0;
|
||||
}
|
||||
|
||||
ol {
|
||||
padding: 0 0 0 32rpx;
|
||||
|
||||
li {
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #A7ABB0;
|
||||
margin: 4rpx 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 状态
|
||||
.my_state {
|
||||
width: 710rpx;
|
||||
height: 40rpx;
|
||||
margin: 12rpx auto;
|
||||
padding-bottom: 110rpx;
|
||||
font-size: 28rpx;
|
||||
font-family: PingFang SC-Regular, PingFang SC;
|
||||
font-weight: 400;
|
||||
color: #F44336;
|
||||
line-height: 40rpx;
|
||||
}
|
||||
|
||||
.line {
|
||||
border-bottom: 2rpx solid #31353D;
|
||||
}
|
||||
}
|
||||
.rotation {
|
||||
position: fixed;
|
||||
bottom: 30rpx;
|
||||
right: 24rpx;
|
||||
left: 24rpx;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
font-size: 30rpx;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #5792f9;
|
||||
color: #fff;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
</style>
|
||||
140
pages/workbench/prescriptionList.vue
Normal file
@@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<view class="">
|
||||
<view class="box safe-area-inset-bottom">
|
||||
<view class="p-row-2 m-t-2">
|
||||
<block v-if="list.length > 0">
|
||||
<view class="p-32 b-r-8 white m-b-2 item" v-for="(item, i) in list" :key="item.id"
|
||||
@click="$go('./prescriptionDetail?id=' +item.data + '¬ice_id=' + item.id)">
|
||||
<view class="flex-row flex-ali-center flex-jus-sp m-t-2">
|
||||
<u-icon margin-left="8" label-size="32" label-color="#6C7380"
|
||||
:name="require('../../static/image/ys.png')" :label="item.content"
|
||||
color="#6ACDBB" size="32"></u-icon>
|
||||
<!-- <d-text :text="statusName[item.status]"></d-text> -->
|
||||
</view>
|
||||
<!-- <view class="flex-row flex-ali-center flex-jus-sp m-t-2">
|
||||
<d-text className="content-c fs-32" :text="getInfo(item.patient || {})"></d-text>
|
||||
</view> -->
|
||||
<view class="flex-row flex-ali-center flex-jus-sp m-t-2">
|
||||
<d-text :text="item.notice_at"></d-text>
|
||||
</view>
|
||||
<view class="rotation" @click.stop="rotation(item)">转方</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
getNotice,
|
||||
rotationApi
|
||||
} from "@/api/all.js";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
page: 1,
|
||||
loading: true,
|
||||
loading2: true,
|
||||
status: "loading",
|
||||
totalPage: 1,
|
||||
loadText: {
|
||||
loadmore: "轻轻上拉",
|
||||
loading: "努力加载中",
|
||||
nomore: "已加载全部",
|
||||
},
|
||||
current: 0,
|
||||
status: ""
|
||||
};
|
||||
},
|
||||
|
||||
created() {},
|
||||
onShow() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
getInfo(user) {
|
||||
return `${user.name} ${user.sex == 1 ? "男" : "女"} ${user.age}岁`;
|
||||
},
|
||||
async getList() {
|
||||
getNotice({
|
||||
page_size: 9999,
|
||||
store_id: uni.getStorageSync('store_id') || '11001'
|
||||
}).then(res => {
|
||||
console.log(res, 'reess')
|
||||
this.list = res.data.list
|
||||
})
|
||||
},
|
||||
async rotation(row) {
|
||||
rotationApi({
|
||||
notice_id: row.id,
|
||||
store_id: uni.getStorageSync('store_id') || '11001'
|
||||
}).then(res => {
|
||||
uni.showToast({
|
||||
title: '转方成功',
|
||||
icon: 'success',
|
||||
mask: true
|
||||
})
|
||||
this.list = this.list.filter(item => item.id != row.id)
|
||||
})
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style>
|
||||
page {
|
||||
background-color: #f9fafb;
|
||||
}
|
||||
</style>
|
||||
<style lang="scss" scoped>
|
||||
.tabs{
|
||||
background-color: #fff;
|
||||
width: 750rpx;
|
||||
position: sticky;
|
||||
top: 0rpx;
|
||||
z-index: 9999999;
|
||||
padding-top: 12rpx;
|
||||
}
|
||||
|
||||
.box {
|
||||
position: relative;
|
||||
z-index: 982;
|
||||
|
||||
image {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .box {
|
||||
.u-tab-item {
|
||||
line-height: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.state {
|
||||
margin-top: 160rpx;
|
||||
|
||||
image {
|
||||
width: 300rpx;
|
||||
height: 223rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
padding: 16rpx 32rpx;
|
||||
}
|
||||
.item {
|
||||
position: relative;
|
||||
.rotation {
|
||||
position: absolute;
|
||||
right: 24rpx;
|
||||
bottom: 24rpx;
|
||||
padding: 8rpx 30rpx;
|
||||
background: #5792f9;
|
||||
color: #fff;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
136
pages1.json
Normal file
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
|
||||
"^d-(.*)": "@/components/d-$1/d-$1.vue"
|
||||
},
|
||||
"pages": [{
|
||||
"path": "pages/workbench/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "工作台",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/patient/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "患者",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/article/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的文章",
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/my/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/pharmacist/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "药师",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [{
|
||||
"root": "subPackages/sub_workbench",
|
||||
"pages": [{
|
||||
"path": "workbench_code",
|
||||
"style": {
|
||||
"navigationBarTitleText": "医生码"
|
||||
}
|
||||
|
||||
}]
|
||||
}, {
|
||||
"root": "subPackages/sub_patient",
|
||||
"pages": [{
|
||||
"path": "patient_label",
|
||||
"style": {
|
||||
"navigationBarTitleText": "标签管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "patient_massInfo",
|
||||
"style": {
|
||||
"navigationBarTitleText": "群发信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "patient_select",
|
||||
"style": {
|
||||
"navigationBarTitleText": "群发信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "patient_details",
|
||||
"style": {
|
||||
"navigationBarTitleText": "患者详情"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "subPackages/sub_article",
|
||||
"pages": [{
|
||||
"path": "article_release",
|
||||
"style": {
|
||||
"navigationBarTitleText": "无标题文档"
|
||||
}
|
||||
}, {
|
||||
"path": "article_draft",
|
||||
"style": {
|
||||
"navigationBarTitleText": "我的草稿"
|
||||
}
|
||||
}, {
|
||||
"path": "article_video",
|
||||
"style": {
|
||||
"navigationBarTitleText": "无标题文档"
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"tabBar": {
|
||||
"color": "#fff",
|
||||
"selectedColor": "#fff",
|
||||
"backgroundColor": "#fff",
|
||||
"borderStyle": "white",
|
||||
"list": [{
|
||||
"pagePath": "pages/workbench/index",
|
||||
"text": "工作台"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/patient/index",
|
||||
"text": "患者"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/article/index",
|
||||
"text": "我的文章"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/my/index",
|
||||
"text": "我的"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/pharmacist/index",
|
||||
"text": "审方"
|
||||
}
|
||||
]
|
||||
},
|
||||
"globalStyle": {
|
||||
"navigationBarTitleText": "掌上互联网医院",
|
||||
"navigationBarBackgroundColor": "#fff",
|
||||
"navigationBarTextStyle": "black",
|
||||
"backgroundColor": "#f7f8fa"
|
||||
}
|
||||
}
|
||||
BIN
static/group/img-yzf.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
static/group/new_xx.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
static/group/xkyard.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
static/image/act.png
Normal file
|
After Width: | Height: | Size: 594 B |
BIN
static/image/activate.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
static/image/aq.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
static/image/cf.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
static/image/cf1.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
static/image/cfd.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
static/image/del2.png
Normal file
|
After Width: | Height: | Size: 351 B |
BIN
static/image/djr.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
static/image/doctor.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
static/image/dx.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
static/image/dy.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
static/image/fbwz.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
static/image/fswz.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
static/image/fwsz.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
static/image/fz.png
Normal file
|
After Width: | Height: | Size: 405 B |
BIN
static/image/gou.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
static/image/grzl.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
static/image/gzt.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
static/image/hlwyy.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
static/image/home1.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
static/image/home2.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
static/image/huiua.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
static/image/hz-qfxx.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
static/image/hz.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
static/image/hz_ddjz.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
static/image/hz_xsjz.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
static/image/hzxq.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
static/image/i.png
Normal file
|
After Width: | Height: | Size: 679 B |
BIN
static/image/i1.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
static/image/i3.png
Normal file
|
After Width: | Height: | Size: 721 B |