李进才 2 years ago
parent 16fa6bb8b9
commit 5f104de493
  1. 2
      src/components/layout/me/me.vue
  2. 75
      src/hooks/hook-websocket.mjs
  3. 12
      src/utils/date-util.mjs
  4. 138
      src/views/body-checkup/combo-detail.vue
  5. 229
      src/views/body-checkup/combo.vue
  6. 103
      src/views/body-checkup/personal-reserve-pay.vue
  7. 74
      src/views/body-checkup/record.vue
  8. 18
      src/views/health-card/health-auth.vue
  9. 2
      src/views/medical-record/medical-record-apply.vue
  10. 2
      src/views/medical-record/medical-record-history.vue
  11. 608
      src/views/online/online-doctor/components/ol-doctor.vue
  12. 316
      src/views/online/online-doctor/components/ol-message.vue
  13. 347
      src/views/online/online-doctor/components/ol-msg-input.vue
  14. 0
      src/views/online/online-doctor/components/ol-user/dialog-workload.vue
  15. 45
      src/views/online/online-doctor/components/ol-user/ol-setting.vue
  16. 201
      src/views/online/online-doctor/components/ol-user/ol-user-list.vue
  17. 273
      src/views/online/online-doctor/components/ol-user/ol-user-state.vue
  18. 0
      src/views/online/online-doctor/components/ol-user/tab-word.vue
  19. 1424
      src/views/online/online-doctor/components/online-doctor copy.vue
  20. 324
      src/views/online/online-doctor/online-box.vue
  21. 60
      src/views/online/online-patient/concern-list.vue
  22. 29
      src/views/online/online-patient/consultation.vue
  23. 1042
      src/views/online/online-patient/doctor-home.vue
  24. 9
      src/views/online/online-patient/ol-dept-list.vue
  25. 670
      src/views/online/online-patient/ol-doct-list.vue
  26. 146
      src/views/online/online-patient/order-manage.vue

@ -77,7 +77,7 @@
<van-icon name="star-o" <van-icon name="star-o"
size="16"></van-icon> size="16"></van-icon>
<div style="font-size:13px;margin-top:1px;" <div style="font-size:13px;margin-top:1px;"
@click="clickModule()">关注医生</div> @click="clickModule({ link: 'concern-doctor.vue' })">关注医生</div>
</div> </div>
<!-- <div class="me__header-item"> <!-- <div class="me__header-item">

