Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
F
frontend-h5
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
songrui
frontend-h5
Commits
3b4e440d
Commit
3b4e440d
authored
Mar 05, 2025
by
songrui
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
随访详情
parent
8e6ad985
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1455 additions
and
4 deletions
+1455
-4
atomic.less
src/assets/css/atomic.less
+2
-0
doc-down.svg
src/assets/icons/doc-down.svg
+3
-0
doc-pause.svg
src/assets/icons/doc-pause.svg
+5
-0
doc-play.svg
src/assets/icons/doc-play.svg
+3
-0
video-default.png
src/assets/image/video-default.png
+0
-0
DocAddress.vue
src/components/docAddress/DocAddress.vue
+0
-0
DocImage.vue
src/components/docImage/DocImage.vue
+157
-0
DocNavBar.vue
src/components/docNavBar/DocNavBar.vue
+62
-0
ImagePreview.vue
src/components/imagePreview/ImagePreview.vue
+67
-0
Mp3.vue
src/components/mediaPlay/Mp3.vue
+154
-0
Mp4.vue
src/components/mediaPlay/Mp4.vue
+129
-0
mp3.js
src/components/mediaPlay/mp3.js
+146
-0
register.js
src/register.js
+26
-0
index.js
src/router/index.js
+6
-1
Tumour.vue
src/tumour/Tumour.vue
+12
-0
visit.js
src/tumour/api/visit.js
+6
-0
base.vue
src/tumour/screening/simpleV2/form/base.vue
+1
-1
index.js
src/tumour/store/index.js
+6
-1
Detail.vue
src/tumour/visit/detail/Detail.vue
+599
-0
common.js
src/utils/common.js
+70
-0
vue.config.js
vue.config.js
+1
-1
No files found.
src/assets/css/atomic.less
View file @
3b4e440d
...
@@ -78,7 +78,9 @@
...
@@ -78,7 +78,9 @@
// 字体大小
// 字体大小
.text-16 { font-size: 16px; }
.text-16 { font-size: 16px; }
.text-12 { font-size: 12px; }
.text-12 { font-size: 12px; }
.text-start { text-align: start; }
.text-center { text-align: center; }
.text-center { text-align: center; }
.text-end { text-align: end; }
.text-black { color: #000; }
.text-black { color: #000; }
.text-green { color: #52C41A; }
.text-green { color: #52C41A; }
.text-red { color: #FF4D4F; }
.text-red { color: #FF4D4F; }
...
...
src/assets/icons/doc-down.svg
0 → 100644
View file @
3b4e440d
<svg
width=
"10"
height=
"6"
viewBox=
"0 0 10 6"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M4.99999 3.78145L8.29999 0.481445L9.24266 1.42411L4.99999 5.66678L0.757324 1.42411L1.69999 0.481445L4.99999 3.78145Z"
/>
</svg>
src/assets/icons/doc-pause.svg
0 → 100644
View file @
3b4e440d
<svg
width=
"8"
height=
"9"
viewBox=
"0 0 8 9"
xmlns=
"http://www.w3.org/2000/svg"
>
<rect
x=
"0.158203"
y=
"0.900391"
width=
"2.68262"
height=
"7.70361"
rx=
"1"
/>
<rect
x=
"5.1582"
y=
"0.900391"
width=
"2.68262"
height=
"7.70361"
rx=
"1"
/>
</svg>
\ No newline at end of file
src/assets/icons/doc-play.svg
0 → 100644
View file @
3b4e440d
<svg
width=
"8"
height=
"9"
viewBox=
"0 0 8 9"
xmlns=
"http://www.w3.org/2000/svg"
>
<path
d=
"M6.6432 3.90404C7.26987 4.29571 7.26987 5.20837 6.6432 5.60004L1.53 8.79579C0.863951 9.21207 0 8.73323 0 7.94779V1.55629C0 0.770851 0.863951 0.292008 1.53 0.708288L6.6432 3.90404Z"
/>
</svg>
src/assets/image/video-default.png
0 → 100644
View file @
3b4e440d
6.67 KB
src/
tumour/util
s/docAddress/DocAddress.vue
→
src/
component
s/docAddress/DocAddress.vue
View file @
3b4e440d
File moved
src/components/docImage/DocImage.vue
0 → 100644
View file @
3b4e440d
<
template
>
<div
class=
"doc-image"
>
<div
v-if=
"isPdf"
class=
"p-2 flex items-center view-pdf"
>
<doc-icon
type=
"doc-PDF"
style=
"font-size: .48rem"
class=
"shrink-0"
/>
<span
class=
"grow px-4 text-ellipsis"
>
{{
name
}}
</span>
<span
class=
"close-btn"
@
click
.
stop=
"removeBtn"
v-if=
"remove"
>
<doc-icon
type=
"close-circle"
/>
</span>
</div>
<div
class=
"view-img"
v-if=
"status==='success' && !isPdf"
>
<img
:src=
"src"
:alt=
"name"
:loading=
"loading"
>
</div>
<template
v-if=
"!isPdf"
>
<div
class=
"doc-image-wrapper"
v-if=
"status==='loading'"
>
<slot
name=
"placeholder"
>
<div
class=
"doc-image-default"
>
加载中...
</div>
</slot>
</div>
<div
class=
"doc-image-wrapper"
v-if=
"status==='fail'"
>
<slot
name=
"fail"
>
<div
class=
"doc-image-default"
>
加载失败
</div>
</slot>
</div>
<span
class=
"close-btn"
@
click
.
stop=
"removeBtn"
v-if=
"remove"
>
<doc-icon
type=
"close-circle"
/>
</span>
</
template
>
</div>
</template>
<
script
>
export
default
{
name
:
'doc-image'
,
props
:
{
src
:
String
,
// 浏览器应当如何加载该图像
// img标签中的属性 需要浏览器支持
// https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/img
// eager 立即加载图像
// lazy 延迟加载图像,直到它和视口接近到一个计算得到的距离
loading
:
String
,
// 开启删除功能
remove
:
Boolean
,
// 处理pdf预览
isPdf
:
Boolean
,
name
:
String
},
emits
:
[
'removeBtn'
],
data
()
{
return
{
// 图片加载状态 loading | fail | success
status
:
'loading'
,
imgStyle
:
{},
// viewer显示
visible
:
false
,
// 按键界面显示
btVisible
:
false
}
},
methods
:
{
loadImage
()
{
if
(
this
.
isPdf
)
{
this
.
status
=
'success'
return
}
const
image
=
new
Image
()
image
.
onload
=
()
=>
{
this
.
show
=
true
this
.
status
=
'success'
}
image
.
onerror
=
(
err
)
=>
{
console
.
warn
(
'doc-image'
,
err
)
this
.
show
=
false
this
.
status
=
'fail'
}
this
.
status
=
'loading'
image
.
src
=
this
.
src
},
removeBtn
()
{
this
.
btVisible
=
false
this
.
$emit
(
'onRemove'
,
this
.
src
)
}
},
watch
:
{
src
:
{
handler
(
val
)
{
if
(
val
)
{
this
.
loadImage
()
}
},
immediate
:
true
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
.doc-image {
display: inline-block;
width: 100%;
height: 100%;
position: relative;
.view-img {
width: 100%;
height: 100%;
min-height: 90px;
// border: 1px dashed #d9d9d9;
// background: #fafafa;
background: #EFF2F7;
img {
width: 100%;
height: 90px;
object-fit: contain;
}
}
.view-pdf {
width: 100%;
min-height: 48px;
overflow-y: hidden;
border-radius: 8px;
border: 1px solid #EEEEEE;
.close-btn {
top: 50%;
right: 8px;
transform: translateY(-50%);
}
}
.close-btn {
position: absolute;
font-size: 16px;
top: -8px;
right: -8px;
}
}
.doc-image-wrapper {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.doc-image-default {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
background: #f5faf7;
color: #a8abb2;
vertical-align: middle;
user-select: none;
}
</
style
>
src/components/docNavBar/DocNavBar.vue
0 → 100644
View file @
3b4e440d
<
template
>
<div
class=
"px-3 py-3 flex items-center doc-nav-bar"
>
<div
class=
"shrink-0 left"
>
<slot
name=
"left"
>
<span
class=
"back-btn"
@
click=
"goBack"
v-if=
"!hideBack"
>
<doc-icon
type=
"doc-left"
style=
"color: #262626"
/>
</span>
</slot>
</div>
<div
class=
"grow text-center font-semibold title"
>
<slot>
{{
title
}}
</slot>
</div>
<div
class=
"shrink-0 right"
>
<slot
name=
"right"
></slot>
</div>
</div>
</
template
>
<
script
>
import
{
backHome
}
from
'@/utils/common.js'
export
default
{
name
:
'DocNavBar'
,
props
:
{
title
:
String
,
// 是否首页
home
:
Boolean
,
// 替换返回函数
backFunc
:
Function
,
// 隐藏返回按键
hideBack
:
Boolean
},
methods
:
{
goBack
()
{
if
(
this
.
backFunc
)
{
this
.
backFunc
()
return
}
if
(
this
.
home
)
{
backHome
()
return
}
this
.
$router
.
back
()
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
.doc-nav-bar {
background: transparent;
border-bottom: 1px solid #00000019;
.left {
min-width: 24px;
}
.title {
font-size: 16px;
}
}
</
style
>
src/components/imagePreview/ImagePreview.vue
0 → 100644
View file @
3b4e440d
<
template
>
<div>
<div
class=
'list gap-x-2.5 gap-y-1 flex items-center flex-wrap'
>
<div
v-for=
"(url, index) in imgList"
:key=
"index"
@
click=
'toPreview(index)'
class=
"flex gap-x-2.5"
>
<!--
<img
:style=
"
{width: imgSize.width, height: imgSize.height}" :src="url.trueDownloadUrl" /> -->
<DocImage
:style=
"
{width: imgSize.width, height: imgSize.height}" :src="url.trueDownloadUrl"/>
</div>
</div>
<van-overlay
:show=
'imgShow'
@
click=
'imgShow = false'
>
<div
class=
'wrapper'
>
<van-swipe
class=
'block'
:initial-swipe=
'initSwipe'
>
<van-swipe-item
v-for=
'image in imgList'
:key=
'image'
>
<img
:src=
'image.trueDownloadUrl'
style=
'width: 100%;height: 100%'
/>
</van-swipe-item>
</van-swipe>
</div>
</van-overlay>
</div>
</
template
>
<
script
>
import
DocImage
from
'../docImage/DocImage.vue'
export
default
{
name
:
'ImagePreview'
,
components
:
{
DocImage
},
props
:
{
imgList
:
Array
,
imgSize
:
{
default
:
()
=>
{
return
{
width
:
'.97rem'
,
height
:
'.97rem'
}
}}
},
data
()
{
return
{
imgShow
:
false
,
initSwipe
:
0
}
},
methods
:
{
//图片预览
toPreview
(
index
)
{
this
.
initSwipe
=
index
this
.
imgShow
=
true
},
}
}
</
script
>
<
style
scoped
lang=
'less'
>
.wrapper {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
.block {
width: 100%;
}
}
</
style
>
\ No newline at end of file
src/components/mediaPlay/Mp3.vue
0 → 100644
View file @
3b4e440d
<
template
>
<div
class=
"p-1 flex flex-col mp3"
>
<div
v-if=
"file.annexName"
class=
"text-12 mb-1 text-ellipsis"
>
{{
file
.
annexName
}}
</div>
<div
class=
"flex items-center justify-between gap-x-2.5"
>
<div
class=
"shrink-0 play-bt"
@
click
.
stop=
"start(file)"
>
<doc-icon
type=
"doc-play"
v-if=
"!player.playing"
/>
<doc-icon
type=
"doc-pause"
v-else
/>
</div>
<span
class=
"shrink-0 time"
>
{{
timeFormat
(
player
.
duration
)
}}
</span>
<div
class=
"grow progress"
>
<van-slider
v-model=
"player.currentTime"
:max=
"sliderMax"
:bar-height=
"6"
:button-size=
"0"
@
change=
"onProgress"
/>
<!--
<div
:style=
"`width: $
{progress}%`">
</div>
-->
</div>
<span
class=
"shrink-0 time"
:style=
"`opacity: $
{player.currentTime ? 1 : 0}`">
{{
timeFormat
(
player
.
currentTime
)
}}
</span>
<span
class=
"text-16 shrink-0 close-btn"
@
click
.
stop=
"removeBtn"
v-if=
"remove"
>
<doc-icon
type=
"close-circle"
/>
</span>
</div>
<audio
ref=
"audio"
type=
"audio/mpeg"
crossOrigin=
"anonymous"
preload=
"metadata"
style=
"display: none"
></audio>
</div>
</
template
>
<
script
>
import
{
musicPlayer
}
from
'./mp3.js'
import
{
showToast
}
from
'vant'
import
{
useStore
}
from
'@/tumour/store/index.js'
export
default
{
props
:
{
file
:
{
default
:
()
=>
({})
},
activeMediaUrl
:
{
default
:
''
},
remove
:
Boolean
},
emits
:
[
'play'
,
'onRemove'
],
data
()
{
return
{
store
:
useStore
(),
player
:
{},
// 正在播放的items
activeAudio
:
{},
}
},
computed
:
{
sliderMax
()
{
return
this
.
player
.
duration
?
Math
.
floor
(
this
.
player
.
duration
)
:
100
},
progress
()
{
if
(
!
this
.
player
.
currentTime
)
return
0
const
temp
=
this
.
player
.
currentTime
/
this
.
player
.
duration
return
Math
.
round
(
temp
*
1000
)
/
10
}
},
mounted
()
{
this
.
init
()
},
methods
:
{
init
()
{
this
.
player
=
new
musicPlayer
(
this
.
$refs
.
audio
)
this
.
player
.
init
()
this
.
player
.
setSrc
(
this
.
file
.
annexUrl
)
this
.
player
.
audioEl
.
onended
=
()
=>
{
console
.
log
(
'播放结束'
)
this
.
stop
()
}
},
start
(
item
)
{
if
(
!
item
||
!
item
.
annexUrl
)
{
showToast
(
'文件获取失败'
)
return
}
if
(
!
this
.
player
.
audioCtx
)
{
this
.
player
.
init
()
this
.
player
.
setSrc
(
item
.
annexUrl
)
}
if
(
this
.
player
.
playing
)
{
this
.
stop
()
}
else
{
this
.
player
.
audioEl
.
play
()
this
.
activeAudio
=
item
this
.
player
.
playing
=
true
this
.
$emit
(
'play'
,
item
)
console
.
log
(
'this.player.duration'
,
this
.
player
.
audioEl
.
duration
)
}
console
.
log
(
'this.player'
,
this
.
player
)
},
stop
()
{
this
.
player
.
audioEl
.
pause
()
this
.
player
.
playing
=
false
},
timeFormat
(
value
)
{
if
(
!
value
||
value
==
Infinity
)
{
return
'00:00'
}
let
date
=
Math
.
ceil
(
parseFloat
(
value
))
let
minutes
=
Math
.
floor
(
date
/
60
)
let
seconds
=
date
%
60
let
format
=
`
${
minutes
>=
10
?
minutes
:
'0'
+
minutes
.
toString
()}
:
${
seconds
>=
10
?
seconds
:
'0'
+
seconds
.
toString
()}
`
return
format
},
onProgress
(
value
)
{
this
.
player
.
progressChange
(
value
)
this
.
player
.
playing
=
true
},
removeBtn
()
{
this
.
$emit
(
'onRemove'
,
this
.
file
)
}
},
watch
:
{
activeMediaUrl
(
val
)
{
if
(
val
!==
this
.
file
.
annexUrl
)
{
this
.
stop
()
}
},
'store.documentHidden'
:
{
handler
(
val
)
{
if
(
val
&&
this
.
activeMediaUrl
==
this
.
file
.
annexUrl
)
{
this
.
stop
()
}
}
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
.mp3 {
background-color: #fff;
.play-bt {
display: inline-flex;
width: 24px;
height: 24px;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: #E4F2F0;
font-size: 10px;
padding-left: 2px;
color: var(--van-primary-color);
}
.progress {
// height: 6px;
// border-radius: 4px;
// background: #EFF2F7;
// overflow: hidden;
// text-align: left;
// >div {
// height: 100%;
// background: #54CCBD;
// }
}
}
</
style
>
src/components/mediaPlay/Mp4.vue
0 → 100644
View file @
3b4e440d
<
template
>
<div
class=
"mp4"
>
<div
class=
"flex flex-wrap justify-between video-list"
>
<div
v-for=
"item in files"
:key=
"item.annexId"
@
click
.
stop=
"start(item)"
>
<div
class=
"item"
>
<div
class=
"shrink-0 play-bt"
>
<doc-icon
type=
"doc-play"
/>
</div>
<span
class=
"close-btn"
@
click
.
stop=
"removeBtn(item)"
v-if=
"remove"
>
<doc-icon
type=
"close-circle"
/>
</span>
</div>
<div
v-if=
"item.annexName"
class=
"text-12 my-1 text-ellipsis"
>
{{
item
.
annexName
}}
</div>
</div>
</div>
<!--
<van-popup
v-model:show=
"visible"
:close-on-click-overlay=
"false"
closeable
close-icon-position=
"top-right"
close-icon=
"clear"
>
<video
controls
v-if=
"visible"
style=
"width: calc(100vw - var(--van-padding-md) * 2)"
>
<source
:src=
"activeVideo.annexUrl"
type=
"video/mp4"
/>
播放失败!
</video>
</van-popup>
-->
<van-overlay
:show=
"visible"
>
<div
class=
"h-full flex items-center justify-center wrapper"
@
click
.
stop
>
<video
controls
v-if=
"visible"
ref=
"video"
>
<source
:src=
"activeVideo.annexUrl"
type=
"video/mp4"
/>
播放失败!
</video>
<van-icon
name=
"close"
class=
"close-icon"
@
click=
"visible = false"
/>
</div>
</van-overlay>
</div>
</
template
>
<
script
>
import
{
useStore
}
from
'@/tumour/store/index.js'
export
default
{
props
:
{
files
:
{
default
:
()
=>
[]
},
activeMediaUrl
:
{
default
:
''
},
remove
:
Boolean
},
emits
:
[
'play'
,
'onRemove'
],
data
()
{
return
{
visible
:
false
,
activeVideo
:
{},
store
:
useStore
()
}
},
methods
:
{
start
(
item
)
{
this
.
activeVideo
=
item
this
.
visible
=
true
this
.
$emit
(
'play'
,
item
)
},
removeBtn
(
item
)
{
this
.
$emit
(
'onRemove'
,
item
)
}
},
watch
:
{
activeMediaUrl
(
val
)
{
if
(
val
!==
this
.
activeVideo
.
annexUrl
)
{
const
dom
=
this
.
$refs
.
video
dom
&&
dom
.
pause
()
}
},
'store.documentHidden'
:
{
handler
(
val
)
{
if
(
val
&&
this
.
activeMediaUrl
==
this
.
activeVideo
.
annexUrl
)
{
const
dom
=
this
.
$refs
.
video
dom
&&
dom
.
pause
()
}
}
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
.video-list {
>div {
width: calc(50% - 5px);
.item {
position: relative;
background: url('@/assets/image/video-default.png') no-repeat;
background-size: 100%;
height: .84rem;
display: flex;
align-items: center;
justify-content: center;
}
}
.play-bt {
display: inline-flex;
width: 36px;
height: 36px;
align-items: center;
justify-content: center;
border-radius: 50%;
background-color: #E4F2F0;
font-size: 15px;
padding-left: 2px;
color: var(--van-primary-color);
}
.close-btn {
position: absolute;
font-size: 16px;
top: -8px;
right: -8px;
}
}
.wrapper {
position: relative;
.close-icon {
position: absolute;
top: 16px;
right: 16px;
color: #ccc;
font-size: 24px;
}
video {
width: calc(100vw - var(--van-padding-md) * 2);
background-color: #fff;
}
}
</
style
>
src/components/mediaPlay/mp3.js
0 → 100644
View file @
3b4e440d
export
class
musicPlayer
{
constructor
(
audioEl
)
{
this
.
audioEl
=
audioEl
// 音频上下文
this
.
audioCtx
=
null
// 音源
this
.
audioSource
=
null
// 时长
this
.
duration
=
0
// 当前播放时间
this
.
currentTime
=
0
// 播放进度
this
.
progress
=
0
// 声音
this
.
volume
=
20
// AnalyserNode 接口表示了一个可以提供实时频域和时域分析信息的节点
this
.
analyser
=
null
// 音量节点
this
.
gainNode
=
null
// 缓冲进度
this
.
timeRange
=
null
// 是否播放中
this
.
playing
=
false
}
init
()
{
// 音频上下文
this
.
audioCtx
=
new
(
window
.
AudioContext
||
window
.
webkitAudioContext
)()
if
(
!
this
.
audioCtx
)
{
throw
new
Error
(
'audioCtx is null'
)
}
// 获取音频数据的节点
this
.
analyser
=
this
.
audioCtx
.
createAnalyser
()
// 音量节点
this
.
gainNode
=
this
.
audioCtx
.
createGain
()
this
.
gainNode
.
gain
.
value
=
1
this
.
audioEl
.
volume
=
this
.
volume
/
100
// 从<audio>或<video>元素生成的音频源
this
.
audioSource
=
this
.
audioCtx
.
createMediaElementSource
(
this
.
audioEl
)
this
.
audioEl
.
ontimeupdate
=
()
=>
{
this
.
currentTime
=
this
.
audioEl
.
currentTime
if
(
this
.
progress
>=
this
.
duration
)
return
this
.
progress
=
this
.
currentTime
}
this
.
audioEl
.
onloadedmetadata
=
()
=>
{
// 时长
this
.
duration
=
this
.
audioEl
.
duration
console
.
log
(
'onloadedmetadata'
,
this
.
duration
)
}
this
.
audioEl
.
onprogress
=
()
=>
{
// 当浏览器正在下载音频/视频时
this
.
timeRange
=
this
.
audioEl
.
buffered
if
(
this
.
timeRange
&&
this
.
timeRange
.
length
>
0
)
{
console
.
log
(
'buffered'
,
this
.
audioEl
.
buffered
.
start
(
0
),
this
.
audioEl
.
buffered
.
end
(
0
)
)
}
}
this
.
audioEl
.
oncanplay
=
()
=>
{
console
.
log
(
'可播放'
)
setTimeout
(()
=>
{
this
.
getAudioSource
()
},
100
)
}
this
.
audioEl
.
onerror
=
(
e
)
=>
{
console
.
error
(
'加载出现错误'
,
e
)
this
.
onerror
(
e
)
}
}
onerror
()
{}
onended
()
{}
setSrc
(
src
)
{
this
.
progress
=
0
this
.
audioEl
.
src
=
src
this
.
audioEl
.
load
()
}
// 调整进度
progressChange
(
value
)
{
this
.
audioEl
.
currentTime
=
value
}
// 调整音量
volumeChange
(
value
)
{
this
.
volume
=
value
this
.
audioEl
.
volume
=
this
.
volume
/
100
}
// 音频波形处理
getAudioSource
()
{
// 节点链接到音源
this
.
audioSource
.
connect
(
this
.
analyser
)
// 链接音量节点
this
.
analyser
.
connect
(
this
.
gainNode
)
this
.
gainNode
.
connect
(
this
.
audioCtx
.
destination
)
return
// 使用快速傅立叶变换(Fast Fourier Transform (FFT) )来捕获音频数据
// this.analyser.fftSize = 2048
this
.
analyser
.
fftSize
=
256
let
bufferLength
=
this
.
analyser
.
frequencyBinCount
let
dataArray
=
new
Uint8Array
(
bufferLength
)
let
c
=
this
.
boardEl
let
canvasWidth
=
c
.
width
let
canvasHeight
=
c
.
height
let
ctx
=
c
.
getContext
(
'2d'
)
let
left
=
this
ctx
.
strokeStyle
=
'rgba(81,167,255, .5)'
drawBar
()
function
drawBar
()
{
// 波形绘制
ctx
.
clearRect
(
0
,
0
,
canvasWidth
,
canvasHeight
)
let
barWidth
=
(
canvasWidth
/
bufferLength
)
*
1
let
barHeight
=
0
let
x
=
0
left
.
analyser
.
getByteFrequencyData
(
dataArray
)
for
(
let
i
=
0
;
i
<
bufferLength
;
i
++
)
{
barHeight
=
dataArray
[
i
]
/
2
let
tempColor
=
barHeight
*
3
>
255
?
255
:
barHeight
*
3
ctx
.
fillStyle
=
'rgba('
+
tempColor
+
', 160, 255, .5)'
ctx
.
fillRect
(
x
,
canvasHeight
-
barHeight
/
2
,
barWidth
,
barHeight
)
x
+=
barWidth
+
0.1
}
requestAnimationFrame
(
drawBar
)
}
}
}
src/register.js
View file @
3b4e440d
...
@@ -14,4 +14,30 @@ dayjs.locale('cn')
...
@@ -14,4 +14,30 @@ dayjs.locale('cn')
export
function
registe
(
app
)
{
export
function
registe
(
app
)
{
// 自定义组件
// 自定义组件
app
.
use
(
DocIcon
)
app
.
use
(
DocIcon
)
app
.
config
.
globalProperties
.
$idCardHide
=
idCardHide
app
.
config
.
globalProperties
.
$phoneHide
=
phoneHide
app
.
config
.
globalProperties
.
$addrJoin
=
addrJoin
}
// idCard 脱敏
function
idCardHide
(
idCard
)
{
if
(
!
idCard
||
idCard
.
length
<
18
)
{
return
idCard
}
return
idCard
.
substring
(
0
,
6
)
+
'******'
+
idCard
.
substring
(
14
)
}
// phone 脱敏
function
phoneHide
(
phone
)
{
if
(
!
phone
||
phone
.
length
<
11
)
{
return
phone
}
return
phone
.
substring
(
0
,
3
)
+
'******'
+
phone
.
substring
(
9
)
}
// 地址拼接显示
function
addrJoin
(
str1
=
''
,
str2
=
''
)
{
if
(
!
str1
&&
!
str2
)
return
'-'
return
(
str1
??
''
)
+
(
str2
??
''
)
}
}
src/router/index.js
View file @
3b4e440d
...
@@ -9,7 +9,12 @@ const routes = [
...
@@ -9,7 +9,12 @@ const routes = [
{
{
path
:
'screening/simple/form'
,
path
:
'screening/simple/form'
,
name
:
'tumour-screening-simple-form'
,
name
:
'tumour-screening-simple-form'
,
component
:
()
=>
import
(
/* webpackChunkName: "page-tumour" */
'@/tumour/screening/simpleV2/form/Index.vue'
)
component
:
()
=>
import
(
/* webpackChunkName: "page-tumour-screening" */
'@/tumour/screening/simpleV2/form/Index.vue'
)
},
{
path
:
'visit/detail'
,
name
:
'tumour-visit-detail'
,
component
:
()
=>
import
(
/* webpackChunkName: "page-tumour-visit" */
'@/tumour/visit/detail/Detail.vue'
)
}
}
]
]
}
}
...
...
src/tumour/Tumour.vue
View file @
3b4e440d
...
@@ -15,6 +15,8 @@ import { useStore } from './store/index.js'
...
@@ -15,6 +15,8 @@ import { useStore } from './store/index.js'
export
default
{
export
default
{
created
()
{
created
()
{
this
.
init
()
this
.
init
()
// 监听页面是否隐藏
document
.
addEventListener
(
'visibilitychange'
,
this
.
visibilitychange
)
},
},
setup
()
{
setup
()
{
const
store
=
useStore
()
const
store
=
useStore
()
...
@@ -25,7 +27,17 @@ export default {
...
@@ -25,7 +27,17 @@ export default {
getDict
().
then
(
res
=>
{
getDict
().
then
(
res
=>
{
this
.
store
.
$patch
({
dict
:
res
.
data
})
this
.
store
.
$patch
({
dict
:
res
.
data
})
})
})
},
visibilitychange
()
{
if
(
document
.
hidden
)
{
this
.
store
.
onDocumentHidden
(
true
)
}
else
{
this
.
store
.
onDocumentHidden
(
false
)
}
}
}
},
beforeUnmount
()
{
document
.
removeEventListener
(
'visibilitychange'
,
this
.
visibilitychange
)
}
}
}
}
</
script
>
</
script
>
...
...
src/tumour/api/visit.js
0 → 100644
View file @
3b4e440d
import
{
fetchBase
}
from
'@/utils/fetch.js'
// 简易筛查 新增
export
function
getVisitById
(
id
,
loading
=
true
)
{
return
fetchBase
({
url
:
`/tumour-admin/v1/h5-app/visit-details/
${
id
}
`
,
loading
})
}
src/tumour/screening/simpleV2/form/base.vue
View file @
3b4e440d
...
@@ -194,7 +194,7 @@ import { useStore } from '@/tumour/store/index.js'
...
@@ -194,7 +194,7 @@ import { useStore } from '@/tumour/store/index.js'
import
{
getResidentInfo
}
from
'@/tumour/api/base.js'
import
{
getResidentInfo
}
from
'@/tumour/api/base.js'
import
{
getDictValue
}
from
'@/tumour/utils/dictionaries.js'
import
{
getDictValue
}
from
'@/tumour/utils/dictionaries.js'
import
{
showToast
}
from
'vant'
import
{
showToast
}
from
'vant'
import
DocAddress
from
'@/
tumour/util
s/docAddress/DocAddress.vue'
import
DocAddress
from
'@/
component
s/docAddress/DocAddress.vue'
const
defaultForm
=
(
info
=
{})
=>
{
const
defaultForm
=
(
info
=
{})
=>
{
const
form
=
{
const
form
=
{
...
...
src/tumour/store/index.js
View file @
3b4e440d
...
@@ -4,7 +4,9 @@ export const useStore = defineStore('tumour', {
...
@@ -4,7 +4,9 @@ export const useStore = defineStore('tumour', {
state
:
()
=>
{
state
:
()
=>
{
return
{
return
{
// 字典
// 字典
dict
:
[]
dict
:
[],
// 页面是否处于隐藏状态
documentHidden
:
false
}
}
},
},
getters
:
{},
getters
:
{},
...
@@ -12,6 +14,9 @@ export const useStore = defineStore('tumour', {
...
@@ -12,6 +14,9 @@ export const useStore = defineStore('tumour', {
getDict
(
val
)
{
getDict
(
val
)
{
if
(
!
val
)
return
[]
if
(
!
val
)
return
[]
return
this
.
dict
[
val
]
||
[]
return
this
.
dict
[
val
]
||
[]
},
onDocumentHidden
(
value
)
{
this
.
documentHidden
=
value
}
}
}
}
})
})
src/tumour/visit/detail/Detail.vue
0 → 100644
View file @
3b4e440d
<
template
>
<div
class=
"h-full flex flex-col visit-detail"
>
<DocNavBar
home
v-if=
"embed !== 'wx'"
>
随访详情
</DocNavBar>
<div
class=
"px-4 py-3 flex shrink-0 base-info"
>
<div
class=
"flex w-full"
>
<div
class=
"grow flex flex-col justify-between"
>
<div
class=
"flex justify-between"
>
<span
class=
"name"
>
{{
baseInfo
.
residentName
||
'-'
}}
</span>
</div>
<div
class=
'top-label'
>
<div
class=
'mt-3 flex'
>
<div><span>
随访方式:
</span><span
class=
'color-b'
>
{{
info
.
visitModeTrans
}}
</span></div>
<div
class=
'ml-4'
>
随访日期:
<span
class=
'color-b'
>
{{
info
.
visitDate
}}
</span></div>
</div>
<div><span>
下次随访日期:
</span>
<span
v-if=
"info.nextVisitCustomDate"
class=
'color-b'
>
{{
info
.
nextVisitCustomDate
}}
</span>
<span
v-else
class=
'color-b'
>
{{
info
.
nextVisitDictTrans
}}
</span>
</div>
</div>
</div>
</div>
</div>
<div
class=
'p-3 grow cont-box'
>
<div
class=
'p-3 h-full cont-inner'
>
<div
class=
'flex justify-between collapse-head mt-2'
>
<span
class=
'text-16 font-semibold'
>
全部内容
</span>
<span
@
click=
'toggleAll'
>
<span
v-if=
'!collapseAll'
>
展开全部
</span>
<span
v-else
>
收起全部
</span>
<span
:class=
"['ml-2 icon-down',
{ 'icon-down-expanded': collapseAll }]">
<doc-icon
type=
'doc-down'
/>
</span>
</span>
</div>
<van-collapse
:model-value=
"activeCollapse"
ref=
'collapse'
class=
'doc-collapse'
@
change=
'collapseChange'
>
<van-collapse-item
v-for=
"item in collapseList"
:key=
'item.name'
:title=
'item.title'
:name=
'item.name'
>
<template
#
right-icon
>
<doc-icon
type=
'doc-down'
/>
</
template
>
<!-- 基本信息 -->
<div
v-if=
"item.name === '1'"
>
<div
v-for=
'item in columnsBase'
:key=
'item.key'
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
{{ item.title }}
</span>
<span
v-if=
"item.key === 'idCard'"
>
{{ $idCardHide(baseInfo.idCard) || '-'
}}
</span>
<span
class=
'text-end'
v-else
>
<span>
{{ baseInfo[item.key] || '-' }}
</span>
<span
v-if=
'item.unit'
class=
'ml-1'
>
{{ item.unit }}
</span>
</span>
</div>
</div>
<!-- 随访信息 -->
<div
v-if=
"item.name === '2'"
>
<div
class=
"info-item"
v-if=
"visitCategory == 2"
>
<span
class=
'shrink-0 mr-2'
>
随访人群
</span>
<span
class=
'text-end'
>
{{ info.speciesTrans }}
</span>
</div>
<div
class=
"info-item"
v-else-if=
"visitCategory == 1"
>
<span
class=
'shrink-0 mr-2'
>
确诊肿瘤
</span>
<span
class=
'text-end'
>
{{ info.diseaseName }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
随访方式
</span>
<span
class=
'text-end'
>
{{ info.visitModeTrans }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
随访类型
</span>
<span
class=
'text-end'
>
{{ info.visitTypeTrans }}
</span>
</div>
<div
class=
"info-item"
v-if=
"info.lastStatus == 2"
>
<span
class=
'shrink-0 mr-2'
>
失访原因
</span>
<span
class=
'text-end'
>
<span>
{{ info.loseReasonTrans }}
</span>
<span
v-if=
"info.loseReason == 99"
class=
"ml-2"
>
{{ info.loseReasonOther }}
</span>
</span>
</div>
<div
class=
"info-item"
v-if=
"info.lastStatus == 1"
>
<span
class=
'shrink-0 mr-2'
>
下次随访日期
</span>
<span
class=
'text-end'
>
{{ info.nextVisitDate }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
随访日期
</span>
<span
class=
'text-end'
>
{{ info.visitDate }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
随访单位
</span>
<span
class=
'text-end'
>
{{ info.visitUnitName }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
随访科室
</span>
<span
class=
'text-end'
>
{{ info.visitDepartName }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
随访医生
</span>
<span
class=
'text-end'
>
{{ info.visitDoctorName }}
</span>
</div>
</div>
<!-- 随访内容 -->
<div
v-if=
"item.name === '3'"
>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
家族遗传史
</span>
<span
class=
'text-end'
>
{{ visitContent.familyHistory == 1 ? visitContent.familySpeciesTrans : '无' }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
是否吸烟
</span>
<span
class=
'text-end'
>
{{ visitContent.smokeStateTrans }}
</span>
</div>
<div
v-if=
"visitContent.smokeState != 4"
class=
"info-item-block p-2"
>
<div
v-if=
"![4].includes(visitContent.smokeState)"
>
吸烟开始年龄: {{ visitContent.smokeAge || '-' }}
</div>
<div
v-if=
"[1,2,3].includes(visitContent.smokeState)"
>
最近7天是否吸烟: {{ visitContent.smokeAge || '-' }}
</div>
<div
v-if=
"[1,2].includes(visitContent.smokeState)"
>
日吸烟量: {{ visitContent.smokeDay || '-' }}
</div>
<div
v-if=
"[1,2].includes(visitContent.smokeState)"
>
目标吸烟量: {{ visitContent.smokeTarget || '-' }}
</div>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
饮酒
</span>
<span
class=
'text-end'
>
<span>
{{ visitContent.drinkStateTrans }}
</span>
<span
v-if=
"visitContent.drinkRate = 1"
>
({{ visitContent.drinkRateTrans }})
</span>
</span>
</div>
<div
v-if=
"[1,2].includes(visitContent.drinkState)"
class=
"info-item-block p-2"
>
<div>
日饮酒量: {{ visitContent.drinkDay || '-' }}
<span
class=
"ml-1"
>
ml
</span></div>
<div>
目标饮酒量: {{ visitContent.drinkTarget || '-' }}
<span
class=
"ml-1"
>
ml
</span></div>
<div>
饮酒种类: {{ visitContent.drinkDayTypeTrans || '-' }}
</div>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
运动
</span>
<span
class=
'text-end'
>
{{ visitContent.sportsStateTrans }}
</span>
</div>
<div
v-if=
"visitContent.sportsState == 1"
class=
"info-item-block p-2"
>
<div>
运动强度: {{ visitContent.sportsStrengthTrans || '-' }}
</div>
<div>
目标运动强度:
<span>
{{ visitContent.sportsTargetWeek }}
</span>
<span
class=
"ml-1"
>
次/周,
</span>
<span>
{{ visitContent.sportsTargetMinute }}
</span>
<span
class=
"ml-1"
>
分钟/次
</span>
</div>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
饮食
</span>
<span
class=
'text-end'
>
{{ visitContent.foodStateTrans }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
是否复发患者
</span>
<span
class=
'text-end'
>
{{ visitContent.relapseTrans }}
</span>
</div>
<div
class=
"info-item"
v-if=
"visitContent.relapse == 1"
>
<span
class=
'shrink-0 mr-2'
>
复发时间
</span>
<span
class=
'text-end'
>
{{ visitContent.relapseDate }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
是否转移患者
</span>
<span
class=
'text-end'
>
{{ visitContent.transferTrans }}
</span>
</div>
<div
class=
"info-item"
v-if=
"visitContent.transfer == 1"
>
<span
class=
'shrink-0 mr-2'
>
转移时间
</span>
<span
class=
'text-end'
>
{{ visitContent.transferDate }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
目前病情
</span>
<span
class=
'text-end'
>
<span
v-if=
"visitContent.currentCondition == 4"
>
{{ visitContent.currentConditionOther }}
</span>
<span
v-else
>
{{ visitContent.currentConditionTrans }}
</span>
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
治疗情况
</span>
<span
class=
'text-end'
>
{{ visitContent.treatSituationTrans }}
</span>
</div>
<div
class=
"info-item"
v-if=
"visitContent.treatSituation == 2"
>
<span
class=
'shrink-0 mr-2'
>
治疗方式
</span>
<span
class=
'text-end'
>
<span>
{{ visitContent.treatItemTrans }}
</span>
<span
v-if=
"visitContent.treatItem.includes(10)"
class=
"ml-2"
>
{{ visitContent.treatItemOther }}
</span>
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
用药不良反应
</span>
<span
class=
'text-end'
>
{{ visitContent.adverseDrugReactionsTrans }}
</span>
</div>
<div
v-if=
"visitContent.adverseDrugReactions == 1"
class=
"info-item-block p-2"
>
<div>
不良反应: {{ visitContent.adverseReactions || '-' }}
</div>
<div>
医生处置: {{ visitContent.doctorDisposal || '-' }}
</div>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
随访情况
</span>
<span
class=
'text-end'
>
{{ visitContent.visitSituation }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
处置意见
</span>
<span
class=
'text-end'
>
{{ visitContent.disposalOpinions }}
</span>
</div>
<div
class=
"py-1"
>
图片上传
</div>
<ImagePreview
:imgList=
"visitContent.imgUrlList"
class=
"mt-1"
v-if=
"visitContent.imgUrlList.length"
/>
<span
v-if=
"!visitContent.imgUrlList || !visitContent.imgUrlList.length"
>
-
</span>
</div>
<!-- 肿瘤信息 -->
<div
v-if=
"item.name === '4'"
>
<div
class=
"py-1"
>
临床TNM分期
</div>
<div
class=
"info-item-block p-2"
>
<div>
T: {{ tumourInfo.clinicalTnmTTrans || '-' }}
</div>
<div>
N: {{ tumourInfo.clinicalTnmNTrans || '-' }}
</div>
<div>
M: {{ tumourInfo.clinicalTnmMTrans || '-' }}
</div>
</div>
<div
class=
"py-1"
>
病理TNM分期
</div>
<div
class=
"info-item-block p-2"
>
<div>
T: {{ tumourInfo.pathologyTnmTTrans || '-' }}
</div>
<div>
N: {{ tumourInfo.pathologyTnmNTrans || '-' }}
</div>
<div>
M: {{ tumourInfo.pathologyTnmMTrans || '-' }}
</div>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
临床分期
</span>
<span
class=
'text-end'
>
{{ tumourInfo.clinicalStagesTrans || '-' }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
病理诊断名称
</span>
<span
class=
'text-end'
>
{{ tumourInfo.diagnosisResultName || '-' }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
病理诊断编码
</span>
<span
class=
'text-end'
>
{{ tumourInfo.diagnosisResultCode || '-' }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
继发部位
</span>
<span
class=
'text-end'
>
{{ tumourInfo.secondarySite || '-' }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
继发部位时间
</span>
<span
class=
'text-end'
>
{{ tumourInfo.secondarySiteDate || '-' }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
分子分型
</span>
<span
class=
'text-end'
>
{{ tumourInfo.molecularTypingName || '-' }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
分子分型记录时间
</span>
<span
class=
'text-end'
>
{{ tumourInfo.molecularTypingDate || '-' }}
</span>
</div>
<div
class=
"py-1"
>
ICD-O-3编码
</div>
<div
class=
"info-item-block p-2"
>
<div>
解剖学C: {{ tumourInfo.anatomyCName || '-' }}
</div>
<div>
形态学M: {{ tumourInfo.morphologyCName || '-' }}
</div>
<div>
行为: {{ tumourInfo.morphologyMName || '-' }}
</div>
<div>
分级: {{ tumourInfo.gradeName || '-' }}
</div>
</div>
</div>
<!-- 疗效评估 -->
<div
v-if=
"item.name === '5'"
>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
疗效评估
</span>
<span
class=
'text-end'
>
{{ efficacyInfo.curativeTrans || '-' }}
</span>
</div>
<div
class=
"info-item"
>
<span
class=
'shrink-0 mr-2'
>
其他评估
</span>
<span
class=
'text-end'
>
{{ efficacyInfo.otherEvaluationsTrans || '-' }}
</span>
</div>
<div
class=
"info-item-block p-2"
v-if=
"efficacyInfo?.otherEvaluations?.includes(1)"
>
<div>
NRS疼痛评分
</div>
<div>
{{ efficacyInfo.nrsPainTrans }}
</div>
<div>
评分结果: {{ efficacyInfo.nrsPainScore || '-' }} 分
</div>
</div>
<div
class=
"info-item-block p-2 mt-2"
v-if=
"efficacyInfo?.otherEvaluations?.includes(2)"
>
<div>
痛主诉疼痛分级
</div>
<div>
{{ efficacyInfo.painTrans }}
</div>
<div>
评分结果: {{ efficacyInfo.painScore || '-' }} 分
</div>
</div>
<div
class=
"info-item-block p-2 mt-2"
v-if=
"efficacyInfo?.otherEvaluations?.includes(3)"
>
<div>
肿瘤患者ECOG体力状态评分
</div>
<div>
{{ efficacyInfo.ceogTrans }}
</div>
<div>
评分结果: {{ efficacyInfo.ceogScore || '-' }} 分
</div>
</div>
<div
class=
"info-item-block p-2 mt-2"
v-if=
"efficacyInfo?.otherEvaluations?.includes(4)"
>
<div>
体能状态评分
</div>
<div>
{{ efficacyInfo.staminaTrans }}
</div>
<div>
评分结果: {{ efficacyInfo.staminaScore || '-' }} 分
</div>
</div>
</div>
<!-- 健康指导 -->
<div
v-if=
"item.name === '6'"
>
<div
class=
"info-item-block p-2"
>
<div
v-for=
"item in guideTextList"
class=
"flex"
>
<span
class=
"shrink-0"
>
{{item.templateModeTrans}}:
</span>
<span
class=
"grow text-wrap"
>
{{ item.templateContent }}
</span>
</div>
</div>
</div>
<!-- 健康宣教 -->
<div
v-if=
"item.name === '7'"
>
<div
class=
"info-item-block p-2"
v-if=
"propagandaTextList.length"
>
<div
v-for=
"item in propagandaTextList"
class=
"flex"
>
<span
class=
"shrink-0"
>
{{item.textModeTrans}}:
</span>
<span
class=
"grow text-wrap"
>
{{ item.content }}
</span>
</div>
</div>
<div
class=
"mt-2"
v-if=
"mp4List.length"
>
<Mp4
:files=
"mp4List"
:activeMediaUrl=
"activeMediaUrl"
@
play=
"e => activeMediaUrl = e.annexUrl"
/>
</div>
<div
class=
"flex flex-col mt-2"
style=
"row-gap: .06rem;"
v-if=
"mp3List.length"
>
<Mp3
:file=
"item"
v-for=
"item in mp3List"
:key=
"item.annexId"
:activeMediaUrl=
"activeMediaUrl"
@
play=
"e => activeMediaUrl = e.annexUrl"
/>
</div>
</div>
<!-- 催检 -->
<div
v-if=
"item.name === '8'"
>
<div
class=
"py-1"
>
催检内容
</div>
<div
class=
"info-item-block p-2"
>
<div>
{{ info.urgentInsContent || '-' }}
</div>
</div>
</div>
<!-- 推送渠道 -->
<div
v-if=
"item.name === '9'"
>
<div
class=
"info-item-block p-2"
>
<span
class=
"mr-2"
>
{{ info.pushMethodTrans }}
</span>
<span
v-if=
"info.pushMethod.includes(2)"
>
{{ info.pushTellTypeTrans }}
<span
v-if=
"info.pushTellType == 1"
>
{{ baseInfo.telephone }}
</span>
<span
v-if=
"info.pushTellType == 2"
>
{{ baseInfo.contactRelation1Trans || '-' }}
{{ baseInfo.contactName1 || '-' }}
{{ baseInfo.contactPhone1 }}
</span>
</span>
</div>
</div>
</van-collapse-item>
</van-collapse>
</div>
</div>
</div>
</template>
<
script
>
import
{
showNotify
}
from
'vant'
import
{
getVisitById
}
from
'@/tumour/api/visit.js'
import
{
fetchDataHandle
}
from
'@/utils/common.js'
import
DocNavBar
from
'@/components/docNavBar/DocNavBar.vue'
import
ImagePreview
from
'@/components/imagePreview/ImagePreview.vue'
import
Mp3
from
'@/components/mediaPlay/Mp3.vue'
import
Mp4
from
'@/components/mediaPlay/Mp4.vue'
const
DefaultCollapseList
=
[
{
title
:
'居民信息'
,
name
:
'1'
},
{
title
:
'随访信息'
,
name
:
'2'
},
{
title
:
'随访内容'
,
name
:
'3'
},
{
title
:
'肿瘤信息'
,
name
:
'4'
},
{
title
:
'疗效评估'
,
name
:
'5'
},
{
title
:
'健康指导'
,
name
:
'6'
},
{
title
:
'健康宣教'
,
name
:
'7'
},
{
title
:
'催检'
,
name
:
'8'
},
{
title
:
'推送渠道'
,
name
:
'9'
}
]
export
default
{
components
:
{
DocNavBar
,
ImagePreview
,
Mp3
,
Mp4
},
data
()
{
return
{
info
:
{},
activeCollapse
:
[],
collapseList
:
[],
// 全部展开、收起
collapseAll
:
false
,
columnsBase
:
[
{
title
:
'姓名'
,
key
:
'residentName'
},
{
title
:
'证件号码'
,
key
:
'idCard'
},
{
title
:
'性别'
,
key
:
'genderTrans'
},
{
title
:
'出生日期'
,
key
:
'dataBirth'
},
{
title
:
'年龄'
,
key
:
'age'
},
{
title
:
'民族'
,
key
:
'nationalTrans'
},
{
title
:
'本人电话'
,
key
:
'telephone'
},
{
title
:
'现住址'
,
key
:
'presentCodeTrans'
},
{
title
:
'详细地址'
,
key
:
'nowAddress'
},
{
title
:
'户籍地址'
,
key
:
'registeredCodeTrans'
},
{
title
:
'详细地址'
,
key
:
'permanentAddress'
}
],
activeMediaUrl
:
null
}
},
computed
:
{
id
()
{
return
this
.
$route
.
query
.
id
||
'232987'
},
embed
()
{
return
this
.
$route
.
query
.
embed
},
baseInfo
()
{
return
this
.
info
.
residentsInfo
||
{}
},
// 随访类型
visitType
()
{
return
this
.
info
.
visitType
||
[]
},
// 通用 专病
visitCategory
()
{
return
this
.
info
.
visitCategory
},
// 健康指导内容
guideTextList
()
{
const
list
=
this
.
info
.
visitHealthGuideList
||
[]
return
list
.
filter
(
e
=>
e
.
templateContent
)
},
// 健康宣教
propagandaTextList
()
{
const
list
=
this
.
info
.
visitPublicizeList
||
[]
return
list
.
filter
(
e
=>
e
.
type
==
'1'
)
},
mp3List
()
{
const
list
=
this
.
info
.
visitPublicizeList
||
[]
return
list
.
filter
(
e
=>
e
.
type
==
'2'
)
},
mp4List
()
{
const
list
=
this
.
info
.
visitPublicizeList
||
[]
return
list
.
filter
(
e
=>
e
.
type
==
'3'
)
},
// 随访内容
visitContent
()
{
const
visitContent
=
this
.
info
.
visitContent
||
{}
return
fetchDataHandle
(
visitContent
,
{
familySpecies
:
'strToArrNum'
,
foodState
:
'strToArrNum'
,
treatItem
:
'strToArrNum'
})
},
//诊断
diagnosisFormInfo
()
{
return
this
.
info
.
visitDiagnosisInfoList
||
[]
},
//肿瘤
tumourInfo
()
{
return
this
.
info
.
visitTumourInfo
||
{}
},
//疗效评估
efficacyInfo
()
{
return
this
.
info
.
visitCurativeEffect
||
{}
},
},
created
()
{
document
.
title
=
'随访详情'
if
(
!
this
.
id
)
{
showNotify
({
type
:
'warning'
,
message
:
'未获取到患者信息'
,
duration
:
0
})
return
}
this
.
load
()
},
methods
:
{
load
()
{
getVisitById
(
this
.
id
).
then
(
res
=>
{
this
.
info
=
fetchDataHandle
(
res
.
data
,
{
healthPushWay
:
'strToArrNum'
,
publicizePushWay
:
'strToArrNum'
,
urgentPushWay
:
'strToArrNum'
,
publicizeType
:
'strToArrNum'
,
visitType
:
'strToArrNum'
,
drinkDayType
:
'strToArrNum'
,
pushMethod
:
'strToArrNum'
,
})
console
.
log
(
'this.info'
,
this
.
info
)
const
exclude
=
[]
if
(
!
this
.
visitType
.
includes
(
1
))
{
exclude
.
push
(
'3'
)
}
if
(
this
.
info
.
isTumour
!=
1
)
{
exclude
.
push
(
'4'
)
}
if
(
this
.
info
.
isCurativeEffect
!=
1
)
{
exclude
.
push
(
'5'
)
}
if
(
!
this
.
visitType
.
includes
(
2
))
{
exclude
.
push
(
'6'
)
}
if
(
!
this
.
visitType
.
includes
(
3
))
{
exclude
.
push
(
'7'
)
}
if
(
!
this
.
visitType
.
includes
(
4
))
{
exclude
.
push
(
'8'
)
}
if
(
!
this
.
info
.
pushMethod
.
length
)
{
exclude
.
push
(
'9'
)
}
this
.
collapseList
=
DefaultCollapseList
.
filter
(
e
=>
!
exclude
.
includes
(
e
.
name
))
})
},
// 折叠面板切换
collapseChange
(
val
)
{
// console.log(val, this.activeCollapse)
if
(
val
&&
val
.
length
<=
2
)
{
this
.
activeCollapse
=
val
.
slice
(
val
.
length
-
1
)
}
else
{
if
(
this
.
activeCollapse
.
length
>
val
.
length
)
{
this
.
activeCollapse
=
val
}
if
(
this
.
activeCollapse
.
length
<
val
.
length
)
{
this
.
activeCollapse
=
val
.
slice
(
val
.
length
-
1
)
}
}
if
(
val
&&
val
.
length
===
this
.
collapseList
.
length
)
{
this
.
collapseAll
=
true
}
else
{
this
.
collapseAll
=
false
}
},
// 全部展开、收起
toggleAll
()
{
if
(
this
.
collapseAll
)
{
this
.
activeCollapse
=
[]
}
else
{
this
.
activeCollapse
=
this
.
collapseList
.
map
(
e
=>
e
.
name
)
}
this
.
collapseAll
=
!
this
.
collapseAll
}
}
}
</
script
>
<
style
lang=
"less"
scoped
>
.base-info {
background: linear-gradient(to bottom, #DFF5F4 , #fff 50%);
color: #8c8c8c;
.name {
font-weight: 600;
color: #000;
font-size: 18px;
}
.top-label {
line-height: 22px;
}
.color-b {
color: #262626;
}
}
.cont-box {
background-color: #f9f9f9;
.cont-inner {
background: linear-gradient(to bottom, #DFF5F4, #fff .6rem);
border-top-left-radius: .08rem;
border-top-right-radius: .08rem;
}
}
.collapse-head {
.icon-down {
vertical-align: middle;
font-size: .12rem;
.svg-icon {
transition: all .2s;
}
}
.icon-down-expanded {
.svg-icon {
transform: rotate(-180deg);
}
}
}
.info-item {
display: flex;
justify-content: space-between;
padding: 4px 0;
}
.info-item-block {
background: #F8FAFC;
color: #4D5665;
font-size: 13px;
}
// 折叠面板
:deep(.doc-collapse) {
margin-top: .1rem;
&::after {
display: none;
}
.van-cell {
padding: .1rem 0;
color: #8C8C8C;
font-weight: 600;
background: transparent;
&::after {
display: none;
}
.svg-icon {
font-size: .12rem;
transition: all .2s;
}
}
.van-collapse-item {
.van-collapse-item__content {
padding: 0;
color: #262626;
}
&::after {
display: none;
}
}
// 展开
.van-collapse-item__title--expanded {
.svg-icon {
transform: rotate(-180deg);
}
}
}
</
style
>
src/utils/common.js
View file @
3b4e440d
...
@@ -87,3 +87,72 @@ export function getInfoByIdCard(idCard) {
...
@@ -87,3 +87,72 @@ export function getInfoByIdCard(idCard) {
age
age
}
}
}
}
//原生方法调用 当前方法传参数两种 字符串或者map
export
function
callMobile
(
handlerInterface
,
parameters
)
{
let
classStr
=
Object
.
prototype
.
toString
.
call
(
parameters
);
if
(
classStr
===
'[object String]'
||
classStr
===
'[object Object]'
)
{
let
param
=
parameters
;
if
(
classStr
===
"[object Object]"
)
{
//判断传参是str ,还是object
//handlerInterface由iOS addScriptMessageHandler与andorid addJavascriptInterface 代码注入而来。
param
=
JSON
.
stringify
(
parameters
);
//参数必须转化成json格式
}
try
{
if
(
isIOSWebKit
())
{
//ios
if
(
window
.
webkit
!==
undefined
)
{
if
(
param
==
'{}'
)
{
window
.
webkit
.
messageHandlers
[
handlerInterface
].
postMessage
(
null
);
}
else
{
window
.
webkit
.
messageHandlers
[
handlerInterface
].
postMessage
(
param
);
}
}
}
else
if
(
isAndroid
())
{
//安卓传输不了js json对象,只能传输string
if
(
param
==
'{}'
)
{
window
[
'function'
][
handlerInterface
]();
}
else
{
window
[
'function'
][
handlerInterface
](
param
);
}
}
}
catch
(
e
)
{
}
}
}
// 判断是否是ios
export
function
isIOSWebKit
()
{
const
aa
=
window
.
navigator
.
userAgent
;
if
(
!!
aa
.
match
(
/
\(
i
[^
;
]
+;
(
U;
)?
CPU.+Mac OS X/
))
{
// ios端
return
true
;
}
}
// 判断是否安卓
export
function
isAndroid
()
{
const
aa
=
window
.
navigator
.
userAgent
;
if
(
aa
.
indexOf
(
'Android'
)
!==
-
1
||
aa
.
indexOf
(
'Adr'
)
!==
-
1
)
{
return
true
}
}
// 判断是否在微信中
export
function
isWeiXin
()
{
const
ua
=
window
.
navigator
.
userAgent
.
toLowerCase
()
return
/micromessenger/
.
test
(
ua
)
}
//关闭页面
export
function
backHome
()
{
if
(
isIOSWebKit
())
{
//ios
console
.
log
(
'ios'
)
callMobile
(
"onBack"
,
{})
}
else
if
(
isAndroid
())
{
console
.
log
(
'Android'
)
callMobile
(
"closePage"
,
{})
}
if
(
isWeiXin
())
{
// 微信中
console
.
log
(
'weixin'
)
WeixinJSBridge
.
call
(
'closeWindow'
)
}
}
\ No newline at end of file
vue.config.js
View file @
3b4e440d
...
@@ -22,7 +22,7 @@ module.exports = defineConfig({
...
@@ -22,7 +22,7 @@ module.exports = defineConfig({
// 设置代理
// 设置代理
proxy
:
{
proxy
:
{
'/tumour-admin'
:
{
'/tumour-admin'
:
{
target
:
'http://192.168.1.1
18
:8081'
,
target
:
'http://192.168.1.1
74
:8081'
,
// target: 'https://beta-tumour.zmnyjk.com',
// target: 'https://beta-tumour.zmnyjk.com',
changOrigin
:
true
,
changOrigin
:
true
,
pathRewrite
:
{
pathRewrite
:
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment