Browse Source

心率联调

dev
kola-web 2 days ago
parent
commit
1d07555c45
  1. 19
      src/components/pickerArea/index.ts
  2. 1306
      src/components/popup/index.scss
  3. 65
      src/components/popup/index.wxml
  4. BIN
      src/images/badge1.png
  5. BIN
      src/images/badge2.png
  6. BIN
      src/images/bg13.png
  7. BIN
      src/images/bg14.png
  8. BIN
      src/images/bg15.png
  9. BIN
      src/images/bg16.png
  10. BIN
      src/images/clsoe.png
  11. 1
      src/pages/articleDetail/index.scss
  12. 5
      src/pages/followForm/index.ts
  13. 8
      src/pages/followForm/index.wxml
  14. 68
      src/pages/health/index.scss
  15. 193
      src/pages/health/index.ts
  16. 69
      src/pages/health/index.wxml
  17. 68
      src/pages/heartDetail/index.ts
  18. 16
      src/pages/heartDetail/index.wxml
  19. 3
      src/pages/heartForm/index.json
  20. 157
      src/pages/heartForm/index.ts
  21. 43
      src/pages/heartForm/index.wxml
  22. 8
      src/pages/index/index.scss
  23. 13
      src/pages/index/index.ts
  24. 20
      src/pages/index/index.wxml
  25. 2
      src/pages/myCollection/index.ts
  26. 110
      src/pages/videoList/index.scss
  27. 41
      src/pages/videoList/index.wxml

19
src/components/pickerArea/index.ts