@ -170,7 +170,8 @@ export function HOnMessage(resp, { success, onNotify }) {
const isWin = (cacheToUserId === fromUserId) ? (!cacheOrderId ? true : (orderId === cacheOrderId)) : false const isWin = (cacheToUserId === fromUserId) ? (!cacheOrderId ? true : (orderId === cacheOrderId)) : false
const isMeOther = (fromUserId == cacheUserId && toUserId == cacheToUserId && resp.device && cache.device != resp.device) // 自己的其他设备
const isMeOtherDevice = (fromUserId == cacheUserId && toUserId == cacheToUserId && resp.device && cache.device != resp.device)
console.log('isWin=', isWin, '\nfromUser------------------------\n', fromUser, '\ntoUser------------------------\n', toUser, '\n*****************************'); console.log('isWin=', isWin, '\nfromUser------------------------\n', fromUser, '\ntoUser------------------------\n', toUser, '\n*****************************');
@ -284,7 +285,7 @@ export function HOnMessage(resp, { success, onNotify }) {
userList.value.unshift(userList.value.splice(toUser.index, 1)[0]) userList.value.unshift(userList.value.splice(toUser.index, 1)[0])
toUser.unreadText = resp.data.content toUser.unreadText = resp.data.content
if (isMeOther) { if (isMeOtherDevice && isWin) {
msgList.value.push({ msgList.value.push({
content: resp.data.content, content: resp.data.content,
msgType: resp.data.msgType, msgType: resp.data.msgType,
@ -401,6 +402,7 @@ export function HGetUserInfo(toUserId) {
} }
/** /**
* 发送消息 * 发送消息
* sendState { -1:发送失败; 1:发送中; 值不存在:发送成功 } * sendState { -1:发送失败; 1:发送中; 值不存在:发送成功 }
@ -509,6 +511,14 @@ export function HCreateConnect(userId) {
webSocket.value.send(JSON.stringify({ fromUserId: userId, action: 1, device: cache.device })) webSocket.value.send(JSON.stringify({ fromUserId: userId, action: 1, device: cache.device }))
} }
/**
* 关闭连接
*/
export function HClose() {
WebSocketUtil.close()
}
/** /**
* 检测链接状态是否正常 * 检测链接状态是否正常
*/ */
@ -540,14 +550,26 @@ function HGetState(success) {
return webSocket.value.readyState === 1 return webSocket.value.readyState === 1
} }
/** /**
* 关闭连接 * 通知后台
* @param {String} userId   本人id
*/ */
export function HClose() { export function HSendAdmin({ action }) {
WebSocketUtil.close() if (!HGetState()) return
webSocket.value.send(JSON.stringify({ fromUserId: cache.userId, device: cache.device, action }))
} }
// 关闭连接
export function HDisConnect() {
if (!HGetState()) return
webSocket.value.send(JSON.stringify({
fromUserId: cache.userId,
device: cache.device,
action: -1
}))
}
function keep() { function keep() {
setInterval(() => { setInterval(() => {
// HCreateWebSocket(cache.url, cache) // HCreateWebSocket(cache.url, cache)
@ -561,3 +583,44 @@ function createGuid() {
return v.toString(16); return v.toString(16);
}); });
} }
export function JsonToArr(data) {
try {
if (!data) return []
data = JSON.parse(data)
if (!data || typeof data !== 'object') return []
return [data]
} catch (e) {
return []
}
}
export function JsonByKey(key, data, curData) {
if (!data) return curData
try {
data = JSON.parse(data)
} catch (e) {
return curData
}
const val = data[key]
if (val === undefined || val === null || val === '') return curData
return val
}
// 文本提示标签
export function UserListTipTag(rowData) {
if (rowData.cacheContent) {
rowData.cacheContent = rowData.cacheContent.trim()
if (rowData.cacheContent) return `<span style="color:red;">[草稿]</span>${rowData.cacheContent}`
}
const tip = (!rowData.unreadText ? (rowData.tipContent) : rowData.unreadText)
if (!tip) return ''
if (tip === 'tip') return '[提示]'
if (tip.indexOf('/upload/') !== -1 || tip === 'image') return '[图片]'
if (tip === 'symptom') return '[症状描述]'
return tip
}

@ -194,6 +194,17 @@ export function computDate(date, days, fmt) {
return format(new Date(day), fmt) return format(new Date(day), fmt)
} }
/**
* 8位日期转换成带横线的日期20221010 => 2022-10-10
* @param {String} date 日期
*/
export function date8StrAddLine(date) {
if (typeof date === 'string' && date.length === 8) {
return date.substring(0, 4) + '-' + date.substring(4, 6) + '-' + date.substring(6, 8)
}
return date
}
export default Object.freeze(window.DateUtil = { export default Object.freeze(window.DateUtil = {
format, format,
dateFormat, dateFormat,
@ -202,5 +213,6 @@ export default Object.freeze(window.DateUtil = {
isFutureDay, isFutureDay,
inTimeRange, inTimeRange,
getTimeEndPointWeek, getTimeEndPointWeek,
date8StrAddLine,
computDate computDate
}) })

@ -27,7 +27,7 @@
<span style="font-size: 18px;color: #fff;width: 60px;line-height: 60px;"></span> <span style="font-size: 18px;color: #fff;width: 60px;line-height: 60px;"></span>
</div> </div>
<div style="width: calc(100% - 60px);display: flex;flex-direction: column;"> <div style="width: calc(100% - 60px);display: flex;flex-direction: column;">
<div style="font-size: 20px;font-weight: bolder;padding: 5px 0;color: var(--text-a);">个人保健健康体检男女通用套餐</div> <div style="font-size: 20px;font-weight: bolder;padding: 5px 0 5px 8px;color: var(--text-a);">{{ state.pack.name }}</div>
</div> </div>
</div> </div>
@ -39,14 +39,21 @@
<div style="display: flex;flex-direction: row;align-items: center;justify-content: space-between;padding: 4px 0;"> <div style="display: flex;flex-direction: row;align-items: center;justify-content: space-between;padding: 4px 0;">
<span style="color: var(--text-b);font-size: 14px;">适用人群</span> <span style="color: var(--text-b);font-size: 14px;">适用人群</span>
<div style="display: flex;flex-direction: row;align-items: center;justify-content: flex-end;color: var(--text-c);"> <div style="display: flex;flex-direction: row;align-items: center;justify-content: flex-end;color: var(--text-c);">
<span style="margin-right: 6px;">男女通用</span> <span style="margin-right: 6px;">{{ state.pack.sex === '0'? '男女通用' : state.pack.sex === '1'? '适用男性' : state.pack.sex === '2'? '适用女性' : '' }}</span>
</div>
</div>
<div style="display: flex;flex-direction: row;align-items: center;justify-content: space-between;padding: 4px 0;">
<span style="color: var(--text-b);font-size: 14px;">套餐描述</span>
<div style="display: flex;flex-direction: row;align-items: center;justify-content: flex-end;color: var(--text-c);">
<span style="margin-right: 6px;">{{ state.pack.description }}</span>
</div> </div>
</div> </div>
<div style="width: 100%;height: 1px;background-color: var(--border-d);"></div> <div style="width: 100%;height: 1px;background-color: var(--border-d);"></div>
<div style="display: flex;flex-direction: row;align-items: center;justify-content: space-between;padding: 4px 0;"> <div style="display: flex;flex-direction: row;align-items: center;justify-content: space-between;padding: 4px 0;">
<span style="color: var(--text-b);font-size: 14px;">电话咨询</span> <span style="color: var(--text-b);font-size: 14px;">电话咨询</span>
<div style="display: flex;flex-direction: row;align-items: center;justify-content: flex-end;color: var(--text-c);"> <div style="display: flex;flex-direction: row;align-items: center;justify-content: flex-end;color: var(--text-c);">
<span style="margin-right: 6px;">0876-1234567</span> <span style="margin-right: 6px;"><a :href="`tel:0876-1234567`"
style="color: var(--text-c);">0876-1234567</a></span>
<van-icon name="arrow" <van-icon name="arrow"
size="14" size="14"
color="var(--text-c)" /> color="var(--text-c)" />
@ -76,26 +83,24 @@
</span> </span>
<span> <span>
<span style="font-size: 13px;color: var(--text-c);">共计</span> <span style="font-size: 13px;color: var(--text-c);">共计</span>
<span style="font-weight: bolder;">&emsp;88&emsp;</span> <span style="font-weight: bolder;">&emsp;{{ state.feeItemTotal }}&emsp;</span>
<span style="font-size: 13px;color: var(--text-c);"></span></span> <span style="font-size: 13px;color: var(--text-c);"></span></span>
</div> </div>
</template> </template>
<van-collapse v-model="state.itemActive"> <van-collapse v-model="state.itemActive">
<van-collapse-item v-for="(item, key) in checkItems" <van-collapse-item v-for="(item, key) in state.feeItem"
:key="key" :key="key"
:title="item.title" :title="item.feeItemName"
:name="item.id" :name="item.id"
:value="`${item.count} 项`"> :is-link="item.reportItems.length > 0"
<div v-for="(i, k) in item.child" :readonly="item.reportItems.length === 0"
:key="k" :value="item.reportItems.length > 0? `${item.reportItems.length} 项`:''">
style="padding: 4px 6px;border-bottom: 1px solid var(--border-c);"> <span style="font-size: 13px;color: var(--text-c);padding: 3px 0px;">{{ item.reportItems.map(r => r.rptItemName).join("、") }}</span>
<div style="font-size: 13px;color: var(--text-a);line-height: 20px;font-weight: bold;">{{ i.title }}</div>
<div style="font-size: 13px;color: var(--text-c);padding: 3px 0px;">{{ i.content }}</div>
</div>
</van-collapse-item> </van-collapse-item>
</van-collapse> </van-collapse>
</van-cell-group> </van-cell-group>
<van-cell-group title="包含项目"
<van-cell-group title="注意事项"
style="margin-bottom: 8px;background-color: #fff;"> style="margin-bottom: 8px;background-color: #fff;">
<template #title> <template #title>
<div style="display: flex;flex-direction: row;justify-content: space-between;align-items: center;font-size: 17px;"> <div style="display: flex;flex-direction: row;justify-content: space-between;align-items: center;font-size: 17px;">
@ -126,7 +131,7 @@
</div> </div>
</van-cell-group> </van-cell-group>
<van-cell-group title="包含项目" <van-cell-group title="体检流程"
style="background-color: #fff;"> style="background-color: #fff;">
<template #title> <template #title>
<div style="display: flex;flex-direction: row;justify-content: space-between;align-items: center;font-size: 17px;"> <div style="display: flex;flex-direction: row;justify-content: space-between;align-items: center;font-size: 17px;">
@ -196,6 +201,7 @@
</div> </div>
<van-button type="primary" <van-button type="primary"
class="btn-confirm-pay" class="btn-confirm-pay"
:disabled="!packId"
@click="toPay">确认订购</van-button> @click="toPay">确认订购</van-button>
</div> </div>
</transition> </transition>
@ -206,90 +212,24 @@
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { WxBack } from '@/utils/common-util.mjs' import { WxBack } from '@/utils/common-util.mjs'
import { axios } from 'axios'
export default { export default {
name: 'combo-detail', name: 'combo-detail',
setup(props, context) { setup(props, context) {
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const checkItems = [ // ID
{ const packId = route.query.packId
id: 1,
title: '基础检查',
count: 26,
child: [
{
title: '一般检查',
content: '身高、体重、体重指数(BMI)、血压、脉搏'
}, {
title: '外科检查',
content: '皮肤、浅表淋巴结、甲状腺'
}, {
title: '内科检查',
content: '营养、面容、心脏听诊、腹部触诊(肝/胆/脾/肾)、肺部'
}, {
title: '眼科检查',
content: '外眼、眼底镜检查、裂隙灯检查、色觉、矫正视力(左右)'
}, {
title: '耳鼻喉检查',
content: '外耳、外耳道、鼻腔、鼓膜'
}, {
title: '口腔检查',
content: '唇、牙齿、舌、牙周'
},
]
}, {
id: 2,
title: '实验室检查',
count: 52,
child: [
{
title: '血常规',
content: '白细胞计数、红细胞计数、血红蛋白量、中性粒细胞百分比、淋巴细胞百分比、红细胞压积、中间细胞计数、淋巴细胞数、中性粒细胞数、中间细胞百分比、平均红细胞体积、平均血红蛋白量、平均血红蛋白浓度、红细胞分布宽度、血小板容积、血小板分布宽度、血小板平均体积、血小板计数、嗜碱性粒细胞百分比、嗜碱性粒细胞数目、嗜酸性粒细胞数目、嗜酸性粒细胞百分比、异常淋巴细胞百分比、异常淋巴细胞数目、单核细胞百分比'
}, {
title: '尿常规',
content: '尿胆原、胆红素、尿酮体、隐血、尿蛋白、亚硝酸盐、尿白细胞、尿糖、尿比重、酸碱度、维生素C'
}, {
title: '血糖测定',
content: '空腹血糖 (GLU)'
}, {
title: '血脂检测',
content: '总胆固醇 (TC)、甘油三醋 (TG)、高密度脂蛋白胆固醇(HDL-C)'
}, {
title: '肾功能',
content: '血尿素氮(BUN)、尿素 (UREA)、血清尿酸检测(UA)'
}, {
title: '肝功能检查检查',
content: '总蛋白 (TP)、白球白蛋白 (ALB)、球蛋白 (GLB)比 (ALB/GLO) 、谷丙转氨酶 (ALT) 、谷转氨酶(AST) 、谷草/谷丙 (AST/ALT) 、总胆红素 (T-Bl)'
}, {
title: '肝炎感染检查',
content: '乙肝表面抗原(HBsAg)'
},
]
}, {
id: 3,
title: '仪器检查',
count: 10,
child: [
{
title: 'B超检查',
content: '肝、胆、脾、双肾、胰、阴道、前列腺'
}, {
title: 'X光(DR)',
content: '胸部(正位)、胸部(侧位)'
}, {
title: '心电图',
content: '十二导联心电图'
}
]
}
]
const state = reactive({ const state = reactive({
payMoney: 198.00, payMoney: 198.00,
showFooter: true, showFooter: true,
hospital: '', hospital: '',
itemActive: [] itemActive: [],
pack: '', //
feeItem: [], //
feeItemTotal: 0, //
}) })
if (WxConfig.micro && WxConfig.micro.hospital) state.hospital = WxConfig.micro.hospital if (WxConfig.micro && WxConfig.micro.hospital) state.hospital = WxConfig.micro.hospital
@ -300,14 +240,32 @@ export default {
}) })
} }
function getFeeItems() {
if (!packId) return vant.Toast.fail('参数缺失,无法查询套餐详情!')
axios.RGet('/personal/getFeeItems', {
packId: packId
}).then(response => {
if (response.code === 200) {
console.log('response.data', response.data)
state.feeItemTotal = 0
state.pack = response.data.pack
state.feeItem = response.data.feeItem
response.data.feeItem.forEach(item => {
state.feeItemTotal += item.reportItems.length
})
}
})
}
getFeeItems()
function toPay() { function toPay() {
router.push({ path: 'personal-reserve-pay' }) router.push({ path: 'personal-reserve-pay', query: { packId: packId } })
} }
return { return {
state, state,
packId,
onCancel, onCancel,
checkItems,
toPay toPay
} }
}, },

@ -1,10 +1,10 @@
<template> <template>
<div class="combo"> <div class="combo">
<van-tabs v-model:active="state.comboIndex"> <van-tabs v-model:active="state.comboIndex">
<van-tab v-for="item in combos" <van-tab v-for="item in state.items"
:key="item.index" :key="item.index"
:name="item.index" :name="item.index"
:title="item.label"> :title="item.name">
</van-tab> </van-tab>
</van-tabs> </van-tabs>
@ -28,8 +28,8 @@
</div> </div>
<div style="display: flex;flex-direction: row;padding: 5px;"> <div style="display: flex;flex-direction: row;padding: 5px;">
<div style="flex-direction: column;width: calc(50vw - 3px);height: calc();margin-right: 3px;"> <div style="flex-direction: column;width: calc(50vw - 3px);margin-right: 3px;">
<div v-for="(item, k) in items.filter(i => i.comboId === state.comboIndex).filter((i, index) => index%2 === 0)" <div v-for="(item, k) in getItems({ initItem: state.items.find(c => c.index === state.comboIndex), flag: 0 })"
:key="k" :key="k"
style="border: 1px solid var(--border-d);border-radius: 6px;overflow: hidden;background-color: #fff;margin-bottom: 10px;" style="border: 1px solid var(--border-d);border-radius: 6px;overflow: hidden;background-color: #fff;margin-bottom: 10px;"
@click="toBuy(item)"> @click="toBuy(item)">
@ -38,18 +38,18 @@
:key="i">{{ t }}<br /></span> :key="i">{{ t }}<br /></span>
</div> </div>
<div style="padding: 5px 5px;color: var(--text-b);"> <div style="padding: 5px 5px;color: var(--text-b);">
{{ item.label }} {{ item.name }}
</div> </div>
<div style="display: flex;align-items: center;padding: 5px;"> <div style="display: flex;align-items: center;padding: 5px;">
<div style="flex: 1;color: var(--color-danger);font-size: 12px;"><span style="font-size: 16px;font-weight: 600;">{{ parseInt(item.price).toFixed(2) }}</span></div> <div style="flex: 1;color: var(--color-danger);font-size: 12px;"><span style="font-size: 16px;font-weight: 600;">{{ parseInt(item.price).toFixed(2) }}</span></div>
<div style="flex: 1;font-size: 12px;color: var(--text-c);text-align: right;"> <div style="flex: 1;font-size: 12px;color: var(--text-c);text-align: right;">
{{ item.sales > 99? '99+':item.sales }}人付款 <!-- {{ item.sales > 99? '99+':item.sales }}人付款 -->
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div style="flex-direction: column;width: calc(50vw - 3px);margin-left: 3px;"> <div style="flex-direction: column;width: calc(50vw - 3px);margin-left: 3px;">
<div v-for="(item, k) in items.filter(i => i.comboId === state.comboIndex ).filter((i, index) => index%2 !== 0)" <div v-for="(item, k) in getItems({ initItem: state.items.find(c => c.index === state.comboIndex), flag: 1 })"
:key="k" :key="k"
style="border: 1px solid var(--border-d);border-radius: 6px;overflow: hidden;background-color: #fff;margin-bottom: 10px;" style="border: 1px solid var(--border-d);border-radius: 6px;overflow: hidden;background-color: #fff;margin-bottom: 10px;"
@click="toBuy(item)"> @click="toBuy(item)">
@ -58,12 +58,12 @@
:key="i">{{ t }}<br /></span> :key="i">{{ t }}<br /></span>
</div> </div>
<div style="padding: 5px 5px;color: var(--text-b);"> <div style="padding: 5px 5px;color: var(--text-b);">
{{ item.label }} {{ item.name }}
</div> </div>
<div style="display: flex;align-items: center;padding: 5px;"> <div style="display: flex;align-items: center;padding: 5px;">
<div style="flex: 1;color: var(--color-danger);font-size: 12px;"><span style="font-size: 16px;font-weight: 600;">{{ parseInt(item.price).toFixed(2) }}</span></div> <div style="flex: 1;color: var(--color-danger);font-size: 12px;"><span style="font-size: 16px;font-weight: 600;">{{ parseInt(item.price).toFixed(2) }}</span></div>
<div style="flex: 1;font-size: 12px;color: var(--text-c);text-align: right;"> <div style="flex: 1;font-size: 12px;color: var(--text-c);text-align: right;">
{{ item.sales > 99? '99+':item.sales }}人付款 <!-- {{ item.sales > 99? '99+':item.sales }}人付款 -->
</div> </div>
</div> </div>
</div> </div>
@ -77,6 +77,7 @@
import { reactive, ref, onUnmounted, computed, watch } from 'vue'; import { reactive, ref, onUnmounted, computed, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { store } from 'vue-helper' import { store } from 'vue-helper'
import { axios } from 'axios'
export default ({ export default ({
name: 'combo', name: 'combo',
setup(props, context) { setup(props, context) {
@ -85,201 +86,79 @@ export default ({
store.dispatch('setTitle', '个人体检预约') store.dispatch('setTitle', '个人体检预约')
const combos = [
{
index: 0,
label: '基础体检'
}, {
index: 1,
label: '入职体检'
}, {
index: 2,
label: '专项体检'
}, {
index: 3,
label: '婚孕体检'
}, {
index: 4,
label: '女性体检'
}, {
index: 5,
label: '男性体检'
}, {
index: 6,
label: '健康证'
}, {
index: 7,
label: '其他体检'
}
]
const items = [
{
id: 0,
comboId: 0,
label: '个人保健健康体检男女通用套餐',
price: '789',
sales: 120
}, {
id: 1,
comboId: 0,
label: '精细化全面妇科检查',
price: '189',
sales: 98
}, {
id: 2,
comboId: 1,
label: '入职体检(满足大部分事业单位)',
price: '179',
sales: 120
}, {
id: 3,
comboId: 1,
label: '入职体检',
price: '159',
sales: 120
}, {
id: 4,
comboId: 1,
label: '入职体检(豪华升级)',
price: '199',
sales: 120
}, {
id: 5,
comboId: 2,
label: '月经问题专项体检',
price: '120',
sales: 120
}, {
id: 6,
comboId: 2,
label: '性传染病深度筛查',
price: '318',
sales: 120
}, {
id: 7,
comboId: 2,
label: '孕期B超检查',
price: '49',
sales: 120
}, {
id: 8,
comboId: 2,
label: '女性不孕专项初步排查检查套餐',
price: '260',
sales: 120
}, {
id: 10,
comboId: 3,
label: '早孕检查|人流检查',
price: '20',
sales: 120
}, {
id: 11,
comboId: 3,
label: '女性孕前检查套餐',
price: '168',
sales: 120
}, {
id: 12,
comboId: 3,
label: '男性育前检查套餐',
price: '168',
sales: 120
}, {
id: 13,
comboId: 3,
label: '女性孕前健康检查',
price: '168',
sales: 120
}, {
id: 14,
comboId: 3,
label: '女性孕前前面备孕健康检查套餐',
price: '888',
sales: 120
}, {
id: 15,
comboId: 4,
label: 'HPV+TCT+全面妇科检查',
price: '298',
sales: 120
}, {
id: 16,
comboId: 4,
label: '宫颈癌筛查+全面妇科检查',
price: '298',
sales: 120
}, {
id: 17,
comboId: 5,
label: '男性育前健康检查',
price: '168',
sales: 120
}, {
id: 18,
comboId: 5,
label: '不育精准筛查',
price: '288',
sales: 120
}, {
id: 19,
comboId: 5,
label: '男性育前全面健康检查',
price: '800',
sales: 120
}, {
id: 20,
comboId: 6,
label: '公共场所健康证',
price: '198',
sales: 8
}, {
id: 21,
comboId: 7,
label: '两性传染病基础筛查套餐',
price: '88',
sales: 20
}
]
const state = reactive({ const state = reactive({
comboIndex: 0, comboIndex: 0,
comboLabel: combos[0].label comboLabel: '',
combos: [],
items: []
}) })
function toBuy(item) { function toBuy(item) {
router.push({ path: 'combo-detail' }) router.push({
path: 'combo-detail', query: {
packId: item.id
}
})
} }
function getComboLabel(label) { function getComboLabel(label) {
const length = label.length const length = label ? label.length : 0
if (length <= 3) { if (length <= 3) {
return [label] return [label]
} else { } else {
if (length % 2 === 0) { if (length % 2 === 0) {
return [label.substring(0, length / 2), label.substring(length / 2, length)] return [label.substring(0, length / 2), label.substring(length / 2, length)]
} else { } else {
return [label.substring(0, Math.floor(length / 2)), label.substring(Math.floor(length / 2), length)] return [label.substring(0, Math.floor(length / 2)), label.substring(Math.floor(length / 2), length)]
} }
} }
} }
watch(() => state.comboIndex, () => { watch(() => state.comboIndex, () => {
state.comboLabel = combos.find(i => i.index === state.comboIndex).label state.comboLabel = state.combos.find(c => c.index === state.comboIndex).name
}) })
onUnmounted(() => { onUnmounted(() => {
sessionStorage.removeItem(store.state.prefix + 'title') sessionStorage.removeItem(store.state.prefix + 'title')
}) })
function getList() {
axios.get('/personal/getPackList').then(response => {
if (response.code === 200) {
state.items = []
state.combos = response.data.map((c, index) => {
return {
name: c.name,
index: index
}
})
response.data.forEach((Item, Index) => {
Item.index = Index
Item.dictPacks.forEach((item, index) => {
item.comboId = Index
})
state.items.push(Item)
})
console.log('response.data', response.data)
state.comboLabel = state.combos.length > 0 ? state.combos[0].name : ''
}
})
}
getList()
function getItems({ initItem, flag }) {
if (!initItem || initItem.dictPacks.length === 0) return []
const list = initItem.dictPacks.filter(c => c.comboId === state.comboIndex)
return list.filter((i, index) => index % 2 === flag)
}
return { return {
state, state,
combos, // combos,
items, // items,
toBuy, toBuy,
getComboLabel getComboLabel,
getItems
} }
} }
}) })

@ -27,6 +27,14 @@
placeholder="请输入联系电话" placeholder="请输入联系电话"
:rules="[{ required: true, message: '请输入【电话号码】', trigger: 'onBlur' }, :rules="[{ required: true, message: '请输入【电话号码】', trigger: 'onBlur' },
{ name, message: '请输入格式正确的【电话号码】', trigger: 'onBlur' }]" /> { name, message: '请输入格式正确的【电话号码】', trigger: 'onBlur' }]" />
<van-field v-model="form.nation"
readonly
is-link
label="民族"
class="require text_left"
placeholder="点击选择民族"
:rules="[{ required: true, message: '点击选择民族', trigger: 'onBlur' }]"
@click="state.nationShow = true" />
<van-field v-model="form.address" <van-field v-model="form.address"
label="地址" label="地址"
class="text_left" class="text_left"
@ -75,13 +83,24 @@
:max-date="state.calendar.maxDate" :max-date="state.calendar.maxDate"
@confirm="calendarConfirm" /> @confirm="calendarConfirm" />
<van-popup v-model:show="state.nationShow"
round
position="bottom"
:style="{ height: '45%' }">
<van-picker title="民 族"
:columns="state.nations"
@confirm="onNationConfirm"
@cancel="onNationCancel" />
</van-popup>
</div> </div>
</template> </template>
<script> <script>
import { reactive, ref } from 'vue'; import { reactive, ref, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import SheetPatient from '@/components/patient/sheet-patient.vue' import SheetPatient from '@/components/patient/sheet-patient.vue'
import { axios } from 'axios'
export default { export default {
name: 'personal-reserve-pay', name: 'personal-reserve-pay',
components: { components: {
@ -91,6 +110,11 @@ export default {
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const packId = route.query.packId
if (!packId) {
vant.Toast.fail('参数缺失,请退出重新选择体检套餐')
}
const state = reactive({ const state = reactive({
showPatientSheet: false, showPatientSheet: false,
patient: '', patient: '',
@ -98,7 +122,9 @@ export default {
show: false, show: false,
minDate: getCalendarDate(1), minDate: getCalendarDate(1),
maxDate: getCalendarDate(7) maxDate: getCalendarDate(7)
} },
nations: [],
nationShow: false
}) })
const formRef = ref(null) const formRef = ref(null)
@ -108,7 +134,8 @@ export default {
idCardNo: '', idCardNo: '',
tel: '', tel: '',
address: '', address: '',
reserveDate: '' reserveDate: '',
nation: ''
}) })
function onConfirmPatient(patient) { function onConfirmPatient(patient) {
@ -139,15 +166,72 @@ export default {
} }
formRef.value.validate().then(() => { formRef.value.validate().then(() => {
vant.Dialog.confirm({ title: '提示', message: '请确认体检人信息以及预约时间是否正确?' }).then(() => { vant.Dialog.confirm({ title: '提示', message: '请确认体检人信息以及预约时间是否正确?' }).then(() => {
createOrder()
})
}).catch(() => {
})
}
function getConfig() {
axios.get('/config/GetReserveConfig').then(response => {
if (response.code === 200) {
state.nations = response.data.Nation.map(n => n.value)
}
})
}
getConfig()
function onNationConfirm(val, index) {
form.nation = val
state.nationShow = false
}
function onNationCancel() {
state.nationShow = false
}
watch(() => state.nationShow, () => {
if(state.nationShow && state.nations.length === 0) {
getConfig()
}
})
/**
* 创建订单
*/
function createOrder() {
if (!packId) return vant.Toast.fail('参数缺失,预定购买体检套餐')
axios.post('/personal/createOrder', {
name: state.patient.name,
idCard: state.patient.idCardNo,
birthday: state.patient.birthday,
age: state.patient.age,
sex: state.patient.sex === '男' ? 1 : state.patient.sex === '女' ? 2 : '',
tel: form.tel,
cardAddress: state.patient.address,
address: form.address,
nation: form.nation,
reserveTime: form.reserveDate,
packId: packId
}).then(response => {
if (response.code === 200) {
vant.Toast.success({ vant.Toast.success({
duration: 1000, duration: 1000,
message: '预约成功,将前往预约记录页面', onClose: () => { message: '预约成功,将前往预约记录查看', onClose: () => {
router.replace({ path: '/record' }) router.replace({ path: '/record' })
} }
}) })
}) } else if (response.code === 90001) {
}).catch(() => { vant.Toast.success({
duration: 1000,
message: response.message, onClose: () => {
router.replace({ path: '/record' })
}
})
} else {
vant.Toast.success.fail(response.message)
}
}) })
} }
@ -157,7 +241,10 @@ export default {
form, form,
onConfirmPatient, onConfirmPatient,
calendarConfirm, calendarConfirm,
onPay onPay,
onNationConfirm,
onNationCancel,
createOrder
} }
}, },
} }

@ -1,21 +1,23 @@
<template> <template>
<div class="record"> <div class="record">
<SheetPatientDate :showNavbar="false" /> <SheetPatientDate :showNavbar="false"
:showCode="false"
@confirm="getRecordList" />
<div class="container"> <div class="container">
<div v-for="(item, k) in state.list" <div v-for="(item, k) in state.list"
:key="k" :key="k"
class="item"> class="item">
<div style="position: relative;padding: 8px 10px;border-bottom: 1px solid var(--border-d);display: flex;justify-content: space-between;align-items: center;overflow: hidden;"> <div style="min-height: 16px;font-size: 12px;position: relative;padding: 8px 10px;border-bottom: 1px solid var(--border-d);display: flex;justify-content: space-between;align-items: center;overflow: hidden;">
<span>{{ item.applyTime }}</span> <span><span style="color: var(--text-c);">体检号</span>{{ item.id }}</span>
<div style="position: absolute;border-radius: 50%;width: 88px;height: 88px;overflow: hidden;top: -48px;right: -34px;" <div style="position: absolute;border-radius: 50%;width: 88px;height: 88px;overflow: hidden;top: -48px;right: -34px;"
:style="{backgroundColor: item.type === 1? 'var(--color-primary)': 'var(--color-success)' }"> :style="{backgroundColor: item.type === 1? 'var(--color-primary)': 'var(--color-success)' }">
<span v-if="item.type === 1" <span v-if="!item.oeid"
style="position: absolute;bottom: 14px;left: 18px; color: var(--text-b);text-align: center;color: #fff;">个检</span> style="position: absolute;bottom: 16px;left: 20px; color: var(--text-b);text-align: center;color: #fff;">个检</span>
<span v-else-if="item.type === 2" <span v-else
style="position: absolute;bottom: 14px;left: 18px;color: var(--text-b);text-align: center;color: #fff;">团检</span> style="position: absolute;bottom: 16px;left: 20px;color: var(--text-b);text-align: center;color: #fff;">团检</span>
</div> </div>
</div> </div>
<div class="content"> <div class="content">
<div style="padding: 4px 0;"> <div style="padding: 4px 0;">
{{ item.conboName }} {{ item.conboName }}
@ -23,7 +25,8 @@
<div style="line-height: 30px; display: flex;justify-content: space-between;"> <div style="line-height: 30px; display: flex;justify-content: space-between;">
<!-- <span>预约时间:</span> --> <!-- <span>预约时间:</span> -->
<span style="">{{ item.reserveTime }}</span> <span style="">{{ item.reserveTime }}</span>
<span v-if="item.type === 1" style="font-size: 18px;color: var(--color-warning);">{{ item.price }}</span> <span v-if="item.type === 1"
style="font-size: 18px;color: var(--color-warning);">{{ item.price }}</span>
<span v-else-if="item.type === 2">{{ item.count }}</span> <span v-else-if="item.type === 2">{{ item.count }}</span>
</div> </div>
</div> </div>
@ -37,6 +40,7 @@ import { reactive, ref, watch, onUnmounted } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { store } from 'vue-helper' import { store } from 'vue-helper'
import SheetPatientDate from '@/components/patient/select-patient-date.vue'; import SheetPatientDate from '@/components/patient/select-patient-date.vue';
import { axios } from 'axios'
export default { export default {
name: 'record', name: 'record',
components: { components: {
@ -47,31 +51,9 @@ export default {
const router = useRouter(); const router = useRouter();
store.dispatch('setTitle', '体检预约记录') store.dispatch('setTitle', '体检预约记录')
const state = reactive({ const state = reactive({
patient: store.getters.getPatient, list: []
bedDate: store.getters.getBegDate,
endDate: store.getters.getEndDate,
list: [{
type: 1,
applyTime: '2023-06-20 12:12:00',
reserveTime: '2023-06-20 12:12:00',
name: '张三',
price: '198',
isFinished: true,
conboId: 12,
conboName: '个人保健健康体检男女通用套餐',
}, {
type: 2,
applyTime: '2023-06-20 12:12:00',
reserveTime: '2023-06-20 12:12:00',
name: '张三',
price: '198',
isFinished: false,
conboId: 12,
conboName: '个人保健健康体检男女通用套餐',
count: 22
}]
}) })
watch(() => store.state.handlePromise, (promise) => { watch(() => store.state.handlePromise, (promise) => {
@ -84,8 +66,34 @@ export default {
sessionStorage.removeItem(store.state.prefix + 'title') sessionStorage.removeItem(store.state.prefix + 'title')
}) })
function getRecordList({ patient, begDate, endDate }) {
axios.RGet('/reserveRecord/getReserveRecords', {
begDate: begDate,
endDate: endDate,
name: patient.name,
idCard: patient.idCardNo
}).then(response => {
if (response.code === 200) {
console.log('response.data', response.data)
state.list = response.data
} else {
vant.Toast.fail(response.message)
}
})
}
setTimeout(() => {
getRecordList({
patient: store.getters.getPatient,
begDate: store.getters.getBegDate,
endDate: store.getters.getEndDate
})
}, 150)
return { return {
state, state,
getRecordList
} }
}, },
} }

@ -10,6 +10,7 @@
label="身份证号" label="身份证号"
name="idCardNo" name="idCardNo"
autofocus autofocus
:readonly="true"
maxLength="18" maxLength="18"
placeholder="请填写身份证号码" placeholder="请填写身份证号码"
:border="false" :border="false"
@ -18,6 +19,7 @@
<van-field class="input" <van-field class="input"
v-model="patient.name" v-model="patient.name"
:readonly="true"
label="姓&emsp;&emsp;名" label="姓&emsp;&emsp;名"
name="name" name="name"
maxLength="18" maxLength="18"
@ -26,16 +28,18 @@
:rules="[{ required: true, message: '必填' }]"> :rules="[{ required: true, message: '必填' }]">
</van-field> </van-field>
<div style="margin: 16px 0; width:100%;text-align:center;"> <div style="margin: 16px 0; width:100%;text-align:center;">
<span @click="onClick()" <van-button round type="primary"
style="color:var(--color-primary)">{{text}}</span> @click.prevent.stop="onClick()"
style="width:160px; height:30px;padding: 0 10px;">人脸识别</van-button>
</div> </div>
</van-form> </van-form>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { Go } from '@/utils/common-util.mjs'
export default { export default {
data() { data() {
@ -79,4 +83,10 @@ export default {
} }
}, },
} }
</script> </script>
<style>
.card__box{
}
</style>

@ -383,7 +383,7 @@ export default {
use: form.useWay, use: form.useWay,
phone: form.phone, phone: form.phone,
} }
axios.post('wx/record/upload', params).then(response => { axios.post('/wx/record/upload', params).then(response => {
if (response.code === 200) { if (response.code === 200) {
vant.Toast.success('预约成功') vant.Toast.success('预约成功')
resetForm() resetForm()

@ -119,7 +119,7 @@ export default {
function getHistory() { function getHistory() {
patient.value = store.getters.getPatient patient.value = store.getters.getPatient
if (!patient.value || (patient.value && !patient.value.patientId)) return vant.Toast.fail('患者参数缺失,无法查询翻拍记录!') if (!patient.value || (patient.value && !patient.value.patientId)) return vant.Toast.fail('患者参数缺失,无法查询翻拍记录!')
axios.RGet('wx/record/listByPatientId', { axios.RGet('/wx/record/listByPatientId', {
patientId: patient.value.patientId, patientId: patient.value.patientId,
}).then(response => { }).then(response => {
if (response.code === 200) { if (response.code === 200) {

@ -1,201 +1,40 @@
<template> <template>
<div style="position: relative;"> <div style="position: relative;">
<transition-group mode="out-in"> <transition-group mode="out-in">
<OLDoctState key="head"
v-model:show="retry.dialog.show"
:showUsers="info.showUsers"
:setting="setting"
:retry="retry"
:isTipErr="retry.dialog.isTipErr"
:setOLState="onSetOLState"
:HDisConnect="HDisConnect"
:practising="info.practising"
@dialogConfirm="onDialogConfirm"></OLDoctState>
<section key="1" <section key="1"
v-show="info.showUsers"> v-show="info.showUsers">
<section class="header__wrap">
<div class="header__btn"
@click="onBack">
<svg t="1618975131673"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="3215"
width="14"
height="14">
<path d="M778.671 926.323a56.811 56.811 0 1 1-80.33 80.331L243.85 552.165a56.811 56.811 0 0 1 0-80.33l454.49-454.49a56.811 56.811 0 1 1 80.33 80.331L364.348 512 778.67 926.323z"
p-id="3216"
fill="#ffffff"></path>
</svg>
</div>
<div style="display: flex;">
<van-popover v-model:show="setting.show">
<section style="width:150px;min-height: 100px;">
<div class="setting-line-item"
style="border-bottom: 1px solid #E6E8EB;">
<span>工号</span>
<span>{{ setting.doctCode }}</span>
</div>
<div class="setting-line-item"
@click="updateIFAccepted(true, 1);">
<div style="background-color: #67C23A;border-radius: 50%;width: 14px;height: 14px;"></div>
<span style="margin-left: 8px;">在线</span>
</div>
<div class="setting-line-item"
@click="updateIFAccepted(true, 0)">
<svg t="1673753531710"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="5550"
width="14"
height="14">
<path d="M512 51.2c-254.464 0-460.8 206.336-460.8 460.8s206.336 460.8 460.8 460.8 460.8-206.336 460.8-460.8-206.336-460.8-460.8-460.8z m280.064 740.864c-74.24 74.24-175.104 116.224-280.064 115.712-104.96 0-205.824-41.472-280.064-115.712-74.24-74.24-116.224-175.104-116.224-280.064s41.472-205.824 116.224-280.064C306.176 157.696 407.04 115.712 512 116.224c104.96 0 205.824 41.472 280.064 116.224 74.24 74.24 116.224 175.104 115.712 280.064 0.512 104.448-41.472 205.312-115.712 279.552z"
fill="#d81e06"
p-id="5551"></path>
<path d="M837.12 232.448l-604.16 604.16c-12.8 12.8-33.28 12.8-45.568 0-12.8-12.8-12.8-33.28 0-45.568l604.16-604.16c12.8-12.8 33.28-12.8 45.568 0 12.288 12.8 12.288 33.28 0 45.568z"
fill="#d81e06"
p-id="5552"></path>
</svg>
<span style="margin-left: 8px;">离线</span>
</div>
<div class="setting-line-item"
@click="openWorkload">
<van-icon name="chart-trending-o"
size="18" />
<span style="margin-left: 6px;">统计</span>
</div>
</section>
<template #reference>
<div style="margin-right: 5px;text-align: right;padding: 0 5px;">
<div style="color: #606266;">{{ setting.name }}</div>
<div style="display: flex;align-items: center;margin-top: 6px;">
<svg v-if="!setting.ifAccepted"
t="1673753531710"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="5550"
width="14"
height="14">
<path d="M512 51.2c-254.464 0-460.8 206.336-460.8 460.8s206.336 460.8 460.8 460.8 460.8-206.336 460.8-460.8-206.336-460.8-460.8-460.8z m280.064 740.864c-74.24 74.24-175.104 116.224-280.064 115.712-104.96 0-205.824-41.472-280.064-115.712-74.24-74.24-116.224-175.104-116.224-280.064s41.472-205.824 116.224-280.064C306.176 157.696 407.04 115.712 512 116.224c104.96 0 205.824 41.472 280.064 116.224 74.24 74.24 116.224 175.104 115.712 280.064 0.512 104.448-41.472 205.312-115.712 279.552z"
fill="#d81e06"
p-id="5551"></path>
<path d="M837.12 232.448l-604.16 604.16c-12.8 12.8-33.28 12.8-45.568 0-12.8-12.8-12.8-33.28 0-45.568l604.16-604.16c12.8-12.8 33.28-12.8 45.568 0 12.288 12.8 12.288 33.28 0 45.568z"
fill="#d81e06"
p-id="5552"></path>
</svg>
<div v-else
style="background-color: #67C23A;border-radius: 50%;width: 14px;height: 14px;"></div>
<div style="font-size: 14px;margin-left: 5px;color: #909399;">{{ !setting.ifAccepted ? '离线' : '在线' }}</div>
</div>
</div>
</template>
</van-popover>
<van-image :width="42"
:height="42"
:radius="5"
:src="setting.avatar" />
</div>
</section>
<transition mode="out-in"> <transition mode="out-in">
<section v-if="(tabActive === 'message' || tabActive === 'end')" <OLUserList v-if="(tabActive === 'message' || tabActive === 'end')"
class="user-list__wrap"> :info="info"
<van-search v-model="search" :setting="setting"
placeholder="请输入搜索关键词" /> :tabActive="tabActive"
<transition mode="out-in"> :userList="userList"
<div v-if="info.showUsersData"> @click-user="onClickUser"
<van-empty v-if="!userList || userList.length === 0" @close-order="onCloseOrder"></OLUserList>
image-size="6rem"
description="暂无聊天信息" />
<van-swipe-cell v-for="(item, i) in userList.filter(data => !search || data.name.toLowerCase().includes(search.toLowerCase()))"
:key="i"
stop-propagation
@click="onClickUser($event, i, item)">
<div style="border-bottom: 1px solid var(--border-a);margin: 0;background-color: @white;">
<div class="user-item__box">
<van-badge :content="!item.unreadCount ? null : item.unreadCount"
color="var(--color-danger)">
<div v-if="!item.avatar && item.name"
class="user-item--avatar--err">{{ item.name.substring(0, 1) }}</div>
<van-image v-else
:width="50"
:height="50"
class="user-item--avatar"
:src="item.avatar">
<template #error>
<div v-if="item.name"
class="user-item--avatar--err">{{ item.name.substring(0, 1) }}</div>
</template>
</van-image>
</van-badge>
<div style="width: 100%;padding: 0px 8px;overflow: hidden;display: flex;flex-direction: column;justify-content: space-evenly;">
<div style="font-size: 13px;font-weight: bold;color: var(--text-b);">{{ item.name }}</div>
<div style="width: 100%;height: 22px; line-height: 22px; display: flex; justify-content: space-between;align-items: center;overflow: hidden;">
<div class="user-item--msg-content">{{ getTipTag(item) }}</div>
<div class="user-item--msg-time">{{ getShowTime(item.tipTime) }}</div>
</div>
</div>
</div>
<div style="padding: 3px 18px 5px 10px;display: flex;justify-content: space-between;align-items: center;">
<div style="color: var(--text-b);font-size: 13px;">{{ DateUtil.format(item.orderTime, 'yyyy-MM-dd HH:mm:ss') }}</div>
<div style="color: var(--text-b);font-size: 13px;">NO{{ item.orderId }}</div>
</div>
</div>
<template #right>
<template v-if="item.orderState === 0">
<van-button square
style="height: 100%;width: 90px;"
icon="stop-circle-o"
type="danger"
text="结束订单"
:disabled="info.closeDisabled"
@click="closeOrder(item.orderId)">
<template #icon>
<svg t="1676513693561"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2918"
width="24"
height="24">
<path d="M512 469.35c-15.26 0-27.63-12.37-27.63-27.63V151.83c0-15.26 12.37-27.63 27.63-27.63s27.63 12.37 27.63 27.63v289.89c0 15.26-12.37 27.63-27.63 27.63z"
p-id="2919"></path>
<path d="M643.26 215.69c0 10.19 5.54 19.67 14.6 24.33 106 54.54 177.82 166.49 173.92 294.54-4.98 163.38-136.02 299.05-299.15 309.34-185.71 11.7-340.56-136.05-340.56-319.29 0-123.92 70.86-231.53 174.16-284.64 9.03-4.64 14.51-14.16 14.51-24.32 0-20.48-21.65-34.21-39.86-24.84-129.5 66.65-215.46 206.41-202.85 364.41C152.64 738.43 301.58 885.9 484.9 898.85c219.08 15.47 402.3-158.39 402.3-374.23 0-145.17-82.9-271.31-203.82-333.66-18.31-9.44-40.12 4.14-40.12 24.73z"
p-id="2920"></path>
</svg>
</template>
</van-button>
</template>
</template>
</van-swipe-cell>
</div>
</transition>
</section>
<OLSetting v-else-if="tabActive === 'setting'" <OLSetting v-else-if="tabActive === 'setting'"
:setting="setting" :setting="setting"
:doctKey="info.doctKey" :doctKey="info.doctKey"
:userId="info.userId" :userId="info.userId"
:deptCode="info.deptCode" :deptCode="info.deptCode"
:updateIFAccepted="updateIFAccepted"
:HUpdateState="HUpdateState"></OLSetting> :HUpdateState="HUpdateState"></OLSetting>
</transition> </transition>
<van-tabbar v-model="tabActive" <van-tabbar v-model="tabActive"
placeholder placeholder
safe-area-inset-bottom safe-area-inset-bottom
@change="onTabChange" @change="getUserList()"
style="height: 30px;"> style="height: 30px;">
<van-tabbar-item icon="chat-o" <van-tabbar-item icon="chat-o"
name="message">进行中</van-tabbar-item> name="message">进行中</van-tabbar-item>
@ -243,7 +82,7 @@
<van-button class="header__btn" <van-button class="header__btn"
:disabled="info.closeDisabled" :disabled="info.closeDisabled"
style="margin:0;color: red;background-color: #fff;" style="margin:0;color: red;background-color: #fff;"
@click="closeOrder(info.curUser.orderId)"> @click="onCloseOrder(info.curUser.orderId)">
<template #icon> <template #icon>
<svg t="1676513693561" <svg t="1676513693561"
class="icon" class="icon"
@ -294,7 +133,6 @@
</template> </template>
</template> </template>
</ChatMessage> </ChatMessage>
</div> </div>
<div v-if="msgList.length === 0" <div v-if="msgList.length === 0"
@ -313,14 +151,15 @@
</transition> </transition>
</section> </section>
</section> </section>
<OLMessage :user="info.curUser"
:setting="setting" <OLMsgInput :user="info.curUser"
:userId="info.userId" :setting="setting"
:disabled="tabActive === 'end'" :userId="info.userId"
@text="info.content = $event" :disabled="tabActive === 'end'"
@cancelRevoke="cancelRevoke" @text="info.content = $event"
:onSend="onSend" @cancelRevoke="cancelRevoke"
:deptCode="info.deptCode"> :onSend="onSend"
:deptCode="info.deptCode">
<div class="online__footer-input"> <div class="online__footer-input">
<van-field v-show="false" <van-field v-show="false"
v-model="info.test" v-model="info.test"
@ -342,52 +181,29 @@
:disabled="tabActive === 'end' || info.sendDisabled" :disabled="tabActive === 'end' || info.sendDisabled"
style="width:80px;height: 34px;margin-left: 8px;">发送</van-button> style="width:80px;height: 34px;margin-left: 8px;">发送</van-button>
</div> </div>
</OLMessage> </OLMsgInput>
</section> </section>
</transition-group> </transition-group>
<DialogWorkload v-model:show="setting.showWorkload"
:doct-code="setting.doctCode"></DialogWorkload>
<van-dialog v-model:show="retry.show"
title="提示"
width="266px"
:close-on-click-modal="false"
draggable>
<div style="padding: 10px 16px;min-height: 60px;font-size: 14px;">{{ retry.title }}</div>
<template #footer>
<span class="dialog-footer">
<van-button @click="retry.show = false"
style="width: 50%;"></van-button>
<van-button type="primary"
:loading="retry.loading"
@click="retry.confirm"
style="width: 50%;">
<span><span v-if="retry.second > 0">{{ retry.second }}s</span></span>
</van-button>
</span>
</template>
</van-dialog>
</div> </div>
</template> </template>
<script> <script>
import { route, store, router } from 'vue-helper' import { store } from 'vue-helper'
import { ref, reactive, watch } from 'vue' import { ref, reactive, watch } from 'vue'
import { HCreateWebSocket, HGetUserInfo, HLookUserMsg, HSendMsg, HRepeat, HUpdateState } from '@/hooks/hook-websocket.mjs' import { HCreateWebSocket, HGetUserInfo, HLookUserMsg, HSendMsg, HRepeat, HUpdateState, HSendAdmin, JsonToArr, JsonByKey, UserListTipTag, HDisConnect } from '@/hooks/hook-websocket.mjs'
import { WxBack, GoBind, GoMe, Back } from '@/utils/common-util.mjs'
import DateUtil from '@/utils/date-util.mjs' import DateUtil from '@/utils/date-util.mjs'
import { axios, OL_WS_URL, UPLOAD_URL } from 'axios' import { axios, OL_WS_URL, UPLOAD_URL } from 'axios'
import OLMessage from '@/views/online/online-doctor/components/ol-message.vue' import OLMsgInput from '@/views/online/online-doctor/components/ol-msg-input.vue'
import OLSetting from '@/views/online/online-doctor/components/ol-setting.vue'
import DialogWorkload from '@/views/online/online-doctor/components/dialog-workload.vue'
import ChatMessage from '@/views/online/components/chat-message.vue' import ChatMessage from '@/views/online/components/chat-message.vue'
import OLSetting from '@/views/online/online-doctor/components/ol-user/ol-setting.vue'
import OLDoctState from '@/views/online/online-doctor/components/ol-user/ol-user-state.vue'
import OLUserList from '@/views/online/online-doctor/components/ol-user/ol-user-list.vue'
import URLUtil from '@/utils/url-util.mjs' import URLUtil from '@/utils/url-util.mjs'
export default { export default {
components: { OLMessage, OLSetting, DialogWorkload, ChatMessage }, components: { OLMsgInput, OLSetting, OLDoctState, OLUserList, ChatMessage },
props: { props: {
work: Object, work: Object,
}, },
@ -396,20 +212,19 @@ export default {
const loading = ref(false) const loading = ref(false)
const tabActive = ref('message') const tabActive = ref('message')
const setting = reactive({ const setting = reactive({
show: false, show: false,
isInit: true, isInit: true,
ifAccepted: 0, ifAccepted: 0,
onlineState: 0,
everyDayNum: 0, everyDayNum: 0,
doctCode: '', doctCode: '',
avatar: '', avatar: '',
name: '', name: '',
showWorkload: false,
showRevoke: false, // showRevoke: false, //
}) })
console.log('props', props) console.log('props.work', props.work)
const info = reactive({ const info = reactive({
test: 'test', test: 'test',
@ -432,48 +247,23 @@ export default {
showUsersData: true, showUsersData: true,
sendDisabled: false, sendDisabled: false,
closeDisabled: false, closeDisabled: false,
patientName: '' patientName: '',
practising: { //
practisingScopeCode: props.work.doctor.practisingScopeCode,
practisingScopeName: props.work.doctor.practisingScopeName,
practisingTypeCode: props.work.doctor.practisingTypeCode,
practisingTypeName: props.work.doctor.practisingTypeName
}
}) })
//
const retry = reactive({ const retry = reactive({
show: false, // dialog: {
state: true, // isTipErr: false,
title: '', // show: false,
loading: false, //
cacheSecond: 30, // s
cacheRetryNum: 3, // 线
second: 0, // 线s
retryNum: 3, // 线
closeTitle: '检测到和服务器的连接已断开,是否重新连接?', //
errorTitle: '建立连接失败,是否重试?', //
timeInterval: null,
beg: (title) => {
if (retry.timeInterval) return
retry.show = true
retry.second = retry.cacheSecond
retry.title = !title ? retry.errorTitle : title
if (retry.retryNum > 0) {
retry.timeInterval = setInterval(() => {
retry.second--
if (!retry.second) {
clearInterval(retry.timeInterval)
retry.timeInterval = null
retry.confirm()
retry.show = false
retry.retryNum--
}
}, 1000)
} else {
retry.second = 0
}
},
confirm: () => {
//
retry.second = retry.cacheSecond
retry.loading = true
HRepeat()
}, },
connectState: false, //
loading: false, //
}) })
const msgBoxRef = ref() const msgBoxRef = ref()
@ -487,48 +277,59 @@ export default {
}, 200) }, 200)
} }
const audio = null //
function disconnectTip(isTipErr) {
if (isTipErr === null || isTipErr === undefined) isTipErr = false
retry.state = false // 线
retry.dialog.btnLoading = false
retry.dialog.isTipErr = isTipErr
retry.dialog.show = true
}
const audio = null
const { msgList, userList } = HCreateWebSocket(`${OL_WS_URL}/micro/ws`, { const { msgList, userList } = HCreateWebSocket(`${OL_WS_URL}/micro/ws`, {
userId: info.userId, userId: info.userId,
device: 2, device: 2,
toEnd: toEnd, toEnd: toEnd,
uploadImg: (o) => axios.post('/micro/online/uploadImg', o), uploadImg: (o) => axios.post('/micro/online/uploadImg', o),
success: () => { success: () => {
console.log('success-----------------------------');
retry.state = true retry.state = true
retry.show = false retry.dialog.show = false
retry.loading = false retry.dialog.btnLoading = false
retry.retryNum = retry.cacheRetryNum // retry.retryNum = retry.cacheRetryNum //
getUserList() getUserList()
}, },
error: (e) => { error: (e) => {
console.log('error2') vant.Notify('【建立连接失败,请重试!】' + (e.message ?? ''))
// console.log(e); disconnectTip(true)
retry.state = false
retry.loading = false
retry.beg(retry.errorTitle)
vant.Notify('【建立连接失败,请刷新重试】' + (e && e.message ? e.message : ''))
}, },
onClose: (e) => { onClose: (e) => {
console.log('close2') disconnectTip(false)
retry.state = false
retry.beg(retry.closeTitle)
}, },
onNotify: (action, data, isWin) => { onNotify: (action, data, isWin) => {
console.log('[notify]=', action, isWin) console.log('[notify]_', action, isWin)
if (action === 3) { if (action === 3) {
setTimeout(() => { setTimeout(() => {
loading.value = false loading.value = false
}, 100) }, 100)
} else if (action === 102) { } else if (action === 102) {
// return tableRowIndex.value = 0 // return tableRowIndex.value = 0
} else if (action === 3) {
setTimeout(() => { } else if (action === 4) { // 使
loading.value = false vant.Toast.clear()
}, 100) vant.Dialog.alert({ title: '提示', message: '检测到当前账户已在登录中,是否确认使其强制下线?', showCancelButton: true, confirmButtonText: '是', cancelButtonText: '否' })
.then(() => { HSendAdmin({ action: 5 }) }).catch(() => { })
} else if (action === 5) { // 线
console.log('action=======5=====被强制断线')
vant.Dialog.alert({ title: '提示', message: '您已被强制挤下线,如不是您本人操作,请联系管理员确认', showCancelButton: false, confirmButtonText: '确 定' })
.then(() => { })
} else if (action === 10001) { } else if (action === 10001) {
info.patientInfo = !data ? {} : data info.patientInfo = !data ? {} : data
info.patientInfo.toUserId = info.toUserId info.patientInfo.toUserId = info.toUserId
} else if (action === 100) { } else if (action === 100) {
if (info.isMusic && audio) audio.play() if (info.isMusic && audio) audio.play()
@ -544,16 +345,11 @@ export default {
info.sendDisabled = true info.sendDisabled = true
getUserList() getUserList()
} else if (action === 20002) { } else if (action === 20002) { //
data = JSON.parse(data) userState.onlineState = JsonByKey('onlineState', data, userState.onlineState)
if (data && data.ifAccepted !== undefined && data.ifAccepted !== null) {
setting.ifAccepted = data.ifAccepted } else if (action === 20003) { //
} userState.everyDayNum = JsonByKey('everyDayNum', data, userState.everyDayNum)
} else if (action === 20003) {
data = JSON.parse(data)
if (data && data.everyDayNum !== undefined && data.everyDayNum !== null) {
setting.everyDayNum = data.everyDayNum
}
} }
} }
}) })
@ -586,7 +382,7 @@ export default {
}, 200); }, 200);
setting.doctCode = resp.data.doctCode setting.doctCode = resp.data.doctCode
setting.ifAccepted = !resp.data.ifAccepted ? 0 : resp.data.ifAccepted setting.onlineState = !resp.data.onlineState ? 0 : resp.data.onlineState
setting.everyDayNum = !resp.data.everyDayNum ? 0 : resp.data.everyDayNum setting.everyDayNum = !resp.data.everyDayNum ? 0 : resp.data.everyDayNum
const avatar = !resp.data.avatar ? store.getters.getAvatar : (resp.data.avatar.indexOf('data:image/') !== -1) ? resp.data.avatar : UPLOAD_URL + resp.data.avatar const avatar = !resp.data.avatar ? store.getters.getAvatar : (resp.data.avatar.indexOf('data:image/') !== -1) ? resp.data.avatar : UPLOAD_URL + resp.data.avatar
@ -599,11 +395,6 @@ export default {
}) })
} }
function onTabChange(v) {
getUserList()
}
function getShowTime(val) { function getShowTime(val) {
if (!val) return if (!val) return
return DateUtil.format(val, DateUtil.isToday(val) ? 'HH:mm' : 'yyyy/MM/dd HH:mm') return DateUtil.format(val, DateUtil.isToday(val) ? 'HH:mm' : 'yyyy/MM/dd HH:mm')
@ -678,48 +469,20 @@ export default {
} }
function getTipTag(rowData) {
if (rowData.cacheContent) {
rowData.cacheContent = rowData.cacheContent.trim()
if (rowData.cacheContent) {
return `<span style="color:red;">[草稿]</span>${rowData.cacheContent}`
}
}
const tip = (!rowData.unreadText ? (rowData.tipContent) : rowData.unreadText)
if (!tip) return ''
if (tip === 'tip') return '[提示]'
if (tip.indexOf('/upload/') !== -1 || tip === 'image') return '[图片]'
if (tip === 'symptom') return '[症状描述]'
return tip
}
/**
* 返回退出
*/
function onBack() {
console.log('back-------------------');
// WxBack(route, store, router, true)
Back(true)
}
function onBackMsg() { function onBackMsg() {
info.showUsers = true info.showUsers = true
document.title = sessionStorage.getItem('ynxbd-micro-web-dom-title') document.title = sessionStorage.getItem('ynxbd-micro-web-dom-title')
} }
function updateIFAccepted(isRepeat, val) { function onSetOLState(isRepeat, val) {
if (isRepeat && setting.ifAccepted === val) return if (isRepeat && setting.onlineState === val) return
if (!info.doctKey) return vant.Toast.fail('医生编码为空,请刷新重试!') if (!info.doctKey) return vant.Toast.fail('医生编码为空,请刷新重试!')
axios.post(`/micro/online_doctor/setOLState`, { axios.post(`/micro/online_doctor/setOLState`, { doctKey: info.doctKey, }).then((resp) => {
doctKey: info.doctKey,
}).then((resp) => {
if (resp.code === 200) { if (resp.code === 200) {
setting.ifAccepted = val setting.onlineState = val
HUpdateState({ action: 20002, content: { ifAccepted: val } }) HUpdateState({ action: 20002, content: { onlineState: val } })
if (!val) { if (!val) {
if (resp.data && resp.data.onlineOrderSize) { if (resp.data && resp.data.onlineOrderSize) {
@ -738,7 +501,7 @@ export default {
} }
// //
function closeOrder(orderId) { function onCloseOrder(orderId) {
if (!orderId) return vant.Toast.fail('参数缺失,禁止结束订单!') if (!orderId) return vant.Toast.fail('参数缺失,禁止结束订单!')
vant.Dialog.confirm({ vant.Dialog.confirm({
@ -777,10 +540,7 @@ export default {
onSend({ content, msgType, sendId }) onSend({ content, msgType, sendId })
} }
function openWorkload() {
setting.showWorkload = true
setting.show = false
}
/** /**
* 启动撤销确认撤销 * 启动撤销确认撤销
@ -790,13 +550,9 @@ export default {
if (setting.showRevoke) { if (setting.showRevoke) {
if (revokeMsg.value) { // if (revokeMsg.value) { //
if (new Date().getTime() - new Date(revokeMsg.value.createTime).getTime() > 1000 * 60 * 5) { // if (new Date().getTime() - new Date(revokeMsg.value.createTime).getTime() > 1000 * 60 * 5) { //
vant.Toast.fail('已超过可撤销时间,无法撤销!') return vant.Toast.fail('已超过可撤销时间,无法撤销!')
return
} }
vant.Dialog.confirm({ vant.Dialog.confirm({ title: '提示', message: '确定撤销所选消息吗?消息一旦撤销后将无法恢复!' }).then(() => {
title: '提示',
message: '确定撤销所选消息吗?消息一旦撤销后将无法恢复!'
}).then(() => {
HSendMsg({ HSendMsg({
id: revokeMsg.value.id, id: revokeMsg.value.id,
toUserId: info.toUserId, toUserId: info.toUserId,
@ -846,9 +602,16 @@ export default {
return null return null
} }
function onDialogConfirm() {
retry.dialog.btnLoading = true
HRepeat()
}
return { return {
UPLOAD_URL, UPLOAD_URL,
OL_WS_URL, OL_WS_URL,
UserListTipTag,
HDisConnect,
DateUtil, DateUtil,
tabActive, tabActive,
search, search,
@ -862,17 +625,15 @@ export default {
retry, retry,
getShowTime, getShowTime,
onClickUser, onClickUser,
getUserList,
onSend, onSend,
toEnd, toEnd,
onBack,
onBackMsg, onBackMsg,
updateIFAccepted, onSetOLState,
closeOrder, onCloseOrder,
getTipTag,
onConfirmSymptom, onConfirmSymptom,
onTabChange, onDialogConfirm,
reSend, reSend,
openWorkload,
confirmRevoke, confirmRevoke,
cancelRevoke, cancelRevoke,
revokeCheckClick, revokeCheckClick,
@ -883,102 +644,6 @@ export default {
</script> </script>
<style scoped> <style scoped>
.header__wrap {
background-color: #fff;
display: flex;
align-items: center;
justify-content: space-between;
padding: 5px 16px 3px 16px;
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.1);
border-bottom: 1px solid var(--border-d);
box-sizing: border-box;
height: 50px;
}
.header__btn {
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
padding: 4px;
border-radius: 9px;
background: rgba(0, 0, 0, 0.15);
}
.user-list__wrap {
background: #fff;
height: calc(100vh - 100px);
box-sizing: border-box;
overflow-y: auto;
overflow-x: hidden;
width: 100vw;
max-width: 767px;
/* padding-bottom: 50px; */
}
.user-item__box {
display: flex;
border-bottom: 1px solid var(--border-d);
padding: 9px 10px 0;
}
.user-item--avatar {
flex-shrink: 0;
width: 50px;
height: 50px;
box-sizing: border-box;
border-radius: 5px;
}
.user-item--avatar--err {
font-size: 18px;
font-weight: bold;
width: 100%;
height: 100%;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
border-radius: 5px;
background-color: #409eff;
border: 1px solid var(--border-c);
color: #fff;
box-sizing: border-box;
height: 50px;
width: 50px;
}
.user-item--avatar :deep(img) {
border-radius: 4px;
border: 1px solid var(--border-d);
/* border: 1px solid red; */
box-sizing: border-box;
}
.user-item--msg-time {
color: var(--text-c);
font-size: 12px;
min-width: 110px;
text-align: right;
margin-left: 5px;
}
.user-item--msg-content {
color: var(--text-c);
font-size: 13px;
color: #909399;
font-size: 13px;
margin-right: 6px;
overflow: hidden;
text-overflow: ellipsis;
/* display: -webkit-box; */
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
height: 30px;
margin-top: 6px;
}
.header-state__box { .header-state__box {
text-align: center; text-align: center;
font-size: 13px; font-size: 13px;
@ -988,28 +653,6 @@ export default {
border-radius: 3px; border-radius: 3px;
} }
.van-swipe-cell__right {
display: inline-block;
width: 65px;
height: 44px;
font-size: 15px;
line-height: 44px;
color: #fff;
text-align: center;
background-color: #f44;
}
.setting-line-item {
padding: 8px 10px;
display: flex;
align-items: center;
cursor: pointer;
}
.setting-line-item:hover {
background-color: var(--border-c);
}
.msg__wrap { .msg__wrap {
box-sizing: border-box; box-sizing: border-box;
background: rgb(245, 245, 245); background: rgb(245, 245, 245);
@ -1042,17 +685,6 @@ export default {
padding: 5px 10px; padding: 5px 10px;
} }
.online__middle-header {
height: 40px;
border-bottom: 1px solid #dcdfe6;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px;
box-sizing: border-box;
}
.msg-item-time { .msg-item-time {
margin: 8px 0; margin: 8px 0;
text-align: center; text-align: center;
@ -1072,4 +704,30 @@ export default {
align-items: center; align-items: center;
box-sizing: border-box; box-sizing: border-box;
} }
.header__btn {
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
padding: 4px;
border-radius: 9px;
background: rgba(0, 0, 0, 0.15);
}
.list-leave-to {
opacity: 0;
transform: translateY(10px);
}
.list-enter-from {
opacity: 1;
transform: translateY(10px);
}
.list-enter-active,
.list-leave-active {
transition: all 0.2s ease;
}
</style> </style>

@ -1,316 +0,0 @@
<template>
<div>
<div class="msg__wrap">
<section class="online__footer"
ref="footerRef">
<section style="margin-bottom: 8px;display: flex;justify-content: space-between;">
<div class="online-footer-item"
style="margin-left: 4px;">
<van-icon name="photo-o"
size="25"
color="#929292"
@click="choiceImg" />
<div style="margin-top: 2px;">发图片</div>
</div>
<div class="online-footer-item">
<van-popover v-model:show="dialog.showWord"
placement="top"
:show-arrow="false"
style="left: 10px;"
@open="cancelRevoke">
<div style="width: 70vw;min-height: 150px;max-height: 50vh;padding: 10px 16px;overflow-y: auto;overflow-x: hidden;">
<div v-for="(item, i) in info.wordList"
class="word-item"
@click="clickWord(item)"
:key="i">
<span>{{ i + 1 }}</span>
<span>{{ item.content }}</span>
</div>
</div>
<template #reference>
<van-icon name="coupon-o"
color="#929292"
size="25" />
<div style="margin-top: 2px;">常用语</div>
</template>
</van-popover>
</div>
<div class="online-footer-item"
@click="dialog.showTreat = true; cancelRevoke()">
<van-icon name="records"
color="#929292"
size="25" />
<div style="margin-top: 2px;">就诊记录</div>
</div>
<div class="online-footer-item"
@click="dialog.renderAdvEvent = true; dialog.showAdvEvent = true; cancelRevoke()">
<svg t="1677506651832"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="3724"
width="24"
height="24">
<path d="M928.07 721.416L617.879 153.499c-2.762-5.523-6.445-10.125-9.207-14.727-19.328-34.058-55.227-56.148-94.805-56.148-31.296 0-59.829 13.809-80.079 36.816-10.125 8.286-18.41 18.411-23.933 29.457l-304.668 538.46c-7.363 11.965-12.887 24.852-18.41 37.74-13.805 18.408-20.25 40.5-20.25 63.51-0.918 60.75 47.863 111.375 109.535 113.215h359.895c94.809 0 193.297-0.918 279.816 0h25.773c46.023 0 108.613-11.965 109.535-112.293-0.921-22.093-12.886-48.785-23.011-68.113z m-87.445 124.258H830.5h0.922-24.852c-83.762-0.918-179.488 0-271.531 0-95.73 0-194.214 0.924-280.738 0h-78.238c-30.375-0.918-55.227-25.77-54.309-57.066 0-11.963 3.684-23.928 11.047-34.053l2.762-5.525c4.601-11.965 10.125-23.01 16.566-34.057l305.59-538.462 0.922-1.84c2.763-4.605 5.522-9.207 10.125-11.969l4.603-4.601c11.045-12.887 25.772-20.25 40.499-20.25 19.328 0 37.738 11.046 46.941 28.535l2.762 3.679c1.84 2.762 4.602 6.446 6.445 9.207l310.191 567.917v0.918c10.125 18.412 15.645 34.059 15.645 39.578-1.84 55.231-21.168 57.989-55.227 57.989z m0 0"
p-id="3725"></path>
<path d="M508.344 625.689c15.648 0 27.613-11.967 27.613-27.613V303.53c0-15.644-11.965-27.613-27.613-27.613-15.647 0-27.613 11.969-27.613 27.613v294.546c-0.001 15.647 11.965 27.613 27.613 27.613z m0 0M467.844 706.689a36.826 36.826 0 0 0 18.405 31.887 36.826 36.826 0 0 0 36.825 0 36.821 36.821 0 0 0 18.406-31.887 36.826 36.826 0 0 0-18.406-31.891 36.835 36.835 0 0 0-36.825 0 36.827 36.827 0 0 0-18.405 31.891z m0 0"
p-id="3726"></path>
</svg>
<div style="margin-top: 2px;">不良事件</div>
</div>
</section>
<slot></slot>
</section>
<section class="treat">
<van-popup v-model:show="dialog.showTreat"
position="right"
:style="{ height: '100%', 'width': '75%' }">
<div style="font-size: 15px;font-weight: bolder;color: #606266;padding: 10px;">就诊记录</div>
<section v-if="dialog.treatList && dialog.treatList.length > 0">
<van-cell v-for="(treat, k) in dialog.treatList"
:key="k">
<div class="treat_item_time">{{ treat.registerDate }}</div>
<div class="treat_item">
<div>主诉</div>
<div>{{ treat.complaint }}</div>
</div>
<div class="treat_item">
<div>症状</div>
<div>{{ treat.symptom }}</div>
</div>
<div class="treat_item">
<div>诊断</div>
<div>{{ treat.diagnose }}</div>
</div>
<div class="treat_item">
<div>门诊号</div>
<div>{{ treat.mzNum }}</div>
</div>
<div class="treat_item">
<div>医生</div>
<div>{{ treat.doctName }}</div>
</div>
</van-cell>
</section>
<van-empty v-else
:image-size="[60, 40]"
description="暂无就诊记录" />
</van-popup>
</section>
<AdverseEvent v-if="dialog.renderAdvEvent"
v-model:show="dialog.showAdvEvent"
:user="user"
:setting="setting" />
</div>
</div>
</template>
<script>
import { reactive, ref, watch } from 'vue'
import ImageUtil from '@/utils/image-util.mjs'
import { axios } from 'axios'
import AdverseEvent from '@/views/online/components/adverse-event.vue'
export default {
components: { AdverseEvent },
props: {
user: {
type: Object,
default: () => { }
},
setting: {
type: Object,
default: () => { }
},
disabled: {
type: Boolean,
default: false,
},
userId: String,
onSend: Function,
deptCode: String
},
setup(props, context) {
const dialog = reactive({
test: '1',
showTreat: false,
treatList: [],
showPopover: false,
showAdvEvent: false, //
showNew: false,
showWord: false,
showNew: false,
renderAdvEvent: false
})
const info = reactive({
avatar: '',
name: '',
content: '',
//-----------------
index: -1,
test: '你',
disabled: false,
})
const footerRef = ref()
function choiceImg() {
cancelRevoke()
if (props.disabled) return
const input = document.createElement('input')
input.type = 'file'
input.accept = 'image/*'
input.onchange = async function (e) {
const files = e.target.files || e.dataTransfer.files
if (!files || files.length === 0) return vant.Toast('请选择文件')
const resImg = await ImageUtil.compressImage(files[0])
if (props.onSend instanceof Function) props.onSend({
msgType: 'image',
content: resImg.base64,
width: resImg.width,
height: resImg.height,
})
}
input.click()
}
watch(() => dialog.showWord, (v) => {
if (v) {
setTimeout(() => {
const dom = document.querySelector(".van-popover")
if (dom) {
dom.style.top = ''
dom.style.bottom = '130px'
}
}, 50)
getWord()
}
})
function getWord() {
if (!props.userId) return vant.Toast.fail('用户id缺失')
axios.RGet(`/micro/online_common_word/getByUserId`, {
userId: props.userId,
deptCode: props.deptCode
}).then((resp) => {
if (resp.code === 200) {
info.wordList = resp.data
}
})
}
watch(() => dialog.showTreat, (v) => {
if (v) getTreatRecord()
})
function getTreatRecord() {
let patientId, deptCode
if (props.user) {
patientId = props.user.fkUserId
deptCode = props.user.deptCode
}
if (!patientId || !deptCode) return console.log('查询就诊记录参数缺失-----------');
axios.RGet(`/wx/treat/getTreatList.do`, { patientId, deptCode }).then((resp) => {
if (resp.code === 200) {
dialog.treatList = resp.data
}
})
}
function clickWord(item) {
context.emit('text', item.content)
dialog.showWord = false
}
function cancelRevoke() {
context.emit('cancelRevoke')
}
return {
dialog,
info,
footerRef,
choiceImg,
getTreatRecord,
clickWord,
cancelRevoke
}
}
}
</script>
<style scoped>
.online__footer {
border-top: 1px solid var(--border-b);
border-bottom: 1px solid var(--border-b);
background-color: rgb(246, 246, 246);
padding: 10px 8px 22px 8px;
box-shadow: -1px -2px 8px rgba(0, 0, 0, 0.1);
box-sizing: border-box;
}
.online-footer-item {
text-align: center;
font-size: 13px;
color: #929292;
}
.treat .van-cell {
width: calc(100% - 8px);
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
border: 1px solid #ebeef5;
transition: 0.3 time;
margin: 5px 4px;
padding: 10px;
}
.treat_item_time {
text-align: left;
font-weight: bold;
}
.treat_item {
text-align: left;
}
.treat_item div:nth-child(1) {
position: absolute;
color: #606266;
font-weight: bold;
width: 60px;
overflow-wrap: normal;
}
.treat_item div:nth-child(2) {
padding-left: 50px;
min-height: 24px;
}
.treat_item:nth-child(5) div:nth-child(1) {
font-size: 12px;
}
.word-item {
padding: 8px 5px;
border-bottom: 1px solid var(--border-c);
}
.word-item:hover {
background-color: var(--border-b);
}
</style>

@ -0,0 +1,347 @@
<template>
<div>
<div class="msg__wrap">
<section class="online__footer"
ref="footerRef">
<section style="margin-bottom: 8px;display: flex;justify-content: space-between;">
<van-uploader :before-read="onBeforeRead"
:after-read="onAffterRead">
<div class="online-footer-item"
style="margin-left: 4px;">
<van-icon name="photo-o"
size="25"
color="#929292" />
<div style="margin-top: 2px;">发图片</div>
<!-- <van-icon name="photo-o"
size="25"
color="#929292"
@click="choiceImg" />
<div style="margin-top: 2px;">发图片</div> -->
</div>
</van-uploader>
<div class="online-footer-item">
<van-popover v-model:show="dialog.showWord"
placement="top"
:show-arrow="false"
style="left: 10px;"
@open="cancelRevoke">
<div style="width: 70vw;min-height: 150px;max-height: 50vh;padding: 10px 16px;overflow-y: auto;overflow-x: hidden;">
<div v-for="(item, i) in info.wordList"
class="word-item"
@click="clickWord(item)"
:key="i">
<span>{{ i + 1 }}</span>
<span>{{ item.content }}</span>
</div>
</div>
<template #reference>
<van-icon name="coupon-o"
color="#929292"
size="25" />
<div style="margin-top: 2px;">常用语</div>
</template>
</van-popover>
</div>
<div class="online-footer-item"
@click="dialog.showTreat = true; cancelRevoke()">
<van-icon name="records"
color="#929292"
size="25" />
<div style="margin-top: 2px;">就诊记录</div>
</div>
<div class="online-footer-item"
@click="dialog.renderAdvEvent = true; dialog.showAdvEvent = true; cancelRevoke()">
<svg t="1677506651832"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="3724"
width="24"
height="24">
<path d="M928.07 721.416L617.879 153.499c-2.762-5.523-6.445-10.125-9.207-14.727-19.328-34.058-55.227-56.148-94.805-56.148-31.296 0-59.829 13.809-80.079 36.816-10.125 8.286-18.41 18.411-23.933 29.457l-304.668 538.46c-7.363 11.965-12.887 24.852-18.41 37.74-13.805 18.408-20.25 40.5-20.25 63.51-0.918 60.75 47.863 111.375 109.535 113.215h359.895c94.809 0 193.297-0.918 279.816 0h25.773c46.023 0 108.613-11.965 109.535-112.293-0.921-22.093-12.886-48.785-23.011-68.113z m-87.445 124.258H830.5h0.922-24.852c-83.762-0.918-179.488 0-271.531 0-95.73 0-194.214 0.924-280.738 0h-78.238c-30.375-0.918-55.227-25.77-54.309-57.066 0-11.963 3.684-23.928 11.047-34.053l2.762-5.525c4.601-11.965 10.125-23.01 16.566-34.057l305.59-538.462 0.922-1.84c2.763-4.605 5.522-9.207 10.125-11.969l4.603-4.601c11.045-12.887 25.772-20.25 40.499-20.25 19.328 0 37.738 11.046 46.941 28.535l2.762 3.679c1.84 2.762 4.602 6.446 6.445 9.207l310.191 567.917v0.918c10.125 18.412 15.645 34.059 15.645 39.578-1.84 55.231-21.168 57.989-55.227 57.989z m0 0"
p-id="3725"></path>
<path d="M508.344 625.689c15.648 0 27.613-11.967 27.613-27.613V303.53c0-15.644-11.965-27.613-27.613-27.613-15.647 0-27.613 11.969-27.613 27.613v294.546c-0.001 15.647 11.965 27.613 27.613 27.613z m0 0M467.844 706.689a36.826 36.826 0 0 0 18.405 31.887 36.826 36.826 0 0 0 36.825 0 36.821 36.821 0 0 0 18.406-31.887 36.826 36.826 0 0 0-18.406-31.891 36.835 36.835 0 0 0-36.825 0 36.827 36.827 0 0 0-18.405 31.891z m0 0"
p-id="3726"></path>
</svg>
<div style="margin-top: 2px;">不良事件</div>
</div>
</section>
<slot></slot>
</section>
<section class="treat">
<van-popup v-model:show="dialog.showTreat"
position="right"
:style="{ height: '100%', 'width': '75%' }">
<div style="font-size: 15px;font-weight: bolder;color: #606266;padding: 10px;">就诊记录</div>
<section v-if="dialog.treatList && dialog.treatList.length > 0">
<van-cell v-for="(treat, k) in dialog.treatList"
:key="k">
<div class="treat_item_time">{{ treat.registerDate }}</div>
<div class="treat_item">
<div>主诉</div>
<div>{{ treat.complaint }}</div>
</div>
<div class="treat_item">
<div>症状</div>
<div>{{ treat.symptom }}</div>
</div>
<div class="treat_item">
<div>诊断</div>
<div>{{ treat.diagnose }}</div>
</div>
<div class="treat_item">
<div>门诊号</div>
<div>{{ treat.mzNum }}</div>
</div>
<div class="treat_item">
<div>医生</div>
<div>{{ treat.doctName }}</div>
</div>
</van-cell>
</section>
<van-empty v-else
:image-size="[60, 40]"
description="暂无就诊记录" />
</van-popup>
</section>
<AdverseEvent v-if="dialog.renderAdvEvent"
v-model:show="dialog.showAdvEvent"
:user="user"
:setting="setting" />
</div>
</div>
</template>
<script>
import { reactive, ref, watch } from 'vue'
import ImageUtil from '@/utils/image-util.mjs'
import { axios } from 'axios'
import AdverseEvent from '@/views/online/components/adverse-event.vue'
export default {
components: { AdverseEvent },
props: {
user: {
type: Object,
default: () => { }
},
setting: {
type: Object,
default: () => { }
},
disabled: {
type: Boolean,
default: false,
},
userId: String,
onSend: Function,
deptCode: String
},
setup(props, context) {
const dialog = reactive({
test: '1',
showTreat: false,
treatList: [],
showPopover: false,
showAdvEvent: false, //
showNew: false,
showWord: false,
showNew: false,
renderAdvEvent: false
})
const info = reactive({
avatar: '',
name: '',
content: '',
//-----------------
index: -1,
test: '你',
disabled: false,
})
const footerRef = ref()
function choiceImg() {
cancelRevoke()
if (props.disabled) return
const input = document.createElement('input')
input.type = 'file'
input.accept = 'image/*'
input.onchange = async function (e) {
console.log('e', e)
const files = e.target.files || e.dataTransfer.files
if (!files || files.length === 0) return vant.Toast('请选择文件')
const resImg = await ImageUtil.compressImage(files[0])
if (props.onSend instanceof Function) props.onSend({
msgType: 'image',
content: resImg.base64,
width: resImg.width,
height: resImg.height,
})
}
input.click()
}
watch(() => dialog.showWord, (v) => {
if (v) {
setTimeout(() => {
const dom = document.querySelector(".van-popover")
if (dom) {
dom.style.top = ''
dom.style.bottom = '130px'
}
}, 50)
getWord()
}
})
function getWord() {
if (!props.userId) return vant.Toast.fail('用户id缺失')
axios.RGet(`/micro/online_common_word/getByUserId`, {
userId: props.userId,
deptCode: props.deptCode
}).then((resp) => {
if (resp.code === 200) {
info.wordList = resp.data
}
})
}
watch(() => dialog.showTreat, (v) => {
if (v) getTreatRecord()
})
function getTreatRecord() {
let patientId, deptCode
if (props.user) {
patientId = props.user.fkUserId
deptCode = props.user.deptCode
}
if (!patientId || !deptCode) return console.log('查询就诊记录参数缺失-----------');
axios.RGet(`/wx/treat/getTreatList.do`, { patientId, deptCode }).then((resp) => {
if (resp.code === 200) {
dialog.treatList = resp.data
}
})
}
function clickWord(item) {
context.emit('text', item.content)
dialog.showWord = false
}
function cancelRevoke() {
context.emit('cancelRevoke')
}
function onBeforeRead(file) {
return ImageUtil.compressImage(file)
}
function onAffterRead(file) {
if (props.onSend instanceof Function) {
const img_url = file.content
const img = new Image()
img.src = img_url
img.onload = function () {
props.onSend({
msgType: 'image',
content: file.content,
width: img.width,
height: img.height,
})
}
}
}
return {
dialog,
info,
footerRef,
choiceImg,
getTreatRecord,
clickWord,
cancelRevoke,
onBeforeRead,
onAffterRead
}
}
}
</script>
<style scoped>
.online__footer {
border-top: 1px solid var(--border-b);
border-bottom: 1px solid var(--border-b);
background-color: rgb(246, 246, 246);
padding: 10px 8px 22px 8px;
box-shadow: -1px -2px 8px rgba(0, 0, 0, 0.1);
box-sizing: border-box;
}
.online-footer-item {
text-align: center;
font-size: 13px;
color: #929292;
}
.treat .van-cell {
width: calc(100% - 8px);
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
border: 1px solid #ebeef5;
transition: 0.3 time;
margin: 5px 4px;
padding: 10px;
}
.treat_item_time {
text-align: left;
font-weight: bold;
}
.treat_item {
text-align: left;
}
.treat_item div:nth-child(1) {
position: absolute;
color: #606266;
font-weight: bold;
width: 60px;
overflow-wrap: normal;
}
.treat_item div:nth-child(2) {
padding-left: 50px;
min-height: 24px;
}
.treat_item:nth-child(5) div:nth-child(1) {
font-size: 12px;
}
.word-item {
padding: 8px 5px;
border-bottom: 1px solid var(--border-c);
}
.word-item:hover {
background-color: var(--border-b);
}
</style>

@ -1,17 +1,8 @@
<template> <template>
<div style="width: 100%;box-sizing: border-box;"> <div style="width: 100%;box-sizing: border-box;">
<section style="padding: 5px 2px;background-color: #fff;"> <section style="padding: 5px 2px;background-color: #fff;">
<div style="display:flex;align-items: center;margin-top: 10px;">
<span style="flex-shrink: 0;width: 100px;font-size: 14px;text-align: right;">接诊状态</span>
<van-switch v-model="info.ifAccepted"
size="20px"
:active-value="1"
:inactive-value="0"
style="margin-left: 12px;"
@change="updateIFAccepted(false, $event)" />
</div>
<div style="width: 100%;display:flex;align-items: center;margin-top:10px;margin-bottom: 6px;padding-right:10px;box-sizing: border-box;"> <div class="setting-item">
<div style="flex-shrink: 0;width: 100px;font-size: 14px;text-align: right;">限制人数</div> <div style="flex-shrink: 0;width: 100px;font-size: 14px;text-align: right;">限制人数</div>
<van-field v-model="info.everyDayNum" <van-field v-model="info.everyDayNum"
type="number" type="number"
@ -41,7 +32,7 @@ export default {
doctKey: String, doctKey: String,
userId: String, userId: String,
setting: Object, setting: Object,
updateIFAccepted: Function, onSetOLState: Function,
HUpdateState: Function, HUpdateState: Function,
deptCode: String deptCode: String
}, },
@ -49,11 +40,6 @@ export default {
const info = reactive({ const info = reactive({
wordList: [], wordList: [],
everyDayNum: null, everyDayNum: null,
ifAccepted: null
})
watch(() => props.setting.ifAccepted, (v) => {
info.ifAccepted = v
}) })
watch(() => props.setting.everyDayNum, (v) => { watch(() => props.setting.everyDayNum, (v) => {
@ -62,7 +48,6 @@ export default {
if (props.setting) { if (props.setting) {
info.everyDayNum = props.setting.everyDayNum info.everyDayNum = props.setting.everyDayNum
info.ifAccepted = props.setting.ifAccepted
} }
function getData() { function getData() {
@ -102,21 +87,6 @@ export default {
</script> </script>
<style scoped> <style scoped>
.list-leave-to {
opacity: 0;
transform: translateY(10px);
}
.list-enter-from {
opacity: 1;
transform: translateY(10px);
}
.list-enter-active,
.list-leave-active {
transition: all 0.2s ease;
}
.word-item { .word-item {
padding: 8px 5px; padding: 8px 5px;
border-bottom: 1px solid var(--border-c); border-bottom: 1px solid var(--border-c);
@ -125,4 +95,15 @@ export default {
.word-item:hover { .word-item:hover {
background-color: var(--border-b); background-color: var(--border-b);
} }
.setting-item {
width: 100%;
display: flex;
align-items: center;
margin-top: 10px;
margin-bottom: 6px;
padding-right: 10px;
box-sizing: border-box;
}
</style> </style>

@ -0,0 +1,201 @@
<template>
<div>
<section class="user-list__wrap">
<van-search v-model="key"
placeholder="请输入搜索关键词" />
<transition mode="out-in">
<div v-if="info.showUsersData">
<van-empty v-if="!userList || userList.length === 0"
image-size="6rem"
description="暂无聊天信息" />
<van-swipe-cell v-for="(item, i) in userList.filter(data => !key || data.name.toLowerCase().includes(key.toLowerCase()))"
:key="i"
stop-propagation
@click="$emit('click-user', $event, i, item)">
<div style="border-bottom: 1px solid var(--border-a);margin: 0;background-color: @white;">
<div class="user-item__box">
<van-badge :content="!item.unreadCount ? null : item.unreadCount"
color="var(--color-danger)">
<div v-if="!item.avatar && item.name"
class="user-item--avatar--err">{{ item.name.substring(0, 1) }}</div>
<van-image v-else
:width="50"
:height="50"
class="user-item--avatar"
:src="item.avatar">
<template #error>
<div v-if="item.name"
class="user-item--avatar--err">{{ item.name.substring(0, 1) }}</div>
</template>
</van-image>
</van-badge>
<div style="width: 100%;padding: 0px 8px;overflow: hidden;display: flex;flex-direction: column;justify-content: space-evenly;">
<div style="font-size: 13px;font-weight: bold;color: var(--text-b);">{{ item.name }}</div>
<div style="width: 100%;height: 22px; line-height: 22px; display: flex; justify-content: space-between;align-items: center;overflow: hidden;">
<div class="user-item--msg-content">{{ UserListTipTag(item) }}</div>
<div class="user-item--msg-time">{{ getShowTime(item.tipTime) }}</div>
</div>
</div>
</div>
<div style="padding: 3px 18px 5px 10px;display: flex;justify-content: space-between;align-items: center;">
<div style="color: var(--text-b);font-size: 13px;">{{ DateUtil.format(item.orderTime, 'yyyy-MM-dd HH:mm:ss') }}</div>
<div style="color: var(--text-b);font-size: 13px;">NO{{ item.orderId }}</div>
</div>
</div>
<template #right>
<template v-if="item.orderState === 0">
<van-button square
style="height: 100%;width: 90px;"
icon="stop-circle-o"
type="danger"
text="结束订单"
:disabled="info.closeDisabled"
@click="$emit('close-order', item.orderId)">
<template #icon>
<svg t="1676513693561"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2918"
width="24"
height="24">
<path d="M512 469.35c-15.26 0-27.63-12.37-27.63-27.63V151.83c0-15.26 12.37-27.63 27.63-27.63s27.63 12.37 27.63 27.63v289.89c0 15.26-12.37 27.63-27.63 27.63z"
p-id="2919"></path>
<path d="M643.26 215.69c0 10.19 5.54 19.67 14.6 24.33 106 54.54 177.82 166.49 173.92 294.54-4.98 163.38-136.02 299.05-299.15 309.34-185.71 11.7-340.56-136.05-340.56-319.29 0-123.92 70.86-231.53 174.16-284.64 9.03-4.64 14.51-14.16 14.51-24.32 0-20.48-21.65-34.21-39.86-24.84-129.5 66.65-215.46 206.41-202.85 364.41C152.64 738.43 301.58 885.9 484.9 898.85c219.08 15.47 402.3-158.39 402.3-374.23 0-145.17-82.9-271.31-203.82-333.66-18.31-9.44-40.12 4.14-40.12 24.73z"
p-id="2920"></path>
</svg>
</template>
</van-button>
</template>
</template>
</van-swipe-cell>
</div>
</transition>
</section>
</div>
</template>
<script>
import { ref } from 'vue'
import { UserListTipTag } from '@/hooks/hook-websocket.mjs'
import DateUtil from '@/utils/date-util.mjs'
export default {
props: {
userList: {
type: Array,
default: () => []
},
info: Object
},
setup() {
const key = ref('')
function getShowTime(val) {
if (!val) return
return DateUtil.format(val, DateUtil.isToday(val) ? 'HH:mm' : 'yyyy/MM/dd HH:mm')
}
return {
UserListTipTag,
DateUtil,
getShowTime,
key,
}
}
}
</script>
<style scoped>
.user-list__wrap {
background: #fff;
height: calc(100vh - 100px);
box-sizing: border-box;
overflow-y: auto;
overflow-x: hidden;
width: 100vw;
max-width: 767px;
/* padding-bottom: 50px; */
}
.user-item__box {
display: flex;
border-bottom: 1px solid var(--border-d);
padding: 9px 10px 0;
}
.user-item--avatar {
flex-shrink: 0;
width: 50px;
height: 50px;
box-sizing: border-box;
border-radius: 5px;
}
.user-item--avatar--err {
font-size: 18px;
font-weight: bold;
width: 100%;
height: 100%;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
border-radius: 5px;
background-color: #409eff;
border: 1px solid var(--border-c);
color: #fff;
box-sizing: border-box;
height: 50px;
width: 50px;
}
.user-item--avatar :deep(img) {
border-radius: 4px;
border: 1px solid var(--border-d);
/* border: 1px solid red; */
box-sizing: border-box;
}
.user-item--msg-time {
color: var(--text-c);
font-size: 12px;
min-width: 110px;
text-align: right;
margin-left: 5px;
}
.user-item--msg-content {
color: var(--text-c);
font-size: 13px;
color: #909399;
font-size: 13px;
margin-right: 6px;
overflow: hidden;
text-overflow: ellipsis;
/* display: -webkit-box; */
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
height: 30px;
margin-top: 6px;
}
.van-swipe-cell__right {
display: inline-block;
width: 65px;
height: 44px;
font-size: 15px;
line-height: 44px;
color: #fff;
text-align: center;
background-color: #f44;
}
</style>

@ -0,0 +1,273 @@
<template>
<div>
<div class="header__wrap">
<transition mode="out-in">
<section v-if="showUsers"
class="header__box">
<div class="header__btn"
@click="onBack">
<svg t="1618975131673"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="3215"
width="14"
height="14">
<path d="M778.671 926.323a56.811 56.811 0 1 1-80.33 80.331L243.85 552.165a56.811 56.811 0 0 1 0-80.33l454.49-454.49a56.811 56.811 0 1 1 80.33 80.331L364.348 512 778.67 926.323z"
p-id="3216"
fill="#ffffff"></path>
</svg>
</div>
<div style="display: flex;">
<van-popover v-model:show="setting.show">
<section style="width:150px;min-height: 100px;">
<div class="setting-line-item"
style="border-bottom: 1px solid #E6E8EB;">
<span>工号</span>
<span>{{ setting.doctCode }}</span>
</div>
<div class="setting-line-item"
style="font-size: 12px;padding: 5px 10px 0;">
<span style="color: var(--text-c);">执业类别</span>
<span>{{ practising.practisingTypeName }}</span>
</div>
<div class="setting-line-item"
style="border-bottom: 1px solid #E6E8EB;font-size: 12px;padding: 5px 10px;">
<span><span style="color: var(--text-c);">执业范围</span>{{ practising.practisingScopeName }}</span>
</div>
<div class="setting-line-item"
@click="setOLState(true, 1);">
<div style="background-color: #67C23A;border-radius: 50%;width: 14px;height: 14px;"></div>
<span style="margin-left: 8px;">在线</span>
</div>
<div class="setting-line-item"
@click="setOLState(true, 0)">
<svg t="1673753531710"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="5550"
width="14"
height="14">
<path d="M512 51.2c-254.464 0-460.8 206.336-460.8 460.8s206.336 460.8 460.8 460.8 460.8-206.336 460.8-460.8-206.336-460.8-460.8-460.8z m280.064 740.864c-74.24 74.24-175.104 116.224-280.064 115.712-104.96 0-205.824-41.472-280.064-115.712-74.24-74.24-116.224-175.104-116.224-280.064s41.472-205.824 116.224-280.064C306.176 157.696 407.04 115.712 512 116.224c104.96 0 205.824 41.472 280.064 116.224 74.24 74.24 116.224 175.104 115.712 280.064 0.512 104.448-41.472 205.312-115.712 279.552z"
fill="#d81e06"
p-id="5551"></path>
<path d="M837.12 232.448l-604.16 604.16c-12.8 12.8-33.28 12.8-45.568 0-12.8-12.8-12.8-33.28 0-45.568l604.16-604.16c12.8-12.8 33.28-12.8 45.568 0 12.288 12.8 12.288 33.28 0 45.568z"
fill="#d81e06"
p-id="5552"></path>
</svg>
<span style="margin-left: 8px;">离线</span>
</div>
<div class="setting-line-item"
@click="openWorkload">
<van-icon name="chart-trending-o"
size="18" />
<span style="margin-left: 6px;">统计</span>
</div>
</section>
<template #reference>
<div style="margin-right: 5px;text-align: right;padding: 0 5px;">
<div style="color: #606266;">{{ setting.name }}</div>
<div style="display: flex;align-items: center;margin-top: 6px;">
<svg v-if="!setting.onlineState"
t="1673753531710"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="5550"
width="14"
height="14">
<path d="M512 51.2c-254.464 0-460.8 206.336-460.8 460.8s206.336 460.8 460.8 460.8 460.8-206.336 460.8-460.8-206.336-460.8-460.8-460.8z m280.064 740.864c-74.24 74.24-175.104 116.224-280.064 115.712-104.96 0-205.824-41.472-280.064-115.712-74.24-74.24-116.224-175.104-116.224-280.064s41.472-205.824 116.224-280.064C306.176 157.696 407.04 115.712 512 116.224c104.96 0 205.824 41.472 280.064 116.224 74.24 74.24 116.224 175.104 115.712 280.064 0.512 104.448-41.472 205.312-115.712 279.552z"
fill="#d81e06"
p-id="5551"></path>
<path d="M837.12 232.448l-604.16 604.16c-12.8 12.8-33.28 12.8-45.568 0-12.8-12.8-12.8-33.28 0-45.568l604.16-604.16c12.8-12.8 33.28-12.8 45.568 0 12.288 12.8 12.288 33.28 0 45.568z"
fill="#d81e06"
p-id="5552"></path>
</svg>
<div v-else
style="background-color: #67C23A;border-radius: 50%;width: 14px;height: 14px;"></div>
<div style="font-size: 14px;margin-left: 5px;color: #909399;">{{ !setting.onlineState ? '离线' : '在线' }}</div>
</div>
</div>
</template>
</van-popover>
<van-image :width="42"
:height="42"
:radius="5"
:src="setting.avatar" />
</div>
</section>
</transition>
</div>
<DialogWorkload v-model:show="dialog.showWorkload"
:doct-code="setting.doctCode"></DialogWorkload>
<van-dialog v-model:show="dialog.show"
title="提示"
width="266px"
:close-on-click-modal="false">
<div style="padding: 10px 16px;min-height: 60px;font-size: 14px;">{{ dialog.title }}</div>
<template #footer>
<span class="dialog-footer">
<van-button @click="dialog.show = false"
style="width: 50%;"></van-button>
<van-button type="primary"
:loading="retry.dialog.btnLoading"
@click="confirm()"
style="width: 50%;">
<span><span v-if="dialog.second > 0">{{ dialog.second }}&nbsp;s</span></span>
</van-button>
</span>
</template>
</van-dialog>
</div>
</template>
<script>
import { reactive, watch, ref } from 'vue'
import { Back } from '@/utils/common-util.mjs'
import DialogWorkload from './dialog-workload.vue'
export default {
components: { DialogWorkload },
props: {
show: Boolean,
showUsers: Boolean,
isTipErr: Boolean,
setting: Object,
retry: Object,
setOLState: Function,
HDisConnect: Function,
practising: Object //
},
setup(props, context) {
watch(() => props.show, (v) => {
if (v) {
showDialog()
} else {
dialog.show = false
}
})
//
const practising = ref(null)
practising.value = props.practising
const dialog = reactive({
show: false,
title: '', // ,
loading: false, //
timeInterval: null,
cacheSecond: 30, // s
cacheRetryNum: 3, // 线
second: 0, // 线s
retryNum: 3, // 线
closeTitle: '检测到和服务器的连接已断开,是否重新连接?', //
errorTitle: '建立连接失败,是否重试?', //
showWorkload: false, //
})
function showDialog() {
if (dialog.timeInterval) return
dialog.show = true
dialog.second = dialog.cacheSecond
dialog.title = props.isTipErr ? dialog.errorTitle : dialog.closeTitle
if (dialog.retryNum > 0) {
dialog.timeInterval = setInterval(() => {
dialog.second--
if (!dialog.second) {
clearInterval(dialog.timeInterval)
dialog.timeInterval = null
confirm()
dialog.show = false
dialog.retryNum--
}
}, 1000);
} else {
dialog.second = 0
}
}
function confirm() {
dialog.second = dialog.cacheSecond
context.emit('dialogConfirm')
}
/**
* 打开统计弹框
*/
function openWorkload() {
dialog.showWorkload = true
props.setting.show = false
}
// 退
function onBack() {
if (props.HDisConnect) props.HDisConnect()
Back(true)
}
return {
dialog,
practising,
onBack,
confirm,
openWorkload,
}
}
}
</script>
<style scoped>
.header__wrap {
background-color: #fff;
width: 100%;
}
.header__box {
display: flex;
align-items: center;
justify-content: space-between;
padding: 5px 16px 3px 16px;
box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.1);
border-bottom: 1px solid var(--border-d);
box-sizing: border-box;
height: 50px;
width: 100%;
}
.header__btn {
width: 20px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
padding: 4px;
border-radius: 9px;
background: rgba(0, 0, 0, 0.15);
}
.setting-line-item {
padding: 8px 10px;
display: flex;
align-items: center;
cursor: pointer;
}
.setting-line-item:hover {
background-color: var(--border-c);
}
</style>

@ -1,25 +1,15 @@
<template> <template>
<div> <div v-if="info.show">
<transition mode="out-in" <transition mode="out-in"
name="van-fade-in-linear"> name="van-fade-in-linear">
<OLDoctor v-if="work.show" <OLDoctor v-if="work.show"
:work="work"></OLDoctor> :work="work"></OLDoctor>
<section v-else>
<section v-if="info.showForm"> <div class="doctor-info__wrap">
<div class="doctor-form"> <div class="doctor-info__header">问诊权限申请</div>
<van-cell-group v-if="false"
inset
style="margin: 8px;">
<div class="explanation">
<span class="expl_title">说明:</span><br />
<div class="expl_content">1根据互联网医院监管平台要求请认真录入并核对确认以下相关信息</div>
<div class="expl_content">2院内审批流程医生提出互联网医院问诊申请 > 科主任审扣 > 医务部审批开放权限</div>
</div>
</van-cell-group>
<van-form @submit="submitForm"> <van-form @submit="submitForm">
<van-cell-group inset <van-cell-group inset
style="margin: 8px;padding: 15px 5px"> style="margin: 8px;padding: 6px;">
<van-field class="required" <van-field class="required"
v-model="work.obtainEmploymentTime" v-model="work.obtainEmploymentTime"
name="obtainEmploymentTime" name="obtainEmploymentTime"
@ -27,10 +17,9 @@
placeholder="从业时间" placeholder="从业时间"
is-link is-link
readonly readonly
@click="chioseDate('obtainEmploymentTime', 'date')" @click="chioseDate('obtainEmploymentTime')"
:rules="[{ required: true, message: '请选择从业时间' }]"> :rules="[{ required: true, message: '请选择从业时间' }]">
</van-field> </van-field>
<van-cell title="医生工号" <van-cell title="医生工号"
:value="work.doctor.doctCode" /> :value="work.doctor.doctCode" />
<van-cell title="证件号码" <van-cell title="证件号码"
@ -41,61 +30,103 @@
:value="work.doctor.showPractisingCertCode" /> :value="work.doctor.showPractisingCertCode" />
<van-cell title="执业类别" <van-cell title="执业类别"
:value="work.doctor.practisingTypeName ? `${work.doctor.practisingTypeName}` : ''" /> :value="work.doctor.practisingTypeName ? `${work.doctor.practisingTypeName}` : ''" />
<van-cell title="执业范围"
:value="work.doctor.practisingScopeName ? `${work.doctor.practisingScopeName}` : ''" /> <van-field class="required"
v-model="work.doctor.practisingScopeName"
name="practisingScopeCode"
label="执业范围"
placeholder="执业范围"
is-link
readonly
@click="chooseOpt('practisingScopeCode', 'practisingScopeName', '执业范围', 'doctorScopeOptions')"
:rules="[{ required: true, message: '请选择执业范围' }]">
</van-field>
<van-cell title="医生职称" <van-cell title="医生职称"
:value="work.doctor.title ? `${work.doctor.title}` : ''" /> :value="work.doctor.title ? `${work.doctor.title}` : ''" />
</van-cell-group> </van-cell-group>
<div style="margin: 16px;display: flex;flex-direction: row;"> <transition mode="out-in">
<van-button block <div v-if="info.showBtn"
@click="onBack" class="footer__box">
style="flex: 2;"> </van-button> <van-button block
<div style="flex: 1;"></div> @click="onBack()"
<van-button block style="flex: 2;"> </van-button>
type="primary" <div style="flex: 1;"></div>
native-type="submit" <van-button block
style="flex: 2;"> </van-button> type="primary"
</div> native-type="submit"
style="flex: 2;"> </van-button>
</div>
<section v-else>
<div style="padding: 8px 32px;">
<div style="display: flex;align-items: center;justify-content: center; width: 100%;box-sizing: border-box;">
<svg t="1693396571961"
style="margin-left: 8px;"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="8683"
width="66"
height="66">
<path d="M540.3 633.7l-0.7 6.9c0 0.7-0.1 1.5-0.1 2.3h-0.1l-3.4-7-3 1.4 7.6 15.4 3-1.6-2.6-5.2 0.4-2.1 6.9 5.1 3.3-1.7-9.3-6.4 1.4-8.9-3.4 1.8zM557.5 645.6c2.6-0.8 4.9-3.4 3.4-8-1.2-3.6-4-5.3-7.4-4.4-3.2 1.1-4.9 4-3.6 8 1.3 3.9 4.4 5.4 7.6 4.4z m-3.2-10c1.7-0.5 3 1.2 3.6 3.1 0.6 2.1 0.4 4.2-1.1 4.6-1.5 0.5-2.9-1-3.6-3.1-0.6-1.8-0.7-4 1.1-4.6zM517.4 648.1l7 16.4 2.5-2.1-1.9-4.3 3.6-2.9 3.8 2.7 2.7-2.1-14.5-10.3-3.2 2.6z m6.2 3.2l3.2 2.4-2.9 2.3-1.7-3.8c-0.5-1-1.1-2.3-1.5-3.2 0.8 0.7 1.9 1.5 2.9 2.3zM568.6 632.8c0.4 0 0.6-0.1 0.8-0.1l-0.6-3.1c-0.2 0-0.5 0-0.7 0.1-1.2 0.2-2.3 1.3-2.6 3h-0.1l-0.5-2-2.7 0.5c0.2 1.1 0.6 2.3 0.8 3.8l1.6 8.3 3.2-0.6-1.2-6.3c-0.4-2 0.5-3.3 2-3.6zM498.5 787.3c1-0.6 1.9-1.2 3.2-1.9l7.6-4.2-1.6-2.8-6.4 3.6c-1.7 1-2.9 0.1-3.3-0.6-0.7-1.2 0.1-2.3 1.4-3l6.3-3.4-1.5-2.9-6.7 3.7c-3.1 1.7-3.6 4-2.4 5.9 0.8 1.5 2.4 2.1 3.4 2.1l-1.4 1 1.4 2.5zM512.4 795.8c3.2-2.5 3.6-5.7 1.5-8.4-1.7-2.1-5-3.4-8.7-0.6-3 2.3-3.7 5.6-1.5 8.3 2 2.6 5.4 3.1 8.7 0.7z m-5.1-6.5c1.8-1.3 3.7-1.8 4.8-0.6 1 1.3 0 3.1-1.8 4.4-1.4 1.1-3.6 1.9-4.6 0.5-1.1-1.3 0.1-3.1 1.6-4.3zM507.6 662.5l-1.7-2.1c-0.8 0.4-1.9 1.1-2.9 2.4-2.3 3-1.9 6.1 0.2 7.7 1.8 1.2 4 0.8 6.5-0.5 1.8-1 3-1.2 3.9-0.5 1 0.8 1.1 2.1 0 3.6-0.8 1.1-2.1 1.9-3.1 2.4l1.8 2.3c0.8-0.4 2.3-1.4 3.3-2.7 2.5-3.1 2.1-6.3-0.1-8.1-1.8-1.4-3.8-1.4-6.4 0-2.1 1.1-3 1.4-4 0.6-0.8-0.6-1-1.8 0-3.1 0.8-1.1 1.8-1.7 2.5-2zM508.9 656.3l12.1 11.8 2.4-2.2-12.3-12zM493.1 678.2l12.5 12.7 1.5-3-3.3-3.2 2.3-4 4.5 1.2 1.7-3-17.2-4.3-2 3.6z m3.2-0.6c1.1 0.4 2.4 0.7 3.4 1.1l3.9 1.1-1.8 3.2-2.9-2.9c-0.7-0.7-1.9-1.7-2.6-2.5zM580.8 675.6l-12.6 38.8h-40.8l33.1 24-12.6 38.6 32.9-23.9 33 23.9-12.6-38.6 32.9-24h-40.7zM510 807.2c0.7-0.7 0.7-1.8 0-2.5-0.8-0.7-1.7-0.7-2.5 0-0.7 0.7-0.7 1.8 0 2.5s1.8 0.7 2.5 0zM532 826c1 0.5 1.9 0.2 2.4-0.7 0.5-0.8 0.2-1.9-0.7-2.4-0.8-0.5-1.8-0.3-2.4 0.7-0.5 1-0.2 1.9 0.7 2.4zM632.8 804.7l-2.7 2.1 14.5 10.3 3.2-2.6-7-16.4-2.5 2.1 1.9 4.3-3.6 2.9-3.8-2.7z m8.5 2l1.7 3.7c0.5 1 1.1 2.3 1.5 3.2v0.1c-0.8-0.7-1.9-1.5-2.9-2.3l-3.2-2.4 2.9-2.3zM624.7 828.8l0.7-6.8c0-0.7 0.1-1.4 0.1-2.3h0.1l3.4 7 3-1.4-7.6-15.4-2.8 1.5 2.6 5.2-0.4 2.1-6.9-5.1-3.3 1.7 9.1 6.4-1.4 8.9 3.4-1.8zM564 823.3c0.6-2.1-0.2-4.1-2.5-4.7-1.3-0.4-2.6-0.1-3.6 0.6l0.1-1.3-2.9-0.7c0 0.7-0.2 1.8-0.6 2.9l-1.2 4.4c-0.7 2.6-0.4 5.2 3.3 6.3 1.9 0.5 3.4 0.4 4.4 0.1v-2.3c-1 0.2-2 0.4-3.2 0-1.7-0.5-1.9-1.4-1.5-2.6 3.8 1 6.9 0.4 7.7-2.7z m-6.6-1.2c0.4-1.5 1.8-1.8 2.6-1.5s1.3 1 1.1 2c-0.6 1.8-2.6 1.7-4.2 1.2l0.5-1.7zM641.8 796.8l12.3 12 2.4-2.4-12.4-12zM607.7 817c-2.6 0.8-5 3.4-3.6 8 1.2 3.6 4 5.3 7.4 4.3 3.2-1.1 4.9-4 3.6-8-1.2-3.8-4.1-5.2-7.4-4.3z m3.3 10c-1.5 0.5-2.9-1.2-3.4-3.1-0.7-2.1-0.5-4.2 1.1-4.6 1.5-0.5 2.9 1 3.6 3.1 0.3 1.9 0.3 4-1.3 4.6zM649.6 787.5c-2.5 3.2-2.1 6.3 0.2 8.2 1.8 1.4 3.8 1.4 6.4 0 2-1.1 3.1-1.4 4-0.6 0.7 0.6 1 1.8 0 3.2-0.8 1.1-1.9 1.7-2.5 1.9l1.7 2.3c0.8-0.4 1.9-1.1 2.9-2.4 2.3-2.9 2-5.9-0.2-7.7-1.8-1.4-4.1-1.2-6.6 0.3-1.8 1-3 1.2-3.9 0.4-1-0.8-1.1-2.1 0-3.6 0.8-1.1 2.1-1.9 3.1-2.4l-1.8-2.3c-0.8 0.4-2.3 1.4-3.3 2.7zM654.6 780.9l-1.7 3 17.3 4.3 2-3.6-12.4-12.7-1.7 3 3.3 3.2-2.3 4-4.5-1.2z m8.8-1.4l2.9 2.9c0.7 0.8 1.8 1.7 2.6 2.5-1.1-0.4-2.4-0.7-3.4-1.1l-3.9-1.1 1.8-3.2zM581 825c0.1-2-1.2-3.8-3.4-4.1-1.3-0.1-2.6 0.4-3.3 1.3l-0.2-1.3-3-0.2c0.1 0.7 0 1.9 0 3l-0.4 4.5c-0.2 2.7 0.7 5.2 4.5 5.5 1.9 0.1 3.4-0.4 4.3-0.7l-0.5-2.1c-0.8 0.5-1.9 0.7-3.1 0.6-1.8-0.1-2.1-1.1-2-2.3 3.9 0.2 6.9-1 7.1-4.2z m-7 0.2c0.1-1.5 1.4-2 2.3-2 0.8 0 1.5 0.6 1.4 1.8-0.1 1.8-2 2.1-3.8 2l0.1-1.8zM542 811.4l-2.9-1.5-6 10.8 2.9 1.6zM596.6 829.8c-0.4 0-0.6 0.1-0.8 0.1l0.6 3.1c0.2 0 0.5 0 0.7-0.1 1.2-0.2 2.3-1.3 2.6-3h0.1l0.6 2.1 2.7-0.5c-0.2-1.1-0.5-2.3-0.8-3.8l-1.7-8.4-3.2 0.6 1.2 6.3c0.4 2-0.5 3.2-2 3.6zM521.2 796.1l-2.2-2.4-9 8.6 2.3 2.5zM524.1 798.6c-0.7-0.6-1.4-1.1-1.8-1.3l-1.7 1.9c0.2 0.1 0.5 0.4 0.8 0.6 0.8 0.7 0.7 1.4-0.2 2.6l-3.6 4-2-1.8-1.7 1.8 2 1.8-2.1 2.5 3.1 1.4 1.4-1.7 1.2 1.1 1.5-1.8-1.2-1.1 4.1-4.3c1-1.1 3-3.3 0.2-5.7zM582.7 828c0.2 4 2.4 5.9 5.3 5.8 3.7-0.2 5.5-3.4 5.2-7-0.2-3.8-2.6-6.1-6.4-5.9-1.5 0.1-3 0.5-3.9 1l0.6 2.3c0.8-0.4 1.8-0.6 3-0.7 1.8-0.1 3.3 0.6 3.6 2.7l-7.4 0.5c-0.1 0.4-0.1 0.8 0 1.3z m7.3 0.5c0.2 1.1-0.3 2.8-2 2.9-1.7 0.1-2.3-1.4-2.4-2.7l4.4-0.2zM545.7 826.8l3.2 1.3 1-13.1-3-1.2-8.7 9.9 3.2 1.3 3.8-5c0.6-1 1.3-1.8 1.9-2.6-0.2 1.1-0.5 2.1-0.6 3.2l-0.8 6.2zM535.3 811.8c1.2-1.7 1-3.8-1-5.1-1.1-0.8-2.5-1-3.6-0.6l0.6-1.2-2.5-1.8c-0.4 0.7-0.8 1.7-1.5 2.5l-2.6 3.7c-1.5 2.3-2 4.9 1.1 7 1.5 1.1 3.1 1.5 4.2 1.5l0.7-2.1c-1 0-2-0.4-3-1.1-1.5-0.8-1.4-1.9-0.6-2.8 3.2 2.3 6.4 2.6 8.2 0z m-6.1-3.3c0.8-1.3 2.3-1.1 3-0.6s1 1.3 0.2 2.3c-1 1.5-2.7 0.8-4.3-0.2l1.1-1.5zM749.8 189.3H499.1c-6.6 0-11.8 5.3-11.8 11.8 0 6.6 5.3 11.8 11.8 11.8h250.6c6.6 0 11.9-5.2 11.9-11.8 0-6.6-5.3-11.8-11.8-11.8zM749.8 285.8H499.1c-6.6 0-11.8 5.3-11.8 11.8s5.3 11.8 11.8 11.8h250.6c6.6 0 11.9-5.3 11.9-11.8 0-6.6-5.3-11.8-11.8-11.8zM761.6 394c0-6.5-5.3-11.8-11.8-11.8H499.1c-6.6 0-11.8 5.3-11.8 11.8 0 6.6 5.3 11.8 11.8 11.8h250.6c6.6 0 11.9-5.4 11.9-11.8z"
p-id="8684"
fill="#8a8a8a"></path>
<path d="M812.1 904.8c0 9-7.6 16.6-16.6 16.6h-67.1C554.6 921.5 228.2 784 228.2 784c-58.3 72.5-127.7 48.2-127.7 11.3V119.2c0-9 7.6-16.6 16.6-16.6h678.4c9 0 16.6 7.6 16.6 16.6l-1 392.8c16.6-45.7 37.5-55.3 37.5-55.3V119.2c0-29.2-23.9-53.1-53.1-53.1H117.1C87.9 66 64 89.9 64 119.2v785.7c0 29.2 23.9 53.1 53.1 53.1h678.4c29.2 0 53.1-23.9 53.1-53.1V768.7l-36.5 41.8v94.3z"
p-id="8685"
fill="#8a8a8a"></path>
<path d="M186.2 158.7c-19.4 0-35.2 15.8-35.2 35.2v207.3c0 19.4 15.8 35.2 35.2 35.2h202c19.4 0 35.2-15.8 35.2-35.2V193.9c-0.1-19.4-15.9-35.2-35.2-35.2h-202z m-5 248.7c11.8-46.5 46.6-66.7 61.9-73.7-20.2-12.1-33.7-34.2-33.7-59.5 0.1-38.3 31.3-69.2 69.4-69 38.3 0.1 69.2 31.1 69 69.4 0 25.3-13.7 47.4-34 59.4 15.3 7.1 51.3 26.5 62.6 73.4H181.2zM797.1 803.6l30.9-33.3c8.1-8.7 7.6-22.5-1.1-30.5L658.8 583.5c-8.8-8.2-22.5-7.6-30.5 1.1l-30.9 33.2c-8.1 8.8-7.6 22.5 1.1 30.5l168.1 156.4c8.8 8.1 22.5 7.6 30.5-1.1zM724.9 580.8c-5.2-4.9-13.3-4.5-18.1 0.6L690 599.5l118.6 110.3 16.8-18c4.8-5.2 4.5-13.3-0.7-18.2l-99.8-92.8zM943.9 448.3c-20.2-18.8-44.8-25.2-90.9 24.5-32 34.5-49.2 91.9-77.4 122.3l-18.3-17c-4.5-4.3-10.9-4.8-14.4-1.1-3.3 3.7-2.4 10 2.1 14.3l70.8 65.8c4.6 4.3 11.1 4.8 14.4 1.1 3.4-3.7 2.4-10-2.1-14.3l-18.3-17c28.3-30.4 84.4-51.7 116.3-86.1 46.1-49.6 38-73.7 17.8-92.5z"
p-id="8686"
fill="#8a8a8a"></path>
<path d="M443.5 731.5c0 75.7 61.6 137.2 137.4 137.2 57.3 0 106.5-35.4 127-85.4l-14-13.1c-16.2 46.9-60.7 80.8-113 80.8-65.9 0-119.7-53.7-119.7-119.7 0-63.1 49.2-114.8 111.2-119.2 1.9-3.8 4.2-7.5 7.2-10.8l6.5-7c-1.8-0.1-3.4-0.2-5.2-0.2-75.7 0-137.4 61.6-137.4 137.4z"
p-id="8687"
fill="#8a8a8a"></path>
</svg>
</div>
<div style="text-align: center;margin-top:12px;color: #606266;font-size: 15px;">{{ info.tip }}</div>
</div>
</section>
</transition>
</van-form> </van-form>
<van-popup v-model:show="visible.dateShow" <van-popup v-model:show="dialog.showDate"
:style="{ borderRadius: '10px 10px 0 0' }" :style="{ borderRadius: '10px 10px 0 0' }"
position="bottom"> position="bottom">
<van-datetime-picker v-model="currentDate" <van-datetime-picker v-model="info.curDate"
type="date" type="date"
title="选择从业时间" title="请选择从业日期"
:min-date="minDate" :min-date="info.minDate"
:max-date="maxDate" :max-date="info.maxDate"
:formatter="formatter" :formatter="formatter"
@confirm="dateConfirm" @confirm="onConfirmDate"
@cancel="visible.dateShow = false"> @cancel="dialog.showDate = false">
</van-datetime-picker> </van-datetime-picker>
</van-popup> </van-popup>
<van-popup v-model:show="dialog.showOpt"
:style="{ borderRadius: '10px 10px 0 0' }"
position="bottom">
<van-picker :title="dialog.title"
:columns="dialog.columns"
:columns-field-names="dialog.columnsFieldNames"
:default-index="dialog.index"
@confirm="onOptConfirm"
@cancel="dialog.showOpt = false" />
</van-popup>
</div> </div>
</section> </section>
<section v-if="info.showEmpty"
class="empty">
<van-empty image-size="80"
description="医生在线接诊信息审核中,请耐心等待!"
style="padding-top: 80px;">
<template #image>
<van-image style="width: 80px;height: 80px;"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEABAMAAACuXLVVAAAAHlBMVEVwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBHcEx7/3Z7AAAACnRSTlP/gMDjo2ZKFzEAHjvfPQAABvtJREFUeNrtnUtvGzcQgKld+XVzAyOFb3LitPVNSewYuikoGlQ3xyjc6Ca3Dgrf3BhJszcBAZrsLZIl7fLfFra8Ky3J2SW5M1RbkDdbNviJ5AyHw+EM40JL3+48Zsgt3H95xoHGhJ/P24ymHf6qA/D+R0bX9uJKgD/bjLI1ogqAKW3/jD2NSgHI+2fsqAwgaTH69kMJwCcH/bPwEgSYMSdtDQQ4cQPAegDAyFH/LAAABos/ebb/DXLbebQkYLtKgLRSZdZryUWOsK4EuMo+/o4TtbSbdRErAHId8ISTtVlGcKwAmEBCgkrQUi1DtiyDsppAbe/uv2ZfAkjaqsHBby1FN2xJCQTE/Wf9NCSA6/kHHWoAPl+HYSQCbKvkg6KNZXXMFlpojbx/ns4X26YAMFJvExTtRFoELB+YMHYAMJZWO8v1cMNB/5nVERUB5uPyvQuAeznoFwG6sn4ia0Nxud0CuBLC23Zz19dWAWDmRg3ypW1vUwGw5gZgKnbGst9tuAFIRIljmR7acgPA2xBAxxHA3ZbcLABM3AMECoADRwB3SicsAIydAsy3fg/gATyAB/AAHsADeAAPUA2Qvsby0/5hB7CNd0WwawPwFdE/3rQB6GJ66C/NARLUK4IDcwDc+5sNc4ApKsCmOUCKCrBlsQZQ7zB7FlKwjQkQWQBMMO+srTThKdokPIv9bugBPIAH8AAewAN4AA/gATyAB/AAHsADeAAP4AFsANJfHiG1n2IrAMRY+6YNAKabUIhm1wMYkPmqNQFQPbU2nlLUCxObKxvUBzfBf3EEUF+8rFkAjOne1bi/tgusNOEU7d3fYd/vhh7gXwYwkINa3QJcyXHFbgEmcmy5WwAuvy9wDDBi7AVfJQD/+JmvFkCYEQ/gAf7/AMmXaJUAF7f5JJ4/iVcE8D6zLYOHKwEYLQWivFoBQDGjws/OAdJW2THdAcCnck8FOcCsPKyPHkA+X4ZOAVQRgR2XACfV/ipSAHVMZt8dQC4C4d7ZTovB6QWoADIdfHS7CySnDHxeTwSQCvlvTkFlRASQJRSIhRE5dgVwLX7hKQOedwMAyQNtH9gufAYOJOdrGGkCGPhqlfqtJQ34SBHmDQMYBTYfgGuwLzP19ACu7X3BS1+3qRjUjh7AsE56G569MF+Xz+WC6xzHUxoCbhBhbmbq4UK4LwABivKRqPcjhCloQlvhpUIyNAGMrmw2ITUQKQACTT1gAtCHtiLVL0NNAIMMUUeQHgoqPITle8EH3WdEbyJoMw5VAKGbzaj+FKD4Y+MaixDFIu3LDkJdMURxCNfRhCgOYcH8GYGp4QgAxopve61O9kEDMFUkd+mqu6EBSOQLuxlgFhMZpV1pyV8BGW+IAAaiBZhAOycRwFg8ig2UmfHoAKaCY2jKoLxXVGfDVuHB6azNoKRHVACZVRm+/BJ9PG/BxhMVwET3CEHmIWlVPvwjBrjRsx4JvWR61iMhwE11klRagMGqHZXyKlxftaMycApws+pFqApHO3YIcJ+LsTGPxmm2wAyExKq4x//6+/XZ5+y4HbsDGBR7hLNQ0m7HDWFG1p0BTMVVt+3YVzwW5W4MCSIRgPSFp259xYop75r5irGEEBQLJ6fjQm8TZuKq5fy8LFx7r691MCqMdwIIIhTQWOGbjM2EsEQQLUM6N8yEsEQQLd31gZkQlgiirae0bA6A6VYLohrgxsY9WrXg1YJIAQCIvJqLYgoApaeeGYJFCKp95dokEENw41N+QKCIwK1fOTT4qjgBjR+uMk3xN6MJnIRcJR74ALABrGTDB+jCSchVpik6wAw+BCnXJzrAuExTvpM/RAfYLlNUCkHEBigRQrUgYgNUVAKQBREbYFi+V8mCiA1QIoRqQUQGKBXCxRptUgEkv2ne9+6/IQGYGjySO4zxAVKj91lP8QF+t8mbiAhgmtQwzACwUscbvxPtFAA6rgfgXhjxygdcGwPc3WLiFVCweKW5yTFLSFgkNGxyxCIaNplFQ45YRiSLodQLfWnnmybLBy/CcM8HsRFuH7GUzJWZLOXRZotiOjUrag1LQvjBAeshlhMaqiM2y43nA8SCSoMaACglpeoAoBTVGlY6TmCAbB+7XNUIZKHwnfoj0LeSApTSclZ6oIdYXO+r0XdYRBUVywvWkMT7M49mfcxuvurY8pm6jiBY5dnmeYnJbDO3LzGZ2NsDS2fKOkU2LXKXrC8AFgNoXWbU3iYULTr9QqsPo1pWccB53VKzTRP3rtrfywTfhWHbkt1T+i0uANgla2/UMMxf8AJAXoXUrC2vgplRCptmLAAkVslPYgT/QP7v7boAPH3wXO/fnr2KuARgRVDTmK9deD3kqACLh8p2qX7qA3B+YTYIl+gAPH2781hbl35b37H0DwWiYbMzHrQAAAAAAElFTkSuQmCC" />
</template>
</van-empty>
</section>
</transition> </transition>
</div> </div>
</template> </template>
<script> <script>
import { route, store, router } from 'vue-helper' import { store } from 'vue-helper'
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
import { axios } from 'axios' import { axios } from 'axios'
import { WxBack } from '@/utils/common-util.mjs' import { Back } from '@/utils/common-util.mjs'
import DateUtil from '@/utils/date-util.mjs'
import OLDoctor from '@/views/online/online-doctor/components/ol-doctor.vue' import OLDoctor from '@/views/online/online-doctor/components/ol-doctor.vue'
export default { export default {
@ -105,6 +136,30 @@ export default {
if (!params || !params.key) return vant.Toast.fail('权限不足!密钥缺失。') if (!params || !params.key) return vant.Toast.fail('权限不足!密钥缺失。')
const loading = ref(false)
const info = reactive({
show: false,
showBtn: true,
tip: '',
options: {},
minDate: new Date(1960, 0, 1),
maxDate: new Date(2025, 5, 1),
curDate: null,
})
const dialog = reactive({
showDate: false, //
showOpt: false, //
title: '',
index: -1,
codeKey: '',
nameKey: '',
options: [],
doctorScopeOptions: [],
columnsFieldNames: { value: 'code', text: 'label' }
})
const work = reactive({ const work = reactive({
key: null, key: null,
show: false, show: false,
@ -113,6 +168,7 @@ export default {
doctKey: params.key, doctKey: params.key,
doctName: null, doctName: null,
ifAccepted: -1, ifAccepted: -1,
onlineState: 0,
userList: [], userList: [],
doctor: { doctor: {
doctCode: '', doctCode: '',
@ -133,63 +189,51 @@ export default {
user: null, user: null,
}) })
const loading = ref(false)
const info = reactive({
showForm: false,
showEmpty: false,
options: {}
})
function init() { function init() {
console.log('问诊医生-----------------------'); console.log('问诊医生-----------------------');
loading.value = true loading.value = true
axios.RGet(`/micro/online_doctor/getUploadInfo`, { axios.RGet(`/micro/online_doctor/getUploadInfo`, { doctKey: work.doctKey }).then((resp) => {
doctKey: work.doctKey, loading.value = false
}).then((resp) => {
if (resp.code === 200) { if (resp.code === 200) {
if (!resp.data) return console.log('data is null'); if (!resp.data) return vant.Toast.fail('获取医生信息失败')
console.log(resp.data); const doctor = resp.data.doctor ?? {}
const user = resp.data.user
dialog.doctorScopeOptions = resp.data.doctorScopeOptions
const doctor = resp.data.doctor
if (typeof doctor === 'object') work.doctor = doctor if (typeof doctor === 'object') work.doctor = doctor
if (!doctor || !doctor.isXKUpload) { // if (doctor.obtainEmploymentTime) work.obtainEmploymentTime = doctor.obtainEmploymentTime
loading.value = false
return work.tip = '您在HIS中的医生的信息不能满足需求,请补充信息!'
}
if (doctor && doctor.obtainEmploymentTime) { const verifyState = doctor.verifyState
loading.value = false // ||
work.obtainEmploymentTime = doctor.obtainEmploymentTime if (!doctor.isXKUpload) {
info.tip = '信息缺失不满足申请条件,请联系管理员。'
info.show = true
return info.showBtn = false
} }
if (!doctor.verifyState) { // //
loading.value = false if (!verifyState || !user) {
info.showForm = true info.tip = ''
return info.show = true
return info.showBtn = true
} }
if (doctor.verifyState === -1) { // if (verifyState === -1) { //
loading.value = false info.tip = '您的信息在审核中,请耐心等待!'
info.showEmpty = true info.show = true
return work.tip = '信息审核中,请等待审核通过!' return info.showBtn = false
} }
if (doctor.verifyState === 1) { // if (verifyState === 1) { //
loading.value = false
const user = resp.data.user
if (typeof user === 'object') { if (typeof user === 'object') {
work.user = user work.user = user
work.userId = user.id work.userId = user.id
} }
info.show = true
work.show = true work.show = true
} }
// const respOptions = resp.data.options
// options.type = respOptions.type
// options.title = respOptions.title
// options.scope = respOptions.scope
} else { } else {
vant.Toast.fail(resp.message) vant.Toast.fail(resp.message)
} }
@ -198,43 +242,40 @@ export default {
} }
init() init()
const minDate = new Date(1960, 0, 1) //
const maxDate = new Date(2025, 5, 1) function onConfirmDate() { //
const currentDate = ref(new Date(2022, 0, 1)) work.obtainEmploymentTime = DateUtil.format(info.curDate, 'yyyyMMdd')
const currentColumn = ref([]) dialog.showDate = false
}
const visible = reactive({ // key formData
dateShow: false, // function chioseDate(key,) {
currKey: 'birthDate', // if (!info.showBtn) return
}) let date = work[key]
if (date && date.length === 8) date = DateUtil.date8StrAddLine(date)
info.curDate = !date ? new Date(2022, 0, 1) : new Date(date)
/** dialog.showDate = true
* 日期选择确定
*/
function dateConfirm() {
work.obtainEmploymentTime = format(currentDate.value, 'yyyyMMdd')
visible.dateShow = false
} }
/** function chooseOpt(codeKey, nameKey, title, optKeyName) {
* if (!info.showBtn) return
* @param {string} key formData对象属性 dialog.showOpt = true
* @param {string} status 日期选择器区分 dialog.title = title
* @param {string} title 选择器标题 dialog.codeKey = codeKey
* @param {string} optionKey options对象属性 dialog.nameKey = nameKey
*/ dialog.columns = dialog[optKeyName]
function chioseDate(key, status, title, optionKey) { const dataVal = work.doctor[codeKey]
visible.dateShow = true
if (work.obtainEmploymentTime) { dialog.index = !dataVal ? 0 : dialog.columns.findIndex(item => item.code === dataVal)
currentDate.value = new Date(work[key]) }
} else {
currentDate.value = new Date(2022, 0, 1) function onOptConfirm(item) {
} work.doctor[dialog.codeKey] = item.code
work.doctor[dialog.nameKey] = item.label
dialog.showOpt = false
} }
/**
* 表单验证通过提交
*/
function submitForm() { function submitForm() {
// formData.doctCode = work.doctor.doctCode // formData.doctCode = work.doctor.doctCode
delete work.doctor.updateTime delete work.doctor.updateTime
@ -247,19 +288,15 @@ export default {
console.log(resp); console.log(resp);
if (resp.code === 200) { if (resp.code === 200) {
vant.Toast.success('提交成功') vant.Toast.success('提交成功')
info.showForm = false info.showBtn = false
info.showEmpty = true info.tip = '您的信息在审核中,请耐心等待!'
} else { } else {
vant.Toast.fail(resp.message) vant.Toast.fail(resp.message)
} }
}) })
} }
/** //
* 日期时间选择格式化
* @param {String} type 类型
* @param {Object} val 数值
*/
function formatter(type, val) { function formatter(type, val) {
if (type === 'year') return `${val}` if (type === 'year') return `${val}`
if (type === 'month') return `${val}` if (type === 'month') return `${val}`
@ -268,20 +305,18 @@ export default {
// 退 // 退
function onBack() { function onBack() {
return WxBack(route, store, router, true) Back(true)
} }
return { return {
visible,
loading, loading,
info, info,
work, work,
dateConfirm, dialog,
onConfirmDate,
onOptConfirm,
chioseDate, chioseDate,
currentColumn, chooseOpt,
currentDate,
maxDate,
minDate,
submitForm, submitForm,
formatter, formatter,
onBack onBack
@ -309,11 +344,24 @@ export default {
color: rgb(51, 51, 51); color: rgb(51, 51, 51);
} }
.doctor-form>>>.van-field__label { .doctor-info__wrap {}
.doctor-info__header {
background-color: #fff;
padding: 10px;
border-radius: 5px;
margin: 8px;
text-align: center;
font-size: 14px;
box-shadow: 2px 2px 6px rgba(0, 0, 0, 0.05);
color: #606266;
}
.doctor-info__wrap>>>.van-field__label {
color: #323233; color: #323233;
} }
.doctor-form>>>.required .van-field__label::before { .doctor-info__wrap>>>.required .van-field__label::before {
content: '*'; content: '*';
width: 3px; width: 3px;
height: 3px; height: 3px;
@ -323,11 +371,17 @@ export default {
color: red; color: red;
} }
.doctor-form>>>.van-field__control { .doctor-info__wrap>>>.van-field__control {
text-align: right; text-align: right;
} }
.doctor-form>>>.van-field__error-message { .doctor-info__wrap>>>.van-field__error-message {
text-align: right; text-align: right;
} }
.footer__box {
margin: 16px 10px;
display: flex;
flex-direction: row;
}
</style> </style>

File diff suppressed because one or more lines are too long

@ -149,7 +149,7 @@
<script> <script>
import { reactive, toRefs, ref, watch, onBeforeUnmount, nextTick } from 'vue'; import { reactive, toRefs, ref, watch, onBeforeUnmount, nextTick } from 'vue';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { HCreateWebSocket, HSendMsg, HLookUserMsg, HClose, HRepeat } from '@/hooks/hook-websocket.mjs' import { HCreateWebSocket, HSendMsg, HLookUserMsg, HClose, HRepeat, HSendAdmin } from '@/hooks/hook-websocket.mjs'
import { format, formatTime } from '@/utils/date-util.mjs' import { format, formatTime } from '@/utils/date-util.mjs'
import { store } from 'vue-helper' import { store } from 'vue-helper'
import { axios, OL_WS_URL, UPLOAD_URL } from 'axios' import { axios, OL_WS_URL, UPLOAD_URL } from 'axios'
@ -303,6 +303,33 @@ export default {
onNotify: (action, data) => { onNotify: (action, data) => {
if (action === 3) { // if (action === 3) { //
vant.Toast.clear() vant.Toast.clear()
} else if (action === 4) { // 使
console.log('action=========4========其他地方有连接')
vant.Toast.clear()
vant.Dialog.alert({
title: '提示',
message: '检测到当前账户已在登录中,是否确认使其强制下线?',
showCancelButton: true,
confirmButtonText: '是',
cancelButtonText: '否'
}).then(() => {
HSendAdmin({ action: 5 })
}).catch(() => {
})
} else if (action === 5) { // 线
console.log('action=======5=====被强制断线')
vant.Dialog.alert({
title: '提示',
message: '您已被强制挤下线,如不是您本人操作,请联系管理员确认',
showCancelButton: false,
confirmButtonText: '确 定',
cancelButtonText: ''
}).then(() => {
}).catch(() => {
})
} else if (action === 110) { // } else if (action === 110) { //
} else if (action === 9) { // } else if (action === 9) { //

File diff suppressed because one or more lines are too long

@ -15,7 +15,14 @@
<section v-if="deptList.length === 0"> <section v-if="deptList.length === 0">
<van-empty image-size="10rem" <van-empty image-size="10rem"
description="暂无可在线咨询科室信息" /> description="暂无可线上咨询的科室信息">
<div style="display: flex;align-items: center;">
<div style="text-align: left;color:#606266;padding: 0 10px;font-size:15px;">
<div>注意接诊日期为每周星期一 星期五</div>
<div style="margin-top: 5px;">时段上午 08:00~11:30 下午 14:00~17:30</div>
</div>
</div>
</van-empty>
</section> </section>
<section v-else> <section v-else>
<div v-for="(item, i) in deptList" <div v-for="(item, i) in deptList"

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save