@ -257,17 +257,26 @@ Component({
}) })
}, },
handleShare() { handleShare() {
const { ProvinceName, ProvinceId, CityName, CityId } = this.data
if (!ProvinceId) {
wx.showToast({ title: '请选择省份', icon: 'none' })
return
}
if (!CityId) {
wx.showToast({ title: '请选择城市', icon: 'none' })
return
}
this.setData({ this.setData({
show: false, show: false,
}) })
this.triggerEvent('change', [ this.triggerEvent('change', [
{ {
label: this.data.ProvinceName, label: ProvinceName,
value: this.data.ProvinceId, value: ProvinceId,
}, },
{ {
label: this.data.CityName, label: CityName,
value: this.data.CityId, value: CityId,
}, },
]) ])
}, },
@ -286,7 +295,7 @@ Component({
range, range,
active: 1, active: 1,
scrollIntoView0: '', scrollIntoView0: '',
scrollIntoView1: `id${this.data.CityId}`, scrollIntoView1: this.data.CityId ? `id${this.data.CityId}` : '',
}) })
}, },
handleProvince() { handleProvince() {

1306
src/components/popup/index.scss

File diff suppressed because it is too large Load Diff

65
src/components/popup/index.wxml

@ -9,35 +9,48 @@
safe-area-inset-bottom="{{false}}" safe-area-inset-bottom="{{false}}"
root-portal root-portal
> >
<view class="popup1" wx:if="{{type==='argument'}}"> <!-- 心率提醒-引导关注公众号 -->
<image class="logo" src="{{imageUrl}}logo1.png?t={{Timestamp}}"></image> <view class="popup1" wx:if="{{type==='popup1'}}">
<view class="title">欢迎加入“愈见守护”</view> <view class="popup-container" style="background: url('/images/bg13.png') no-repeat top center/100%">
<view class="content"> <view class="title">关注“星动守护”</view>
亲爱的用户,为了更好地向您提供平台服务保护您的权益,我们完善了 <view class="content">我们将在每周五下午7点提醒您记录</view>
<text class="link" bind:tap="routerTo" data-url="/doc/pages/doc1/index?type=1">《个人信息及隐私政策》</text> <image class="code" src="/images/bg1.png" show-menu-by-longpress></image>
,请您仔细阅读。一旦您开始使用,即表示您已充分理解并同意协议内容。
</view> </view>
<view class="check"> </view>
<checkbox <!-- 保存复诊记录成功-引导关注公众号 -->
class="checkbox" <view class="popup2" wx:if="{{type==='popup2'}}">
model:checked="{{popup1Check1}}" <view class="popup-container">
bind:tap="handlePopup1Check1" <image class="badge" src="/images/badge1.png"></image>
color="#f23a2f" <view class="container" style="background: url('/images/bg15.png') no-repeat top center/100%">
></checkbox> <view class="title">保存复诊记录成功!</view>
<view class="c-content"> <view class="code-wrap" style="background: url('/images/bg14.png') no-repeat top center/100%">
我特此同意 <image class="code" src="/images/bg1.png" show-menu-by-longpress></image>
<text class="link" bind:tap="routerTo" data-url="/doc/pages/doc1/index?type=1">《个人信息及隐私政策》</text> </view>
规定收集我的相关敏感个人信息 <view class="content">
关注“心动守护”公众号
<view></view>
获得服务通知
</view>
</view>
</view>
</view>
<!-- 保持心率成功-引导关注公众号 -->
<view class="popup3" wx:if="{{type==='popup3'}}">
<view class="popup-container">
<image class="badge" src="/images/badge2.png"></image>
<view class="container" style="background: url('/images/bg15.png') no-repeat top center/100%">
<view class="title">保存复诊记录成功!</view>
<view class="code-wrap" style="background: url('/images/bg14.png') no-repeat top center/100%">
<image class="code" src="/images/bg1.png" show-menu-by-longpress></image>
</view>
<view class="content">
关注“心动守护”公众号
<view></view>
获得服务通知
</view>
</view> </view>
</view> </view>
<view class="btn1" bind:tap="handleOk">同意并继续</view>
<view class="btn2" bind:tap="handleCancel">不同意</view>
</view> </view>
<image <image wx:if="{{params.close}}" class="close" src="/images/clsoe.png" bind:tap="handleCancel"></image>
wx:if="{{params.close}}"
class="close"
src="{{imageUrl}}icon25.png?t={{Timestamp}}"
bind:tap="handleCancel"
></image>
</van-popup> </van-popup>

BIN
src/images/badge1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
src/images/badge2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
src/images/bg13.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

BIN
src/images/bg14.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
src/images/bg15.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 KiB

BIN
src/images/bg16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
src/images/clsoe.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

1
src/pages/articleDetail/index.scss

@ -169,6 +169,7 @@ page {
position: fixed; position: fixed;
bottom: 0; bottom: 0;
left: 0; left: 0;
z-index: 10;
width: 100%; width: 100%;
padding: 0 30rpx calc(env(safe-area-inset-bottom) + 30rpx) 20rpx; padding: 0 30rpx calc(env(safe-area-inset-bottom) + 30rpx) 20rpx;
box-sizing: border-box; box-sizing: border-box;

5
src/pages/followForm/index.ts

@ -3,9 +3,10 @@ const app = getApp<IAppOption>()
Page({ Page({
data: { data: {
popupShow: false, popupShow: false,
popupType: '', popupType: 'popup2',
popupParams: { popupParams: {
position: 'bottom', position: 'center',
close: true,
} as any, } as any,
topicShow: false, topicShow: false,

8
src/pages/followForm/index.wxml

@ -88,3 +88,11 @@
<view class="send" bind:tap="handleSubmit">保存记录</view> <view class="send" bind:tap="handleSubmit">保存记录</view>
</view> </view>
</view> </view>
<popup
show="{{popupShow}}"
type="{{popupType}}"
params="{{popupParams}}"
bind:ok="handlePopupOk"
bind:cancel="handlePopupCancel"
></popup>

68
src/pages/health/index.scss

@ -70,6 +70,25 @@ page {
height: 24rpx; height: 24rpx;
} }
} }
.week-alert {
display: flex;
align-items: center;
gap: 12rpx;
font-size: 28rpx;
color: rgba(30, 41, 59, 1);
.wx-checkbox-input {
width: 32rpx;
height: 32rpx;
border-radius: 8rpx;
&.wx-checkbox-input-checked {
background: linear-gradient(270deg, #439fc7 0%, #2f82a9 100%);
border-color: transparent;
&::before {
color: #fff;
}
}
}
}
} }
.stats-grid { .stats-grid {
margin: 32rpx 30rpx 0; margin: 32rpx 30rpx 0;
@ -151,6 +170,55 @@ page {
} }
} }
} }
.list {
.list-card {
margin: 24rpx 30rpx;
padding: 32rpx;
border-radius: 32rpx;
border: 2rpx solid #fff;
background: rgba(255, 255, 255, 0.7);
box-shadow: 0 16rpx 64rpx 0 rgba(0, 99, 132, 0.04);
backdrop-filter: blur(10rpx);
.lc-header {
display: flex;
align-items: center;
justify-content: space-between;
.status {
padding: 8rpx 16rpx;
font-size: 24rpx;
border-radius: 12rpx;
&.status1 {
color: rgba(47, 130, 169, 1);
background-color: rgba(47, 130, 169, 0.05);
}
&.status2 {
color: rgba(234, 88, 26, 1);
background-color: rgba(234, 88, 26, 0.08);
}
}
.date {
font-size: 28rpx;
color: rgba(100, 116, 139, 1);
}
}
.row {
margin-top: 32rpx;
display: flex;
.label {
flex-shrink: 0;
font-size: 32rpx;
color: rgba(148, 163, 184, 1);
line-height: 44rpx;
}
.content {
padding-left: 32rpx;
font-size: 32rpx;
color: rgba(30, 41, 59, 1);
line-height: 44rpx;
}
}
}
}
} }
.body3 { .body3 {

193
src/pages/health/index.ts

@ -6,12 +6,12 @@ const PAGE_SIZE = 10
Page({ Page({
data: { data: {
popupShow: false, popupShow: false,
popupType: '', popupType: 'popup1',
popupParams: { popupParams: {
position: 'bottom', close: true,
} as any, } as any,
tab: 2, tab: 0,
offsetTop: 0, offsetTop: 0,
// 复诊记录 // 复诊记录
@ -21,10 +21,24 @@ Page({
pages: 1, pages: 1,
count: 0, count: 0,
}, },
startMonth: '',
endMonth: '',
daysSinceLastRevisit: 0, daysSinceLastRevisit: 0,
totalRevisits: 0, totalRevisits: 0,
startMonth: '',
endMonth: '',
// 心率记录
heartRateList: [] as any[],
heartRatePagination: {
page: 1,
pages: 1,
count: 0,
},
heartStats: {
lastHeartRate: 0,
attackCount: 0,
maxHeartRate: 0,
},
}, },
ecDataTrendComponent: null as any, ecDataTrendComponent: null as any,
_loaded: false, _loaded: false,
@ -40,8 +54,14 @@ Page({
app.waitLogin({ type: 0 }).then(() => { app.waitLogin({ type: 0 }).then(() => {
this._loaded = true this._loaded = true
this.getRevisitList() if (this.data.tab === 1) {
this.getLastRevisit() this.getHeartStats()
this.getHeartChart()
this.getHeartRateList()
} else if (this.data.tab === 2) {
this.getRevisitList()
this.getLastRevisit()
}
}) })
}, },
onReady() { onReady() {
@ -63,20 +83,35 @@ Page({
if (query.tab !== undefined) { if (query.tab !== undefined) {
const tab = Number(query.tab) const tab = Number(query.tab)
this.setData({ tab }) this.setData({ tab })
if (tab === 2) { if (tab === 1) {
this.getHeartStats()
this.getHeartChart()
this.getHeartRateList()
} else if (tab === 2) {
this.getRevisitList() this.getRevisitList()
this.getLastRevisit() this.getLastRevisit()
} }
return return
} }
} }
if (this._loaded && this.data.tab === 2) { if (this._loaded) {
this.getRevisitList() if (this.data.tab === 1) {
this.getLastRevisit() this.getHeartStats()
this.getHeartChart()
this.getHeartRateList()
} else if (this.data.tab === 2) {
this.getRevisitList()
this.getLastRevisit()
}
} }
}, },
onReachBottom() { onReachBottom() {
if (this.data.tab === 2) { if (this.data.tab === 1) {
const { heartRatePagination } = this.data
if (heartRatePagination.page < heartRatePagination.pages) {
this.getHeartRateList(heartRatePagination.page + 1, true)
}
} else if (this.data.tab === 2) {
const { revisitPagination } = this.data const { revisitPagination } = this.data
if (revisitPagination.page < revisitPagination.pages) { if (revisitPagination.page < revisitPagination.pages) {
this.getRevisitList(revisitPagination.page + 1, true) this.getRevisitList(revisitPagination.page + 1, true)
@ -86,7 +121,11 @@ Page({
onChange(e: any) { onChange(e: any) {
const { index } = e.detail const { index } = e.detail
this.setData({ tab: index }) this.setData({ tab: index })
if (index === 2) { if (index === 1) {
this.getHeartStats()
this.getHeartChart()
this.getHeartRateList()
} else if (index === 2) {
this.getRevisitList() this.getRevisitList()
this.getLastRevisit() this.getLastRevisit()
} }
@ -134,11 +173,21 @@ Page({
}, },
onStartMonthChange(e: any) { onStartMonthChange(e: any) {
this.setData({ startMonth: e.detail.value }) this.setData({ startMonth: e.detail.value })
this.getRevisitList() if (this.data.tab === 1) {
this.getHeartChart()
this.getHeartRateList()
} else {
this.getRevisitList()
}
}, },
onEndMonthChange(e: any) { onEndMonthChange(e: any) {
this.setData({ endMonth: e.detail.value }) this.setData({ endMonth: e.detail.value })
this.getRevisitList() if (this.data.tab === 1) {
this.getHeartChart()
this.getHeartRateList()
} else {
this.getRevisitList()
}
}, },
handleRevisitTap(e: any) { handleRevisitTap(e: any) {
const { id } = e.currentTarget.dataset const { id } = e.currentTarget.dataset
@ -146,13 +195,83 @@ Page({
url: `/pages/followDetail/index?id=${id}`, url: `/pages/followDetail/index?id=${id}`,
}) })
}, },
handleAddRevisit() { handleHeartTap(e: any) {
const { id } = e.currentTarget.dataset
wx.navigateTo({ wx.navigateTo({
url: '/pages/followForm/index', url: `/pages/heartDetail/index?id=${id}`,
})
},
handleAdd() {
if (this.data.tab === 1) {
wx.navigateTo({
url: '/pages/heartForm/index',
})
} else if (this.data.tab === 2) {
wx.navigateTo({
url: '/pages/followForm/index',
})
}
},
getHeartRateList(page = 1, append = false) {
const { startMonth, endMonth } = this.data
wx.ajax({
method: 'GET',
url: '?r=psvt/heart-rate-record/list',
data: {
page,
count: PAGE_SIZE,
startMonth,
endMonth,
},
}).then((res: any) => {
const list = res.list || []
this.setData({
heartRateList: append ? this.data.heartRateList.concat(list) : list,
heartRatePagination: {
page: res.page || 1,
pages: res.pages || 1,
count: res.count || 0,
},
})
})
},
getHeartStats() {
wx.ajax({
method: 'GET',
url: '?r=psvt/heart-rate-record/statistics',
}).then((res: any) => {
const lastRecord = res?.lastRecord || {}
this.setData({
heartStats: {
lastHeartRate: lastRecord.heartRate || 0,
attackCount: res?.attackCount || 0,
maxHeartRate: res?.maxHeartRate || 0,
},
})
})
},
getHeartChart() {
const { startMonth, endMonth } = this.data
wx.ajax({
method: 'GET',
url: '?r=psvt/heart-rate-record/chart-data',
data: { startMonth, endMonth },
}).then((res: any) => {
this.initChart(res || [])
}) })
}, },
initChart() { initChart(chartData: any[] = []) {
const arr = ['2026-06-01', '2026-06-02', '2026-06-03', '2026-06-04', '2026-06-05', '2026-06-06', '2026-06-07'] const xAxisData = chartData.map((item: any) => item.recordDateTime)
const seriesData = chartData.map((item: any) => {
const isAttack = Number(item.isPsvtAttack) === 1
return {
value: Number(item.heartRate),
itemStyle: isAttack
? { color: '#d62828', borderColor: '#fff' }
: { color: '#fff', borderColor: '#46bc70', borderWidth: 2 },
}
})
this.ecDataTrendComponent.init((canvas, width, height, dpr) => { this.ecDataTrendComponent.init((canvas, width, height, dpr) => {
const chart = echarts.init(canvas, null, { const chart = echarts.init(canvas, null, {
width, width,
@ -166,7 +285,7 @@ Page({
{ {
type: 'inside', type: 'inside',
startValue: 0, startValue: 0,
endValue: 6, endValue: Math.max(chartData.length - 1, 6),
xAxisIndex: [0], xAxisIndex: [0],
}, },
], ],
@ -222,8 +341,11 @@ Page({
type: 'category', type: 'category',
axisLabel: { axisLabel: {
color: 'rgba(148, 163, 184, 1)', color: 'rgba(148, 163, 184, 1)',
formatter: function (value) { formatter: (value) => {
const [_year, month, day] = value.split('-') if (!value) return ''
const parts = value.split(' ')
const datePart = parts[0] || ''
const [_year, month, day] = datePart.split('-')
return `${month}/${day}` return `${month}/${day}`
}, },
}, },
@ -236,7 +358,7 @@ Page({
splitLine: { splitLine: {
show: false, show: false,
}, },
data: arr, data: xAxisData,
}, },
yAxis: [ yAxis: [
{ {
@ -265,15 +387,22 @@ Page({
symbol: 'circle', symbol: 'circle',
symbolSize: 8, symbolSize: 8,
lineStyle: { color: '#46bc70', width: 2 }, lineStyle: { color: '#46bc70', width: 2 },
data: [ data: seriesData,
{ value: 62, itemStyle: { color: '#fff', borderColor: '#46bc70', borderWidth: 2 } }, markArea: {
{ value: 60, itemStyle: { color: '#fff', borderColor: '#46bc70', borderWidth: 2 } }, itemStyle: {
{ value: 61, itemStyle: { color: '#fff', borderColor: '#46bc70', borderWidth: 2 } }, color: 'rgba(45, 190, 141, 0.07)',
{ value: 66, itemStyle: { color: '#d62828', borderColor: '#fff' } }, },
{ value: 63, itemStyle: { color: '#fff', borderColor: '#46bc70', borderWidth: 2 } }, data: [
{ value: 69, itemStyle: { color: '#d62828', borderColor: '#fff' } }, [
{ value: 64, itemStyle: { color: '#fff', borderColor: '#46bc70', borderWidth: 2 } }, {
], yAxis: 60,
},
{
yAxis: 100,
},
],
],
},
}, },
], ],
} }

69
src/pages/health/index.wxml

@ -26,52 +26,81 @@
<view class="body2"> <view class="body2">
<view class="body-op"> <view class="body-op">
<view class="date-range"> <view class="date-range">
<picker mode="date"> <picker mode="date" fields="month" value="{{startMonth}}" bind:change="onStartMonthChange">
<view class="date">2026.01</view> <view class="date">{{startMonth}}</view>
</picker> </picker>
- -
<picker mode="date"> <picker mode="date" fields="month" value="{{endMonth}}" bind:change="onEndMonthChange">
<view class="date">2026.01</view> <view class="date">{{endMonth}}</view>
</picker> </picker>
<image class="icon" src="{{imageUrl}}icon25.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon25.png?t={{Timestamp}}"></image>
</view> </view>
<view class="week-alert">
<checkbox class="check"></checkbox>
每周提醒我
</view>
</view> </view>
<view class="stats-grid"> <view class="stats-grid">
<view class="stat-card"> <view class="stat-card">
<view class="stat-label">最近1次</view> <view class="stat-label">最近1次</view>
<view class="stat-value"> <view class="stat-value">
<text class="stat-number">59</text> <text class="stat-number">{{heartStats.lastHeartRate}}</text>
<text class="stat-unit">次/分</text> <text class="stat-unit">次/分</text>
</view> </view>
</view> </view>
<view class="stat-card"> <view class="stat-card">
<view class="stat-label">最近发作</view> <view class="stat-label">最近发作</view>
<view class="stat-value"> <view class="stat-value">
<text class="stat-number">2</text> <text class="stat-number">{{heartStats.attackCount}}</text>
<text class="stat-unit">次</text> <text class="stat-unit">次</text>
</view> </view>
</view> </view>
<view class="stat-card"> <view class="stat-card">
<view class="stat-label">最高心率</view> <view class="stat-label">最高心率</view>
<view class="stat-value"> <view class="stat-value">
<text class="stat-number">156</text> <text class="stat-number">{{heartStats.maxHeartRate}}</text>
<text class="stat-unit">次/分</text> <text class="stat-unit">次/分</text>
</view> </view>
</view> </view>
</view> </view>
<view class="chart"> <view class="chart">
<ec-canvas id="chart1" ec="{{ ec }}"></ec-canvas> <ec-canvas id="chart1" ec="{{ ec }}"></ec-canvas>
<div class="legend"> <view class="legend">
<div class="l-item"> <view class="l-item">
<div class="dot1"></div> <view class="dot1"></view>
正常心率 正常心率
</div> </view>
<div class="l-item"> <view class="l-item">
<div class="dot2"></div> <view class="dot2"></view>
发作心率 发作心率
</div> </view>
</div> </view>
</view> </view>
<view class="list">
<view
class="list-card"
wx:for="{{heartRateList}}"
wx:key="id"
data-id="{{item.id}}"
bind:tap="handleHeartTap"
>
<view class="lc-header">
<view class="status {{item.isPsvtAttack === 1 ? 'status2' : 'status1'}}">
{{item.isPsvtAttack === 1 ? 'PSVT发作' : '未发作'}}
</view>
<view class="date">{{item.recordDateTime}}</view>
</view>
<view class="row">
<view class="label">心率</view>
<view class="content">{{item.heartRate}}次/分</view>
</view>
<view class="row" wx:if="{{item.remark}}">
<view class="label">备注</view>
<view class="content">{{item.remark}}</view>
</view>
</view>
</view>
<pagination pagination="{{heartRatePagination}}" />
</view> </view>
</van-tab> </van-tab>
<van-tab title="复诊记录"> <van-tab title="复诊记录">
@ -116,6 +145,14 @@
</van-tabs> </van-tabs>
</view> </view>
<view class="fixed-add" bind:tap="handleAddRevisit"> <view class="fixed-add" bind:tap="handleAdd">
<image class="icon" src="{{imageUrl}}icon24.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon24.png?t={{Timestamp}}"></image>
</view> </view>
<popup
show="{{popupShow}}"
type="{{popupType}}"
params="{{popupParams}}"
bind:ok="handlePopupOk"
bind:cancel="handlePopupCancel"
></popup>

68
src/pages/heartDetail/index.ts

@ -8,10 +8,54 @@ Page({
position: 'bottom', position: 'bottom',
} as any, } as any,
fileList: [] as any[], id: '',
detail: {} as any,
}, },
onLoad() { onLoad(options: any) {
app.waitLogin({ type: 0 }).then(() => {}) if (options.id) {
this.setData({ id: options.id })
app.waitLogin({ type: 'any' }).then(() => {
this.getDetail(options.id)
})
}
},
getDetail(id: string) {
wx.ajax({
method: 'GET',
url: '?r=psvt/heart-rate-record/detail',
data: { id },
}).then((res: any) => {
this.setData({ detail: res || {} })
})
},
handleDelete() {
const { id } = this.data
wx.showModal({
title: '提示',
content: '确定删除该心率记录吗?',
success: (res) => {
if (!res.confirm) return
wx.ajax({
method: 'POST',
url: '?r=psvt/heart-rate-record/delete',
data: { id: Number(id) },
}).then(() => {
wx.showToast({ title: '删除成功', icon: 'success' })
setTimeout(() => {
wx.navigateBack()
}, 1000)
})
},
})
},
handleEdit() {
const { id } = this.data
wx.navigateTo({
url: `/pages/heartForm/index?id=${id}`,
})
},
handleBack() {
wx.navigateBack()
}, },
handlePopupOk() { handlePopupOk() {
const { popupType } = this.data const { popupType } = this.data
@ -71,24 +115,6 @@ Page({
}) })
} }
}, },
handleWechatWork() {
wx.navigateTo({
url: '/pages/wechatWork/index',
})
},
handleSetData(e) {
const { fileList } = this.data
this.setData({
fileList: [...fileList, ...e.detail],
})
},
handleDeleteFile(e) {
const { index } = e.detail
const { fileList } = this.data
this.setData({
fileList: fileList.filter((_, i) => i !== index),
})
},
}) })
export {} export {}

16
src/pages/heartDetail/index.wxml

@ -1,5 +1,5 @@
<navbar fixed custom-style="background:{{background}}" back> <navbar fixed custom-style="background:{{background}}" back>
<view class="page-title" slot="left"> <view class="page-title" slot="left" bind:tap="handleBack">
<van-icon name="arrow-left" /> <van-icon name="arrow-left" />
心率记录详情 心率记录详情
</view> </view>
@ -13,25 +13,23 @@
<view class="form-item"> <view class="form-item">
<view class="form-label">日期</view> <view class="form-label">日期</view>
<view class="date"> <view class="date">
<view class="content">2026.07.06 21:30</view> <view class="content">{{detail.recordDateTime || ''}}</view>
</view> </view>
</view> </view>
<view class="form-item"> <view class="form-item">
<view class="form-label">心率</view> <view class="form-label">心率</view>
<view class="date"> <view class="date">
<view class="content">65</view> <view class="content">{{detail.heartRate || ''}}</view>
</view> </view>
</view> </view>
<view class="form-item"> <view class="form-item">
<view class="form-label">其他备注</view> <view class="form-label">其他备注</view>
<view class="remark"> <view class="remark">{{detail.remark || ''}}</view>
本次复诊心悸发作频率较上次减少,发作持续时间约5–10分钟,含服药物后可自行缓解。医生建议继续规律服药,避免剧烈运动及情绪激动,定期复查心电图。
</view>
</view> </view>
<checkbox class="check" disabled>PSVT发作</checkbox> <checkbox class="check" disabled checked="{{detail.isPsvtAttack === 1}}">PSVT发作</checkbox>
</view> </view>
<view class="page-footer"> <view class="page-footer">
<view class="cancel">删除</view> <view class="cancel" bind:tap="handleDelete">删除</view>
<view class="send">编辑</view> <view class="send" bind:tap="handleEdit">编辑</view>
</view> </view>
</view> </view>

3
src/pages/heartForm/index.json

@ -4,6 +4,7 @@
"popup": "/components/popup/index", "popup": "/components/popup/index",
"navbar": "/components/navbar/index", "navbar": "/components/navbar/index",
"uploadFile": "/components/uploadFile/index", "uploadFile": "/components/uploadFile/index",
"van-popup": "@vant/weapp/popup/index" "van-popup": "@vant/weapp/popup/index",
"van-datetime-picker": "@vant/weapp/datetime-picker/index"
} }
} }

157
src/pages/heartForm/index.ts

@ -3,15 +3,144 @@ const app = getApp<IAppOption>()
Page({ Page({
data: { data: {
popupShow: false, popupShow: false,
popupType: '', popupType: 'popup3',
popupParams: { popupParams: {
position: 'bottom', position: 'center',
close: true,
} as any, } as any,
fileList: [] as any[], id: '',
heartRate: '',
recordDateTime: '',
datetimePickerShow: false,
datetimeValue: Date.now(),
isPsvtAttack: 0,
remark: '',
isEdit: false,
}, },
onLoad() { onLoad(options: any) {
app.waitLogin({ type: 0 }).then(() => {}) if (options.id) {
this.setData({ id: options.id, isEdit: true })
app.waitLogin({ type: 'any' }).then(() => {
this.getDetail(options.id)
})
} else {
app.waitLogin({ type: 'any' }).then(() => {})
}
},
getDetail(id: string) {
wx.ajax({
method: 'GET',
url: '?r=psvt/heart-rate-record/detail',
data: { id },
}).then((res: any) => {
if (!res) return
const recordDateTime = res.recordDateTime || ''
// 解析为时间戳供picker使用
let datetimeValue = Date.now()
if (recordDateTime) {
const ts = new Date(recordDateTime.replace(/-/g, '/')).getTime()
if (!isNaN(ts)) datetimeValue = ts
}
// 显示格式 YYYY-MM-DD HH:mm(去掉秒)
const display = recordDateTime ? recordDateTime.replace(/:(\d{2})$/, '') : ''
this.setData({
heartRate: String(res.heartRate || ''),
recordDateTime: display,
datetimeValue,
isPsvtAttack: res.isPsvtAttack ?? 0,
remark: res.remark || '',
})
})
},
onHeartRateInput(e: any) {
this.setData({ heartRate: e.detail.value })
},
showDatetimePicker() {
this.setData({ datetimePickerShow: true })
},
hideDatetimePicker() {
this.setData({ datetimePickerShow: false })
},
onDatetimeConfirm(e: any) {
const date = new Date(e.detail)
const y = date.getFullYear()
const m = String(date.getMonth() + 1).padStart(2, '0')
const d = String(date.getDate()).padStart(2, '0')
const h = String(date.getHours()).padStart(2, '0')
const min = String(date.getMinutes()).padStart(2, '0')
const recordDateTime = `${y}-${m}-${d} ${h}:${min}`
this.setData({
recordDateTime,
datetimeValue: e.detail,
datetimePickerShow: false,
})
},
onPsvtAttackChange(e: any) {
const checked = (e.detail.value || []).includes('1')
this.setData({ isPsvtAttack: checked ? 1 : 0 })
},
onRemarkInput(e: any) {
this.setData({ remark: e.detail.value })
},
handleSubmit() {
const { id, heartRate, recordDateTime, isPsvtAttack, remark, isEdit } = this.data
if (!heartRate) {
wx.showToast({ title: '请输入心率数值', icon: 'none' })
return
}
if (!recordDateTime) {
wx.showToast({ title: '请选择日期时间', icon: 'none' })
return
}
// API需要 Y-m-d H:i:s 格式,补秒
const data = {
heartRate: Number(heartRate),
recordDateTime: `${recordDateTime}:00`,
isPsvtAttack,
remark,
}
wx.showLoading({ title: '保存中' })
if (isEdit) {
wx.ajax({
method: 'POST',
url: '?r=psvt/heart-rate-record/update',
data: { id: Number(id), ...data },
})
.then(() => {
wx.hideLoading()
wx.showToast({ title: '保存成功', icon: 'success' })
setTimeout(() => {
wx.navigateBack()
}, 1000)
})
.catch(() => {
wx.hideLoading()
})
} else {
wx.ajax({
method: 'POST',
url: '?r=psvt/heart-rate-record/create',
data,
})
.then(() => {
wx.hideLoading()
wx.showToast({ title: '保存成功', icon: 'success' })
setTimeout(() => {
wx.navigateBack()
}, 1000)
})
.catch(() => {
wx.hideLoading()
})
}
},
handleBack() {
wx.navigateBack()
}, },
handlePopupOk() { handlePopupOk() {
const { popupType } = this.data const { popupType } = this.data
@ -71,24 +200,6 @@ Page({
}) })
} }
}, },
handleWechatWork() {
wx.navigateTo({
url: '/pages/wechatWork/index',
})
},
handleSetData(e) {
const { fileList } = this.data
this.setData({
fileList: [...fileList, ...e.detail],
})
},
handleDeleteFile(e) {
const { index } = e.detail
const { fileList } = this.data
this.setData({
fileList: fileList.filter((_, i) => i !== index),
})
},
}) })
export {} export {}

43
src/pages/heartForm/index.wxml

@ -1,5 +1,5 @@
<navbar fixed custom-style="background:{{background}}" back> <navbar fixed custom-style="background:{{background}}" back>
<view class="page-title" slot="left"> <view class="page-title" slot="left" bind:tap="handleBack">
<van-icon name="arrow-left" /> <van-icon name="arrow-left" />
心率记录 心率记录
</view> </view>
@ -13,27 +13,44 @@
<view class="rate"> <view class="rate">
<view class="r-title">当前心率数值</view> <view class="r-title">当前心率数值</view>
<view class="wrap"> <view class="wrap">
<input class="input" placeholder-class="input-place" type="number" placeholder="00" maxlength="{{3}}" /> <input class="input" placeholder-class="input-place" type="number" placeholder="00" maxlength="{{3}}" value="{{heartRate}}" bindinput="onHeartRateInput" />
<view class="unit">次/分</view> <view class="unit">次/分</view>
</view> </view>
</view> </view>
<view class="form-item"> <view class="form-item">
<view class="form-label">日期</view> <view class="form-label">日期时间</view>
<picker mode="date"> <view class="date" bind:tap="showDatetimePicker">
<view class="date"> <view class="content" data-place="请选择日期时间">{{recordDateTime}}</view>
<view class="content" data-place="请选择日期"></view> <van-icon class="icon" name="arrow-down" />
<van-icon class="icon" name="arrow-down" /> </view>
</view>
</picker>
</view> </view>
<view class="form-item"> <view class="form-item">
<view class="form-label">其他备注</view> <view class="form-label">其他备注</view>
<textarea class="txa" placeholder-class="txa-place" placeholder="请输入备注内容" maxlength="{{500}}"></textarea> <textarea class="txa" placeholder-class="txa-place" placeholder="请输入备注内容" value="{{remark}}" bindinput="onRemarkInput" maxlength="{{500}}"></textarea>
</view> </view>
<checkbox class="check">PSVT发作</checkbox> <checkbox-group bind:change="onPsvtAttackChange">
<checkbox class="check" value="1" checked="{{isPsvtAttack === 1}}">PSVT发作</checkbox>
</checkbox-group>
</view> </view>
<view class="page-footer"> <view class="page-footer">
<view class="cancel">取消</view> <view class="cancel" bind:tap="handleBack">取消</view>
<view class="send">保存记录</view> <view class="send" bind:tap="handleSubmit">保存记录</view>
</view> </view>
</view> </view>
<van-popup show="{{datetimePickerShow}}" position="bottom" round bind:close="hideDatetimePicker">
<van-datetime-picker
type="datetime"
value="{{datetimeValue}}"
bind:confirm="onDatetimeConfirm"
bind:cancel="hideDatetimePicker"
/>
</van-popup>
<popup
show="{{popupShow}}"
type="{{popupType}}"
params="{{popupParams}}"
bind:ok="handlePopupOk"
bind:cancel="handlePopupCancel"
></popup>

8
src/pages/index/index.scss

@ -150,6 +150,13 @@ page {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: flex-end; justify-content: flex-end;
.title {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
} }
} }
} }
@ -210,6 +217,7 @@ page {
} }
.i-list { .i-list {
margin: 32rpx 30rpx 0; margin: 32rpx 30rpx 0;
min-height: 80vh;
.list-card { .list-card {
margin-top: 32rpx; margin-top: 32rpx;
padding: 32rpx; padding: 32rpx;

13
src/pages/index/index.ts

@ -22,11 +22,11 @@ Page({
sectionList: [] as Array<{ code: string; visible: boolean; subList: any[] }>, sectionList: [] as Array<{ code: string; visible: boolean; subList: any[] }>,
moduleVisible: { moduleVisible: {
health: true, health: true,
'spread1': true, spread1: true,
'video-big': true, 'video-big': true,
'spread2': true, spread2: true,
'qiye-wx': true, 'qiye-wx': true,
'education': true, education: true,
} as Record<string, boolean>, } as Record<string, boolean>,
}, },
onLoad() { onLoad() {
@ -51,10 +51,7 @@ Page({
}).then((res: any) => { }).then((res: any) => {
const list = res || [] const list = res || []
list.forEach((item: any) => { list.forEach((item: any) => {
if ( if ((item.code === 'spread1' || item.code === 'spread2' || item.code === 'serviceConf') && item.subList) {
(item.code === 'spread1' || item.code === 'spread2' || item.code === 'serviceConf') &&
item.subList
) {
item.subList = item.subList.filter((subItem: any) => subItem.showStatus == 1) item.subList = item.subList.filter((subItem: any) => subItem.showStatus == 1)
} }
}) })
@ -70,8 +67,8 @@ Page({
const conf = list.find((item: any) => item.code === code) const conf = list.find((item: any) => item.code === code)
return { return {
code, code,
visible: conf ? conf.showStatus == 1 : false,
subList: conf?.subList || [], subList: conf?.subList || [],
visible: conf ? (conf.showStatus == 1 && (conf.subList || []).length > 0) : false,
} }
}) })
.sort((a, b) => { .sort((a, b) => {

20
src/pages/index/index.wxml

@ -25,7 +25,14 @@
<!-- code: spread1 首页banner --> <!-- code: spread1 首页banner -->
<view class="banner" wx:if="{{item.code==='spread1' && item.visible}}"> <view class="banner" wx:if="{{item.code==='spread1' && item.visible}}">
<swiper class="swiper1"> <swiper class="swiper1">
<swiper-item wx:for="{{item.subList}}" wx:key="subIndex" wx:for-item="subItem" wx:for-index="subIndex" data-linkurl="{{subItem.linkUrl}}" bind:tap="handleBannerTap"> <swiper-item
wx:for="{{item.subList}}"
wx:key="subIndex"
wx:for-item="subItem"
wx:for-index="subIndex"
data-linkurl="{{subItem.linkUrl}}"
bind:tap="handleBannerTap"
>
<image class="s-img" mode="aspectFill" src="{{subItem.img}}"></image> <image class="s-img" mode="aspectFill" src="{{subItem.img}}"></image>
</swiper-item> </swiper-item>
</swiper> </swiper>
@ -51,7 +58,14 @@
<!-- code: spread2 banner2模块 --> <!-- code: spread2 banner2模块 -->
<view class="banner" wx:if="{{item.code==='spread2' && item.visible}}"> <view class="banner" wx:if="{{item.code==='spread2' && item.visible}}">
<swiper class="swiper2"> <swiper class="swiper2">
<swiper-item wx:for="{{item.subList}}" wx:key="subIndex" wx:for-item="subItem" wx:for-index="subIndex" data-linkurl="{{subItem.linkUrl}}" bind:tap="handleBannerTap"> <swiper-item
wx:for="{{item.subList}}"
wx:key="subIndex"
wx:for-item="subItem"
wx:for-index="subIndex"
data-linkurl="{{subItem.linkUrl}}"
bind:tap="handleBannerTap"
>
<image class="s-img" mode="aspectFill" src="{{subItem.img}}"></image> <image class="s-img" mode="aspectFill" src="{{subItem.img}}"></image>
</swiper-item> </swiper-item>
</swiper> </swiper>
@ -112,8 +126,8 @@
</view> </view>
</view> </view>
</view> </view>
<pagination pagination="{{pagination}}" />
</view> </view>
<pagination pagination="{{pagination}}" />
</view> </view>
</view> </view>

2
src/pages/myCollection/index.ts

@ -19,7 +19,7 @@ Page({
count: 0, count: 0,
}, },
}, },
onLoad() { onShow() {
app.waitLogin({ type: 0 }).then(() => { app.waitLogin({ type: 0 }).then(() => {
this.getVideoList() this.getVideoList()
this.getArticleList() this.getArticleList()

110
src/pages/videoList/index.scss

@ -5,6 +5,7 @@ page {
.page-title { .page-title {
font-size: 36rpx; font-size: 36rpx;
color: rgba(51, 51, 51, 1); color: rgba(51, 51, 51, 1);
padding-right: 100rpx;
} }
.page { .page {
@ -74,64 +75,75 @@ page {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 48rpx 30rpx; gap: 48rpx 30rpx;
.card { .card-wrap {
display: block; position: relative;
width: 100%; .hot {
overflow: hidden; position: absolute;
.photo { top: -10rpx;
position: relative; left: 24rpx;
width: 104rpx;
height: 48rpx;
z-index: 1;
}
.card {
display: block;
width: 100%; width: 100%;
height: 442rpx;
border-radius: 32rpx;
overflow: hidden; overflow: hidden;
.p-img { .photo {
display: block; position: relative;
width: 100%; width: 100%;
height: 100%; height: 442rpx;
} border-radius: 32rpx;
.stat { overflow: hidden;
position: absolute; .p-img {
bottom: 0; display: block;
left: 0; width: 100%;
width: 100%; height: 100%;
padding: 0 12rpx; }
height: 104rpx; .stat {
box-sizing: border-box; position: absolute;
background: linear-gradient(180deg, rgba(2, 2, 2, 0) 0%, rgba(3, 3, 3, 0.11) 20.97%, #090909 100%); bottom: 0;
backdrop-filter: opacity(67%); left: 0;
display: flex; width: 100%;
align-items: center; padding: 0 12rpx;
justify-content: flex-end; height: 104rpx;
gap: 8rpx; box-sizing: border-box;
.s-item { background: linear-gradient(180deg, rgba(2, 2, 2, 0) 0%, rgba(3, 3, 3, 0.11) 20.97%, #090909 100%);
padding: 48rpx 12rpx 24rpx; backdrop-filter: opacity(67%);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end;
gap: 8rpx; gap: 8rpx;
font-size: 28rpx; .s-item {
color: rgba(255, 255, 255, 1); padding: 48rpx 12rpx 24rpx;
.icon { display: flex;
width: 32rpx; align-items: center;
height: 32rpx; gap: 8rpx;
} font-size: 28rpx;
&.active1 { color: rgba(255, 255, 255, 1);
color: rgba(234, 88, 26, 1); .icon {
width: 32rpx;
height: 32rpx;
}
&.active1 {
color: rgba(234, 88, 26, 1);
}
} }
} }
} }
} .title {
.title { margin-top: 24rpx;
margin-top: 24rpx; height: 80rpx;
height: 80rpx; padding: 0 12rpx;
padding: 0 12rpx; color: #2a3544;
color: #2a3544; font-size: 28rpx;
font-size: 28rpx; line-height: 40rpx;
line-height: 40rpx; overflow: hidden;
overflow: hidden; text-overflow: ellipsis;
text-overflow: ellipsis; display: -webkit-box;
display: -webkit-box; -webkit-line-clamp: 2;
-webkit-line-clamp: 2; -webkit-box-orient: vertical;
-webkit-box-orient: vertical; }
} }
} }
} }

41
src/pages/videoList/index.wxml

@ -55,32 +55,39 @@
</view> </view>
<view class="list"> <view class="list">
<view <view
class="card" class="card-wrap"
wx:for="{{videoList}}" wx:for="{{videoList}}"
wx:key="Id" wx:key="Id"
bind:tap="handleDetail" bind:tap="handleDetail"
data-id="{{item.Id}}" data-id="{{item.Id}}"
data-index="{{index}}" data-index="{{index}}"
> >
<view class="photo"> <view
<image class="p-img" mode="aspectFill" src="{{item.ImageUrl}}"></image> class="hot"
<view class="stat"> wx:if="{{item.IsRecommend==1}}"
<view class="s-item"> style="background: url('{{imageUrl}}bg16.png?t={{Timestamp}}') no-repeat top center/100%"
<image class="icon" src="{{imageUrl}}icon8-1.png?t={{Timestamp}}"></image> ></view>
{{item.OpenNum}} <view class="card">
</view> <view class="photo">
<view class="s-item"> <image class="p-img" mode="aspectFill" src="{{item.ImageUrl}}"></image>
<image <view class="stat">
wx:if="{{item.IsCompliment==1}}" <view class="s-item">
class="icon" <image class="icon" src="{{imageUrl}}icon8-1.png?t={{Timestamp}}"></image>
src="{{imageUrl}}icon9-active.png?t={{Timestamp}}" {{item.OpenNum}}
></image> </view>
<image wx:else class="icon" src="{{imageUrl}}icon9-1.png?t={{Timestamp}}"></image> <view class="s-item">
<view class="num {{item.IsCompliment ? 'active1' : ''}}">{{item.ComplimentNum || 0}}</view> <image
wx:if="{{item.IsCompliment==1}}"
class="icon"
src="{{imageUrl}}icon9-active.png?t={{Timestamp}}"
></image>
<image wx:else class="icon" src="{{imageUrl}}icon9-1.png?t={{Timestamp}}"></image>
<view class="num {{item.IsCompliment ? 'active1' : ''}}">{{item.ComplimentNum || 0}}</view>
</view>
</view> </view>
</view> </view>
<view class="title">{{item.Title}}</view>
</view> </view>
<view class="title">{{item.Title}}</view>
</view> </view>
</view> </view>
<pagination pagination="{{pagination}}" /> <pagination pagination="{{pagination}}" />

Loading…
Cancel
Save