62 changed files with 4637 additions and 279 deletions
@ -0,0 +1,134 @@
@@ -0,0 +1,134 @@
|
||||
# AGENTS.md - 信达小程序 (Xinda Mini Program) |
||||
|
||||
WeChat Mini Program for thyroid eye disease patient management. Dual-mode app serving both patients (患者端) and doctors (医生端). |
||||
|
||||
## Project Type |
||||
|
||||
- **Framework**: WeChat Mini Program v3.7.7 |
||||
- **Language**: TypeScript (strict mode) |
||||
- **Styling**: SCSS/Sass via `useCompilerPlugins` |
||||
- **UI Library**: Vant Weapp (@vant/weapp) |
||||
- **Renderer**: Skyline enabled |
||||
- **App ID**: `wxf9ce8010f1ad24aa` (dev), `wx71ac9c27c3c3e3f4` (prod) |
||||
|
||||
## Directory Structure |
||||
|
||||
``` |
||||
src/ |
||||
├── pages/ # Doctor-side main pages (医生端) |
||||
├── patient/pages/ # Patient-side pages (subpackage) |
||||
├── gift/pages/ # DTP pharmacy pages (subpackage) |
||||
├── doc/pages/ # Privacy/terms documentation (subpackage) |
||||
├── components/ # Shared components |
||||
├── utils/ # Request, page/component wrappers, utilities |
||||
├── app.ts # App entry with global data |
||||
└── config.ts # Environment configs per appId |
||||
``` |
||||
|
||||
## Key Conventions |
||||
|
||||
### Path Aliases |
||||
- `@/*` → `src/*` (configured in tsconfig.json and app.json `resolveAlias`) |
||||
- Use `@/utils/request` not relative paths |
||||
|
||||
### User Types & Routing |
||||
Login types enforced in `app.ts`: |
||||
- `0`: Not logged in |
||||
- `1`: Patient (患者) → routes to `/patient/pages/*` |
||||
- `2`: Doctor (医生) → routes to `/pages/*` |
||||
|
||||
Use `app.zdWaitLogin()` to guard pages that require login. |
||||
|
||||
### Page/Component Wrappers |
||||
`app.ts` overrides global `Page` and `Component` with wrappers from `utils/page.ts` and `utils/component.ts`: |
||||
- Auto-sets `imageUrl` and `Timestamp` on page load |
||||
- Auto-handles navbar background on scroll |
||||
- Provides default share behavior |
||||
|
||||
### Modal Colors (Required) |
||||
All `wx.showModal` must use: |
||||
```ts |
||||
wx.showModal({ |
||||
confirmColor: '#8c75d0', |
||||
cancelColor: '#141515', |
||||
}) |
||||
``` |
||||
|
||||
## Available Commands |
||||
|
||||
```bash |
||||
# Lint and auto-fix (only command available) |
||||
npm run lint:fix |
||||
|
||||
# Install dependencies (pnpm preferred based on lockfile) |
||||
pnpm install |
||||
|
||||
# Build: Use WeChat Developer Tools |
||||
# - Import project with src/ as root |
||||
# - project.config.json at repo root |
||||
``` |
||||
|
||||
## NPM Dependencies |
||||
|
||||
**Critical**: After `npm install`, run **Tools → Build npm** in WeChat Developer Tools to generate `miniprogram_npm/`. This is required for Vant and other packages. |
||||
|
||||
Key dependencies: |
||||
- `@vant/weapp`: UI components |
||||
- `miniprogram-licia`: Utility library (available as `licia`) |
||||
- `dayjs`: Date handling |
||||
- `mp-html`: Rich HTML rendering |
||||
|
||||
## Images & Assets |
||||
|
||||
**Images are stored in SVN, not git.** |
||||
- SVN URL: `svn://39.106.86.127:28386/projects/xd/proj_src/shop/frontend/web/xd/` |
||||
- Local path: `src/images/` (gitignored) |
||||
- Excluded from upload via `project.config.json` packOptions |
||||
- Only `/images/tabbar/*` is included in uploads |
||||
|
||||
Image URL pattern: |
||||
``` |
||||
{{imageUrl}}/path/to/image.png?t={{Timestamp}} |
||||
``` |
||||
|
||||
## TypeScript Configuration |
||||
|
||||
- Strict mode enabled |
||||
- `noImplicitAny: false` (allows implicit any) |
||||
- Paths: `@/*` mapped to `src/*` |
||||
- Types: `miniprogram-api-typings` for WX API |
||||
|
||||
Global types in `typings/index.d.ts`: |
||||
- `IAppOption`: Global app instance interface |
||||
- `pageType`: 0 | 1 | 2 for user types |
||||
- `wx.ajax`: Extended request method |
||||
|
||||
## ESLint & Formatting |
||||
|
||||
- Config: `@antfu/eslint-config` (flat config in `eslint.config.js`) |
||||
- Prettier: 2-space tabs, no semis, single quotes, trailing commas |
||||
- WXML files parsed as HTML, WXSS as CSS |
||||
- Globals defined: `wx`, `App`, `Page`, `Component`, `getCurrentPages`, etc. |
||||
|
||||
## Environment Configuration |
||||
|
||||
Selected by App ID in `src/config.ts`: |
||||
- `wxf9ce8010f1ad24aa`: Dev/Staging (hbraas.com) |
||||
- `wx71ac9c27c3c3e3f4`: Production (hbsaas.com) |
||||
|
||||
App reads `wx.getAccountInfoSync().miniProgram.appId` on launch to select config. |
||||
|
||||
## Testing & Development |
||||
|
||||
- No unit test framework configured |
||||
- Manual testing via WeChat Developer Tools |
||||
- `project.private.config.json` has hot reload enabled (`compileHotReLoad: true`) |
||||
- Predefined test pages in `project.private.config.json` condition list |
||||
|
||||
## Common Gotchas |
||||
|
||||
1. **NPM packages**: Must run "Build npm" in WeChat tools after install |
||||
2. **Images**: Will 404 if SVN images not checked out to `src/images/` |
||||
3. **Subpackages**: Patient pages are in `patient/` subpackage, not main package |
||||
4. **Skyline**: Enabled in rendererOptions, some components may behave differently |
||||
5. **Login flow**: App automatically calls `startLogin()` on launch; pages must wait via `app.zdWaitLogin()` |
||||
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
{ |
||||
"component": true, |
||||
"usingComponents": { |
||||
"van-icon": "@vant/weapp/icon/index" |
||||
} |
||||
} |
||||
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
.preview-container { |
||||
position: fixed; |
||||
top: 0; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
background: #000; |
||||
z-index: 1000; |
||||
display: flex; |
||||
flex-direction: column; |
||||
opacity: 0; |
||||
visibility: hidden; |
||||
transition: |
||||
opacity 0.3s, |
||||
visibility 0.3s; |
||||
|
||||
&.show { |
||||
opacity: 1; |
||||
visibility: visible; |
||||
} |
||||
} |
||||
|
||||
// 图片展示区域 |
||||
.image-wrapper { |
||||
flex: 1; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
overflow: hidden; |
||||
|
||||
.preview-image { |
||||
display: block; |
||||
width: 100%; |
||||
height: 100%; |
||||
} |
||||
} |
||||
|
||||
// 底部操作栏 |
||||
.action-bar { |
||||
position: absolute; |
||||
bottom: 0; |
||||
left: 0; |
||||
right: 0; |
||||
padding: 40rpx; |
||||
padding-bottom: calc(40rpx + env(safe-area-inset-bottom)); |
||||
background: #fff; |
||||
display: flex; |
||||
gap: 32rpx; |
||||
|
||||
.btn { |
||||
flex: 1; |
||||
height: 88rpx; |
||||
border-radius: 44rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 32rpx; |
||||
font-weight: 500; |
||||
|
||||
&-delete { |
||||
border: 1px solid #b982ff; |
||||
color: #b982ff; |
||||
background: #fff; |
||||
} |
||||
|
||||
&-retake { |
||||
background: linear-gradient(0deg, #e98ff8 0%, #b073ff 100%); |
||||
color: #fff; |
||||
} |
||||
|
||||
&:active { |
||||
opacity: 0.8; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,56 @@
@@ -0,0 +1,56 @@
|
||||
Component({ |
||||
properties: {}, |
||||
|
||||
data: { |
||||
visible: false, |
||||
src: '', |
||||
}, |
||||
|
||||
methods: { |
||||
// 返回/关闭
|
||||
handleBack() { |
||||
this.triggerEvent('close') |
||||
}, |
||||
|
||||
// 更多操作
|
||||
handleMore() { |
||||
this.triggerEvent('more') |
||||
}, |
||||
|
||||
// 预览/查看
|
||||
handlePreview(src) { |
||||
if (src) { |
||||
this.setData({ |
||||
visible: true, |
||||
src, |
||||
}) |
||||
} |
||||
}, |
||||
handleHidePreview() { |
||||
this.setData({ |
||||
visible: false, |
||||
sec: '', |
||||
}) |
||||
}, |
||||
|
||||
// 删除
|
||||
handleDelete() { |
||||
wx.showModal({ |
||||
title: '提示', |
||||
content: '确定要删除这张照片吗?', |
||||
success: (res) => { |
||||
if (res.confirm) { |
||||
this.handleHidePreview() |
||||
this.triggerEvent('delete') |
||||
} |
||||
}, |
||||
}) |
||||
}, |
||||
|
||||
// 重拍
|
||||
handleRetake() { |
||||
this.handleHidePreview() |
||||
this.triggerEvent('retake') |
||||
}, |
||||
}, |
||||
}) |
||||
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
<view class="preview-container {{visible ? 'show' : ''}}"> |
||||
<!-- 图片展示区域 --> |
||||
<view class="image-wrapper"> |
||||
<image class="preview-image" src="{{src}}" mode="aspectFit" /> |
||||
</view> |
||||
|
||||
<!-- 底部操作栏 --> |
||||
<view class="action-bar"> |
||||
<view class="btn btn-delete" bindtap="handleDelete">删除</view> |
||||
<view class="btn btn-retake" bindtap="handleRetake">重拍</view> |
||||
</view> |
||||
</view> |
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
{ |
||||
"usingComponents": { |
||||
"navbar": "/components/navbar/index", |
||||
"van-icon": "@vant/weapp/icon/index" |
||||
}, |
||||
"navigationBarTitleText": "记录" |
||||
} |
||||
@ -0,0 +1,168 @@
@@ -0,0 +1,168 @@
|
||||
.page { |
||||
.container { |
||||
position: relative; |
||||
padding: 40rpx 40rpx 240rpx; |
||||
border-radius: 32rpx 32rpx 0 0; |
||||
background-color: #fff; |
||||
.benchmark { |
||||
position: absolute; |
||||
top: 0; |
||||
right: 0; |
||||
padding-top: 8rpx; |
||||
text-align: center; |
||||
width: 144rpx; |
||||
height: 64rpx; |
||||
font-size: 28rpx; |
||||
color: #fff; |
||||
line-height: 32rpx; |
||||
} |
||||
.date { |
||||
font-size: 40rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
} |
||||
.total { |
||||
margin-top: 32rpx; |
||||
padding-top: 48rpx; |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
border-top: 1px solid rgba(173, 172, 178, 0.1); |
||||
display: flex; |
||||
gap: 22rpx; |
||||
align-items: center; |
||||
.num { |
||||
font-size: 40rpx; |
||||
color: #b073ff; |
||||
} |
||||
&::before { |
||||
content: ''; |
||||
width: 8rpx; |
||||
height: 32rpx; |
||||
background: #b982ff; |
||||
border-radius: 44rpx 44rpx 44rpx 44rpx; |
||||
} |
||||
} |
||||
.banner { |
||||
margin-top: 24rpx; |
||||
padding: 32rpx; |
||||
background: #f6f8f9; |
||||
border-radius: 32rpx 32rpx 32rpx 32rpx; |
||||
border: 2rpx solid #ffffff; |
||||
.title { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
} |
||||
.row { |
||||
margin-top: 24rpx; |
||||
display: flex; |
||||
gap: 24rpx; |
||||
text-align: center; |
||||
.col { |
||||
padding: 24rpx; |
||||
flex: 1; |
||||
background-color: #fff; |
||||
border-radius: 16rpx; |
||||
.name { |
||||
font-size: 28rpx; |
||||
color: #211d2e; |
||||
line-height: 32rpx; |
||||
} |
||||
.content { |
||||
margin-top: 16rpx; |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: baseline; |
||||
gap: 8rpx; |
||||
.num { |
||||
font-size: 56rpx; |
||||
color: #b073ff; |
||||
font-weight: bold; |
||||
} |
||||
.sub { |
||||
font-size: 28rpx; |
||||
color: #211d2e; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.card { |
||||
margin-top: 48rpx; |
||||
.card-title { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 16rpx; |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
&::before { |
||||
content: ''; |
||||
width: 8rpx; |
||||
height: 32rpx; |
||||
background: #b982ff; |
||||
border-radius: 44rpx 44rpx 44rpx 44rpx; |
||||
} |
||||
} |
||||
.card-container { |
||||
margin-top: 24rpx; |
||||
display: grid; |
||||
grid-template-columns: repeat(2, 320rpx); |
||||
justify-content: space-between; |
||||
gap: 30rpx; |
||||
.card-item { |
||||
.photo { |
||||
display: block; |
||||
width: 100%; |
||||
height: 320rpx; |
||||
border-radius: 24rpx; |
||||
} |
||||
.name { |
||||
margin-top: 16rpx; |
||||
font-size: 28rpx; |
||||
color: #adacb2; |
||||
text-align: center; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.footer { |
||||
position: fixed; |
||||
bottom: 0; |
||||
left: 0; |
||||
padding: 20rpx 30rpx 60rpx; |
||||
width: 100%; |
||||
box-sizing: border-box; |
||||
margin-top: 46rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 22rpx; |
||||
background-color: #fff; |
||||
box-shadow: 0 -10rpx 10rpx rgba(204, 204, 204, 0.1); |
||||
.btn1 { |
||||
flex: 1; |
||||
height: 88rpx; |
||||
font-size: 36rpx; |
||||
color: #b982ff; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
border: 1px solid #b982ff; |
||||
background-color: #fff; |
||||
border-radius: 100rpx 100rpx 100rpx 100rpx; |
||||
} |
||||
.btn2 { |
||||
flex: 1; |
||||
height: 88rpx; |
||||
font-size: 36rpx; |
||||
color: #ffffff; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
background: linear-gradient(0deg, #e98ff8 0%, #b073ff 100%); |
||||
border-radius: 100rpx 100rpx 100rpx 100rpx; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,88 @@
@@ -0,0 +1,88 @@
|
||||
const _app = getApp<IAppOption>() |
||||
|
||||
Page({ |
||||
data: { |
||||
history: { |
||||
frontend: [ |
||||
{ |
||||
title: '正面睁眼照', |
||||
content: '平视,目光看向镜头方向,自然睁眼,不眯眼、不瞪眼。', |
||||
}, |
||||
{ |
||||
title: '正面闭眼照', |
||||
content: '正对镜头,面部居中,自然放松,双眼轻轻闭合,不皱眉、不挤眼。', |
||||
}, |
||||
{ |
||||
title: '正面仰头照', |
||||
content: '拍摄时,正对镜头,面部居中,头部自然向上仰至约 45°,双眼同步平视,保持自然睁眼、不眯眼。', |
||||
}, |
||||
], |
||||
backend: [ |
||||
{ |
||||
title: '左侧-90°', |
||||
content: '身体与头部完全转向右侧,呈标准 90° 侧面,仅可见左侧眼睛。', |
||||
}, |
||||
{ |
||||
title: '右侧-90°', |
||||
content: '身体与头部完全转向左侧,呈标准 90° 侧面,仅可见右侧眼睛。', |
||||
}, |
||||
{ |
||||
title: '左侧-45°', |
||||
content: '身体与头部转向右前方 45°。', |
||||
}, |
||||
{ |
||||
title: '右侧-45°', |
||||
content: '身体与头部转向左前方 45°', |
||||
}, |
||||
], |
||||
other: [ |
||||
{ |
||||
title: '正面眼睛上看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛下看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛左看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛右看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛左上看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛右上看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛左下看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛右下看', |
||||
content: '', |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
onLoad() {}, |
||||
|
||||
handlePopupOk() { |
||||
this.setData({ |
||||
popupShow: false, |
||||
}) |
||||
}, |
||||
handlePopupCancel() { |
||||
this.setData({ |
||||
popupShow: false, |
||||
}) |
||||
}, |
||||
}) |
||||
|
||||
export {} |
||||
@ -0,0 +1,74 @@
@@ -0,0 +1,74 @@
|
||||
<navbar fixed title="记录" custom-style="background:{{background}}"> |
||||
<van-icon name="arrow-left" slot="left" size="18px" color="#000" bind:tap="handleBack" /> |
||||
</navbar> |
||||
|
||||
<view |
||||
class="page" |
||||
style="background: url('{{imageUrl}}bg10.png?t={{Timestamp}}') no-repeat top center/100% 610rpx;padding-top:{{pageTop+16}}px;" |
||||
> |
||||
<view class="container"> |
||||
<view class="benchmark" style="background: url('/images/bg56.png') no-repeat top center/100%">基准照</view> |
||||
<view class="date">2026-04-02</view> |
||||
<view class="total"> |
||||
当前记录对应的替妥尤单抗使用次数: |
||||
<text class="num">1</text> |
||||
</view> |
||||
<view class="banner"> |
||||
<view class="title">眼球突出度测量记录</view> |
||||
<view class="row"> |
||||
<view class="col"> |
||||
<view class="name">右眼</view> |
||||
<view class="content"> |
||||
<view class="num">12</view> |
||||
<view class="sub">MM</view> |
||||
</view> |
||||
</view> |
||||
<view class="col"> |
||||
<view class="name">眶间距</view> |
||||
<view class="content"> |
||||
<view class="num">12</view> |
||||
<view class="sub">MM</view> |
||||
</view> |
||||
</view> |
||||
<view class="col"> |
||||
<view class="name">左眼</view> |
||||
<view class="content"> |
||||
<view class="num">12</view> |
||||
<view class="sub">MM</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="card-title">正面</view> |
||||
<view class="card-container"> |
||||
<view class="card-item" wx:for="{{history.frontend}}" wx:key="index"> |
||||
<image class="photo" mode="aspectFill" src="{{imageUrl}}note-demo1.png?t={{Timestamp}}"></image> |
||||
<view class="name">{{item.title}}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="card-title">侧面</view> |
||||
<view class="card-container"> |
||||
<view class="card-item" wx:for="{{history.backend}}" wx:key="index"> |
||||
<image class="photo" mode="aspectFill" src="{{imageUrl}}note-demo1.png?t={{Timestamp}}"></image> |
||||
<view class="name">{{item.title}}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="card-title">眼球运动八个方向</view> |
||||
<view class="card-container"> |
||||
<view class="card-item" wx:for="{{history.other}}" wx:key="index"> |
||||
<image class="photo" mode="aspectFill" src="{{imageUrl}}note-demo1.png?t={{Timestamp}}"></image> |
||||
<view class="name">{{item.title}}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="footer"> |
||||
<view class="btn1">眼突度 对比</view> |
||||
<view class="btn2">照片 对比</view> |
||||
</view> |
||||
</view> |
||||
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
{ |
||||
"navigationBarTitleText": "xxx的眼突度对比", |
||||
"navigationStyle": "default", |
||||
"usingComponents": {} |
||||
} |
||||
@ -0,0 +1,148 @@
@@ -0,0 +1,148 @@
|
||||
.container { |
||||
min-height: 100vh; |
||||
background-color: #f6f8f9; |
||||
padding: 16rpx 30rpx; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.table-wrapper { |
||||
background-color: #eee2ff; |
||||
border-radius: 13rpx; |
||||
border: 1rpx solid #fff; |
||||
overflow: hidden; |
||||
} |
||||
|
||||
/* 表头样式 */ |
||||
.table-header { |
||||
display: flex; |
||||
background-color: #f7f0ff; |
||||
|
||||
&.sticky { |
||||
position: sticky; |
||||
top: 0; |
||||
z-index: 100; |
||||
} |
||||
} |
||||
|
||||
.th { |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: center; |
||||
align-items: center; |
||||
color: #b982ff; |
||||
font-size: 28rpx; |
||||
font-weight: 500; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.th-date { |
||||
width: 200rpx; |
||||
height: 120rpx; |
||||
border-right: 1rpx solid #eee4ff; |
||||
justify-content: flex-end; |
||||
padding-bottom: 20rpx; |
||||
} |
||||
|
||||
.th-eye { |
||||
flex: 1; |
||||
padding: 0; |
||||
border-right: 1rpx solid #eee4ff; |
||||
} |
||||
|
||||
.th-eye-title { |
||||
text-align: center; |
||||
padding: 16rpx 0; |
||||
border-bottom: 1rpx solid #eee4ff; |
||||
width: 100%; |
||||
font-size: 28rpx; |
||||
height: 60rpx; |
||||
box-sizing: border-box; |
||||
} |
||||
|
||||
.th-eye-sub { |
||||
display: flex; |
||||
width: 100%; |
||||
height: 60rpx; |
||||
} |
||||
|
||||
.th-sub-item { |
||||
flex: 1; |
||||
text-align: center; |
||||
border-right: 1rpx solid #eee4ff; |
||||
font-size: 28rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
|
||||
&:last-child { |
||||
border-right: none; |
||||
} |
||||
} |
||||
|
||||
.th-count { |
||||
width: 120rpx; |
||||
text-align: center; |
||||
line-height: 1.3; |
||||
font-size: 28rpx; |
||||
height: 120rpx; |
||||
justify-content: center; |
||||
} |
||||
|
||||
/* 表格内容样式 */ |
||||
.table-body { |
||||
background-color: #eee2ff; |
||||
} |
||||
|
||||
.tr { |
||||
display: flex; |
||||
height: 100rpx; |
||||
|
||||
&:last-child { |
||||
.td-date, |
||||
.td-eye, |
||||
.td-count { |
||||
border-bottom: none; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.td { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
color: #211d2e; |
||||
font-size: 32rpx; |
||||
font-weight: 500; |
||||
box-sizing: border-box; |
||||
height: 100rpx; |
||||
} |
||||
|
||||
.td-date { |
||||
width: 200rpx; |
||||
background-color: #ffffff; |
||||
border-right: 1rpx solid #eee4ff; |
||||
border-bottom: 1rpx solid #eee4ff; |
||||
} |
||||
|
||||
.td-eye { |
||||
flex: 1; |
||||
display: flex; |
||||
background-color: #fff; |
||||
border-bottom: 1rpx solid #eee4ff; |
||||
} |
||||
|
||||
.td-eye-item { |
||||
flex: 1; |
||||
text-align: center; |
||||
border-right: 1rpx solid #eee4ff; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
height: 100rpx; |
||||
} |
||||
|
||||
.td-count { |
||||
width: 120rpx; |
||||
background-color: #ffffff; |
||||
border-bottom: 1rpx solid #eee4ff; |
||||
} |
||||
@ -0,0 +1,25 @@
@@ -0,0 +1,25 @@
|
||||
const _app = getApp<IAppOption>(); |
||||
|
||||
Page({ |
||||
data: { |
||||
dataList: [ |
||||
{ |
||||
date: '2026.1.5', |
||||
left: '40', |
||||
spacing: '40', |
||||
right: '40', |
||||
count: '30', |
||||
}, |
||||
{ |
||||
date: '2025.12.30', |
||||
left: '30', |
||||
spacing: '30', |
||||
right: '30', |
||||
count: '20', |
||||
}, |
||||
], |
||||
}, |
||||
onLoad() {}, |
||||
}); |
||||
|
||||
export {}; |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
<view class="container"> |
||||
<!-- 表格区域 --> |
||||
<view class="table-wrapper"> |
||||
<!-- 吸顶表头 --> |
||||
<view class="table-header sticky"> |
||||
<view class="th th-date">日期</view> |
||||
<view class="th th-eye"> |
||||
<view class="th-eye-title">眼突度(mm)</view> |
||||
<view class="th-eye-sub"> |
||||
<view class="th-sub-item">左侧</view> |
||||
<view class="th-sub-item">眶间距</view> |
||||
<view class="th-sub-item">右侧</view> |
||||
</view> |
||||
</view> |
||||
<view class="th th-count"> |
||||
<view>替妥尤</view> |
||||
<view>输注</view> |
||||
<view>次数</view> |
||||
</view> |
||||
</view> |
||||
|
||||
<!-- 表格内容 --> |
||||
<view class="table-body"> |
||||
<view class="tr" wx:for="{{dataList}}" wx:key="date"> |
||||
<view class="td td-date">{{item.date}}</view> |
||||
<view class="td td-eye"> |
||||
<view class="td-eye-item">{{item.left}}</view> |
||||
<view class="td-eye-item">{{item.spacing}}</view> |
||||
<view class="td-eye-item">{{item.right}}</view> |
||||
</view> |
||||
<view class="td td-count">{{item.count}}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
{ |
||||
"navigationStyle": "default", |
||||
"usingComponents": { |
||||
"van-icon": "@vant/weapp/icon/index" |
||||
}, |
||||
"navigationBarTitleText": "记录" |
||||
} |
||||
@ -0,0 +1,106 @@
@@ -0,0 +1,106 @@
|
||||
page { |
||||
background-color: #f6f8f9; |
||||
} |
||||
.page { |
||||
.total { |
||||
padding: 32rpx 40rpx; |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
} |
||||
.history-list { |
||||
padding: 0 40rpx 240rpx; |
||||
.list-item { |
||||
margin-bottom: 24rpx; |
||||
position: relative; |
||||
border-radius: 32rpx; |
||||
background-color: #fff; |
||||
padding: 32rpx; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
gap: 24rpx; |
||||
.benchmark { |
||||
position: absolute; |
||||
top: 0; |
||||
right: 0; |
||||
padding-top: 8rpx; |
||||
text-align: center; |
||||
width: 124rpx; |
||||
height: 64rpx; |
||||
font-size: 28rpx; |
||||
color: #ffa300; |
||||
line-height: 32rpx; |
||||
} |
||||
.photo { |
||||
width: 140rpx; |
||||
height: 140rpx; |
||||
border-radius: 16rpx; |
||||
} |
||||
.wrap { |
||||
flex: 1; |
||||
.date { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
} |
||||
.tag { |
||||
margin-top: 16rpx; |
||||
padding: 4rpx 12rpx; |
||||
display: inline-block; |
||||
font-size: 24rpx; |
||||
color: #b073ff; |
||||
background: rgba(176, 115, 255, 0.16); |
||||
border-radius: 6rpx 6rpx 6rpx 6rpx; |
||||
} |
||||
.rotate { |
||||
margin-top: 28rpx; |
||||
font-size: 28rpx; |
||||
color: #adacb2; |
||||
line-height: 1; |
||||
} |
||||
} |
||||
.more { |
||||
align-self: center; |
||||
width: 44rpx; |
||||
height: 44rpx; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.footer { |
||||
position: fixed; |
||||
bottom: 0; |
||||
left: 0; |
||||
padding: 20rpx 30rpx 60rpx; |
||||
width: 100%; |
||||
box-sizing: border-box; |
||||
margin-top: 46rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 22rpx; |
||||
background-color: #fff; |
||||
box-shadow: 0 -10rpx 10rpx rgba(204, 204, 204, 0.1); |
||||
.btn1 { |
||||
flex: 1; |
||||
height: 88rpx; |
||||
font-size: 36rpx; |
||||
color: #b982ff; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
border: 1px solid #b982ff; |
||||
background-color: #fff; |
||||
border-radius: 100rpx 100rpx 100rpx 100rpx; |
||||
} |
||||
.btn2 { |
||||
flex: 1; |
||||
height: 88rpx; |
||||
font-size: 36rpx; |
||||
color: #ffffff; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
background: linear-gradient(0deg, #e98ff8 0%, #b073ff 100%); |
||||
border-radius: 100rpx 100rpx 100rpx 100rpx; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,93 @@
@@ -0,0 +1,93 @@
|
||||
const _app = getApp<IAppOption>() |
||||
|
||||
Page({ |
||||
data: { |
||||
history: { |
||||
frontend: [ |
||||
{ |
||||
title: '正面睁眼照', |
||||
content: '平视,目光看向镜头方向,自然睁眼,不眯眼、不瞪眼。', |
||||
}, |
||||
{ |
||||
title: '正面闭眼照', |
||||
content: '正对镜头,面部居中,自然放松,双眼轻轻闭合,不皱眉、不挤眼。', |
||||
}, |
||||
{ |
||||
title: '正面仰头照', |
||||
content: '拍摄时,正对镜头,面部居中,头部自然向上仰至约 45°,双眼同步平视,保持自然睁眼、不眯眼。', |
||||
}, |
||||
], |
||||
backend: [ |
||||
{ |
||||
title: '左侧-90°', |
||||
content: '身体与头部完全转向右侧,呈标准 90° 侧面,仅可见左侧眼睛。', |
||||
}, |
||||
{ |
||||
title: '右侧-90°', |
||||
content: '身体与头部完全转向左侧,呈标准 90° 侧面,仅可见右侧眼睛。', |
||||
}, |
||||
{ |
||||
title: '左侧-45°', |
||||
content: '身体与头部转向右前方 45°。', |
||||
}, |
||||
{ |
||||
title: '右侧-45°', |
||||
content: '身体与头部转向左前方 45°', |
||||
}, |
||||
], |
||||
other: [ |
||||
{ |
||||
title: '正面眼睛上看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛下看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛左看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛右看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛左上看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛右上看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛左下看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛右下看', |
||||
content: '', |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
onLoad() {}, |
||||
handleDiffData() { |
||||
wx.navigateTo({ |
||||
url: '/pages/d_noteDiffData/index', |
||||
}) |
||||
}, |
||||
|
||||
handlePopupOk() { |
||||
this.setData({ |
||||
popupShow: false, |
||||
}) |
||||
}, |
||||
handlePopupCancel() { |
||||
this.setData({ |
||||
popupShow: false, |
||||
}) |
||||
}, |
||||
}) |
||||
|
||||
export {} |
||||
@ -0,0 +1,21 @@
@@ -0,0 +1,21 @@
|
||||
<view class="page"> |
||||
<view class="total">共X条日记记录</view> |
||||
<view class="history-list"> |
||||
<view class="list-item" bind:tap="handleHistory"> |
||||
<view class="benchmark" style="background: url('{{imageUrl}}bg50.png?t={{Timestamp}}') no-repeat top center/100%"> |
||||
基准照 |
||||
</view> |
||||
<image class="photo" src="{{imageUrl}}icon143.png?t={{Timestamp}}"></image> |
||||
<view class="wrap"> |
||||
<view class="date">2026-04-01</view> |
||||
<view class="tag">替妥尤单抗:2</view> |
||||
<view class="rotate">已上传1个角度</view> |
||||
</view> |
||||
<image class="more" src="{{imageUrl}}icon148.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
</view> |
||||
<view class="footer"> |
||||
<view class="btn1" bind:tap="handleDiffData">眼突度 对比</view> |
||||
<view class="btn2">照片 对比</view> |
||||
</view> |
||||
</view> |
||||
@ -1,41 +1,102 @@
@@ -1,41 +1,102 @@
|
||||
<view class="camera-container" wx:if="{{visible}}"> |
||||
<camera |
||||
class="camera" |
||||
device-position="{{devicePosition}}" |
||||
flash="{{flash}}" |
||||
binderror="onCameraError" |
||||
> |
||||
<view class="camera-frame"> |
||||
<view class="frame-corner left-top"></view> |
||||
<view class="frame-corner right-top"></view> |
||||
<view class="frame-corner left-bottom"></view> |
||||
<view class="frame-corner right-bottom"></view> |
||||
<camera class="camera" device-position="{{devicePosition}}" flash="{{flash}}" binderror="onCameraError"> |
||||
<view |
||||
class="camera-container" |
||||
style="background: url('{{imageUrl}}camera-bg.png?t={{Timestamp}}') no-repeat center/100%" |
||||
> |
||||
<view class="example {{exampleShow && 'active'}}" bind:tap="handleExample"> |
||||
<image class="icon" src="{{imageUrl}}icon159.png?t={{Timestamp}}"></image> |
||||
查看示范 |
||||
<view class="example-popup" hidden="{{!exampleShow}}"> |
||||
<view class="content">平视,目光看向镜头方向,自然睁眼,不眯眼、不瞪眼。</view> |
||||
<view class="photo-wrap"> |
||||
<image class="photo" src="{{imageUrl}}{{frame[type].exampleSrc}}.png?t={{Timestamp}}"></image> |
||||
<image class="label" src="{{imageUrl}}icon162.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view |
||||
class="camera-frame" |
||||
style="background: url('{{imageUrl}}{{frame[type].src}}.png?t={{Timestamp}}') no-repeat top center/100%" |
||||
> |
||||
<image wx:if="{{type==8}}" class="icon8" src="{{imageUrl}}icon163.png?t={{Timestamp}}"></image> |
||||
<block wx:elif="{{type==9}}"> |
||||
<image class="icon9-1" src="{{imageUrl}}icon163.png?t={{Timestamp}}"></image> |
||||
<image class="icon9-2" src="{{imageUrl}}icon163.png?t={{Timestamp}}"></image> |
||||
</block> |
||||
<image wx:elif="{{type==10}}" class="icon10" src="{{imageUrl}}icon163.png?t={{Timestamp}}"></image> |
||||
<image wx:elif="{{type==11}}" class="icon11" src="{{imageUrl}}icon163.png?t={{Timestamp}}"></image> |
||||
<image wx:elif="{{type==12}}" class="icon12" src="{{imageUrl}}icon163.png?t={{Timestamp}}"></image> |
||||
<image wx:elif="{{type==13}}" class="icon13" src="{{imageUrl}}icon163.png?t={{Timestamp}}"></image> |
||||
<block wx:elif="{{type==14}}"> |
||||
<image class="icon14-1" src="{{imageUrl}}icon163.png?t={{Timestamp}}"></image> |
||||
<image class="icon14-2" src="{{imageUrl}}icon163.png?t={{Timestamp}}"></image> |
||||
</block> |
||||
<image wx:elif="{{type==15}}" class="icon15" src="{{imageUrl}}icon163.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view> |
||||
<view class="tip">请将眼睛置于虚线框中心位置</view> |
||||
</view> |
||||
<view> |
||||
<view class="order"> |
||||
正面睁眼 |
||||
<view class="num">1</view> |
||||
<view class="m-num">/3</view> |
||||
</view> |
||||
</view> |
||||
<view class="controls"> |
||||
<view class="switch-btn" bindtap="switchCamera"> |
||||
<image class="icon" src="{{imageUrl}}icon160.png?t={{Timestamp}}"></image> |
||||
<view class="name">翻转</view> |
||||
</view> |
||||
<view class="control-btn" bindtap="takePhoto"> |
||||
<image class="icon" src="{{imageUrl}}icon161.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="block"></view> |
||||
</view> |
||||
</view> |
||||
</camera> |
||||
|
||||
<view class="close-btn" bindtap="closeCamera"> |
||||
<van-icon name="cross" size="20px" color="#fff" /> |
||||
</view> |
||||
|
||||
<view class="controls"> |
||||
<view class="control-btn switch-btn" bindtap="switchCamera"> |
||||
<van-icon name="reload" size="24px" color="#fff" /> |
||||
</view> |
||||
<!-- <view class="controls"> --> |
||||
<!-- <view class="control-btn switch-btn" bindtap="switchCamera"> --> |
||||
<!-- <van-icon name="reload" size="24px" color="#fff" /> --> |
||||
<!-- </view> --> |
||||
<!----> |
||||
<!-- <view class="control-btn capture-btn" bindtap="takePhoto"> --> |
||||
<!-- <view class="capture-inner"></view> --> |
||||
<!-- </view> --> |
||||
<!----> |
||||
<!-- <view class="control-btn flash-btn" bindtap="toggleFlash"> --> |
||||
<!-- <van-icon name="{{flash === 'off' ? 'closed-eye' : 'eye'}}" size="24px" color="#fff" /> --> |
||||
<!-- </view> --> |
||||
<!-- </view> --> |
||||
</view> |
||||
|
||||
<view class="control-btn capture-btn" bindtap="takePhoto"> |
||||
<view class="capture-inner"></view> |
||||
<van-popup |
||||
wx:if="{{selectShow}}" |
||||
bind:click-overlay="handleCancel" |
||||
round |
||||
z-index="{{100000}}" |
||||
show="{{ true }}" |
||||
custom-style="background:transparent;" |
||||
position="bottom" |
||||
safe-area-inset-bottom="{{false}}" |
||||
root-portal |
||||
> |
||||
<view class="popup-container"> |
||||
<view class="title"> |
||||
选择上传方式 |
||||
<van-icon name="cross" /> |
||||
</view> |
||||
|
||||
<view class="control-btn flash-btn" bindtap="toggleFlash"> |
||||
<van-icon name="{{flash === 'off' ? 'closed-eye' : 'eye'}}" size="24px" color="#fff" /> |
||||
</view> |
||||
</view> |
||||
|
||||
<view class="preview-section" wx:if="{{previewImage}}"> |
||||
<image class="preview-image" src="{{previewImage}}" mode="aspectFit" /> |
||||
<view class="preview-actions"> |
||||
<van-button type="default" round bindtap="retake">重拍</van-button> |
||||
<van-button type="primary" round custom-style="margin-left: 30rpx;" bindtap="usePhoto">使用照片</van-button> |
||||
<view class="select"> |
||||
<view class="item" bind:tap="handleCamera"> |
||||
<image class="icon" src="{{imageUrl}}icon157.png?t={{Timestamp}}"></image> |
||||
<view class="name">拍摄</view> |
||||
</view> |
||||
<view class="item" bind:tap="handlePicture"> |
||||
<image class="icon" src="{{imageUrl}}icon158.png?t={{Timestamp}}"></image> |
||||
<view class="name">从相册选择</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</van-popup> |
||||
|
||||
@ -1,78 +1,78 @@
@@ -1,78 +1,78 @@
|
||||
const app = getApp<IAppOption>(); |
||||
let timer = null as null | number; |
||||
|
||||
Page({ |
||||
data: { |
||||
mobile: "", |
||||
code: "", |
||||
|
||||
codeText: "发送验证码", |
||||
}, |
||||
onLoad() {}, |
||||
getCode() { |
||||
if (timer) return; |
||||
const mobile = this.data.mobile; |
||||
if (!mobile) { |
||||
wx.showToast({ |
||||
title: "手机号不能为空", |
||||
icon: "none", |
||||
}); |
||||
return; |
||||
} |
||||
// 验证手机号
|
||||
if (!/^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$/.test(mobile)) { |
||||
wx.showToast({ |
||||
title: "手机号格式不正确", |
||||
icon: "none", |
||||
}); |
||||
return; |
||||
} |
||||
wx.ajax({ |
||||
method: "POST", |
||||
url: "?r=zd/login/send-verify-code", |
||||
data: { |
||||
mobile, |
||||
}, |
||||
}).then((res) => { |
||||
console.log(res); |
||||
wx.showToast({ |
||||
icon: "none", |
||||
title: "验证码已发送~", |
||||
}); |
||||
let time = 60; |
||||
timer = setInterval(() => { |
||||
time--; |
||||
this.setData({ |
||||
codeText: time + "s后重新发送", |
||||
}); |
||||
if (time <= 0) { |
||||
clearInterval(timer as number); |
||||
timer = null; |
||||
this.setData({ |
||||
codeText: "发送验证码", |
||||
}); |
||||
} |
||||
}, 1000); |
||||
}); |
||||
}, |
||||
handleSubmit() { |
||||
const { mobile, code } = this.data; |
||||
const { registrationSource, registChannel, regBusinessId } = app.globalData; |
||||
wx.ajax({ |
||||
method: "POST", |
||||
url: "?r=zd/account/update-telephone", |
||||
data: { |
||||
mobile, |
||||
code, |
||||
registrationSource, |
||||
registChannel, |
||||
regBusinessId, |
||||
}, |
||||
}).then((_res) => { |
||||
wx.navigateBack(); |
||||
}); |
||||
}, |
||||
handleBack() { |
||||
wx.navigateBack(); |
||||
}, |
||||
}); |
||||
const app = getApp<IAppOption>(); |
||||
let timer = null as null | number; |
||||
|
||||
Page({ |
||||
data: { |
||||
mobile: "", |
||||
code: "", |
||||
|
||||
codeText: "发送验证码", |
||||
}, |
||||
onLoad() {}, |
||||
getCode() { |
||||
if (timer) return; |
||||
const mobile = this.data.mobile; |
||||
if (!mobile) { |
||||
wx.showToast({ |
||||
title: "手机号不能为空", |
||||
icon: "none", |
||||
}); |
||||
return; |
||||
} |
||||
// 验证手机号
|
||||
if (!/^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\d{8}$/.test(mobile)) { |
||||
wx.showToast({ |
||||
title: "手机号格式不正确", |
||||
icon: "none", |
||||
}); |
||||
return; |
||||
} |
||||
wx.ajax({ |
||||
method: "POST", |
||||
url: "?r=zd/login/send-verify-code", |
||||
data: { |
||||
mobile, |
||||
}, |
||||
}).then((res) => { |
||||
console.log(res); |
||||
wx.showToast({ |
||||
icon: "none", |
||||
title: "验证码已发送~", |
||||
}); |
||||
let time = 60; |
||||
timer = setInterval(() => { |
||||
time--; |
||||
this.setData({ |
||||
codeText: time + "s后重新发送", |
||||
}); |
||||
if (time <= 0) { |
||||
clearInterval(timer as number); |
||||
timer = null; |
||||
this.setData({ |
||||
codeText: "发送验证码", |
||||
}); |
||||
} |
||||
}, 1000); |
||||
}); |
||||
}, |
||||
handleSubmit() { |
||||
const { mobile, code } = this.data; |
||||
const { registrationSource, registChannel, regBusinessId } = app.globalData; |
||||
wx.ajax({ |
||||
method: "POST", |
||||
url: "?r=zd/account/update-telephone", |
||||
data: { |
||||
mobile, |
||||
code, |
||||
registrationSource, |
||||
registChannel, |
||||
regBusinessId, |
||||
}, |
||||
}).then((_res) => { |
||||
wx.navigateBack(); |
||||
}); |
||||
}, |
||||
handleBack() { |
||||
wx.navigateBack(); |
||||
}, |
||||
}); |
||||
|
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
{ |
||||
"usingComponents": { |
||||
"navbar": "/components/navbar/index", |
||||
"van-icon": "@vant/weapp/icon/index" |
||||
}, |
||||
"navigationBarTitleText": "突眼日记" |
||||
} |
||||
@ -0,0 +1,269 @@
@@ -0,0 +1,269 @@
|
||||
page { |
||||
background-color: #f6f8f9; |
||||
} |
||||
.container { |
||||
padding: 20rpx 30rpx; |
||||
min-height: 100vh; |
||||
} |
||||
|
||||
// 基准照片设置卡片 |
||||
.setting-card-empty { |
||||
background: #fff; |
||||
border-radius: 32rpx; |
||||
padding: 32rpx; |
||||
margin-bottom: 32rpx; |
||||
box-shadow: 0rpx 4rpx 32rpx 0rpx rgba(0, 0, 0, 0.04); |
||||
.setting-header { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
margin-bottom: 20rpx; |
||||
} |
||||
|
||||
.setting-title { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 12rpx; |
||||
.icon { |
||||
width: 36rpx; |
||||
height: 36rpx; |
||||
} |
||||
|
||||
text { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
} |
||||
} |
||||
|
||||
.setting-status { |
||||
background: linear-gradient(90deg, #ffd650 0%, #f8a61a 100%); |
||||
color: #fff; |
||||
font-size: 24rpx; |
||||
padding: 6rpx 16rpx; |
||||
border-radius: 6rpx; |
||||
} |
||||
|
||||
.setting-desc { |
||||
font-size: 32rpx; |
||||
color: #69686e; |
||||
line-height: 48rpx; |
||||
background: #f6f8f9; |
||||
padding: 32rpx; |
||||
border-radius: 24rpx; |
||||
} |
||||
} |
||||
.setting-card { |
||||
padding: 32rpx; |
||||
background-color: #fff; |
||||
border-radius: 32rpx; |
||||
padding: 32rpx; |
||||
margin-bottom: 32rpx; |
||||
box-shadow: 0rpx 4rpx 32rpx 0rpx rgba(0, 0, 0, 0.04); |
||||
.setting-header { |
||||
.setting-title { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 12rpx; |
||||
.icon { |
||||
width: 36rpx; |
||||
height: 36rpx; |
||||
} |
||||
|
||||
text { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
} |
||||
} |
||||
} |
||||
.setting-body { |
||||
margin-top: 32rpx; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
gap: 24rpx; |
||||
.photo { |
||||
width: 120rpx; |
||||
height: 120rpx; |
||||
border-radius: 16rpx; |
||||
} |
||||
.wrap { |
||||
flex: 1; |
||||
.name { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
} |
||||
.date { |
||||
margin-top: 24rpx; |
||||
font-size: 28rpx; |
||||
color: #69686e; |
||||
} |
||||
} |
||||
.more { |
||||
font-size: 32rpx; |
||||
color: #b073ff; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 功能按钮区 |
||||
.action-buttons { |
||||
display: flex; |
||||
gap: 30rpx; |
||||
margin-bottom: 56rpx; |
||||
} |
||||
|
||||
.action-btn { |
||||
flex: 1; |
||||
height: 320rpx; |
||||
border-radius: 20rpx; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
gap: 20rpx; |
||||
position: relative; |
||||
overflow: hidden; |
||||
|
||||
&.primary { |
||||
background: linear-gradient(180deg, #e98ff8 0%, #b073ff 100%); |
||||
|
||||
.btn-text { |
||||
color: #fff; |
||||
} |
||||
|
||||
.corner-fold { |
||||
position: absolute; |
||||
top: 0; |
||||
right: 0; |
||||
width: 60rpx; |
||||
height: 60rpx; |
||||
background: linear-gradient(45deg, #e5d2ff 0%, #f6f8f9 50%, #f6f8f9 100%); |
||||
border-radius: 0 0 0 18rpx; |
||||
} |
||||
} |
||||
|
||||
&.secondary { |
||||
background: #fff; |
||||
box-shadow: 0 2rpx 12rpx rgba(14, 0, 32, 0.19); |
||||
|
||||
.btn-text { |
||||
color: #a855f7; |
||||
} |
||||
} |
||||
} |
||||
|
||||
.btn-icon { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
width: 108rpx; |
||||
height: 108rpx; |
||||
} |
||||
|
||||
.btn-text { |
||||
font-size: 32rpx; |
||||
font-weight: 500; |
||||
} |
||||
|
||||
.history-section { |
||||
.section-title { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 16rpx; |
||||
margin-bottom: 30rpx; |
||||
|
||||
.title-bar { |
||||
width: 8rpx; |
||||
height: 32rpx; |
||||
background: #a855f7; |
||||
border-radius: 4rpx; |
||||
} |
||||
|
||||
text { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
} |
||||
} |
||||
|
||||
.history-empty { |
||||
background: #fff; |
||||
border-radius: 32rpx; |
||||
padding: 30rpx; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
padding: 80rpx 0; |
||||
gap: 24rpx; |
||||
.icon { |
||||
width: 64rpx; |
||||
height: 64rpx; |
||||
} |
||||
|
||||
.empty-text { |
||||
font-size: 32rpx; |
||||
color: #adacb2; |
||||
} |
||||
} |
||||
|
||||
.history-list { |
||||
.list-item { |
||||
position: relative; |
||||
margin-top: 24rpx; |
||||
border-radius: 32rpx; |
||||
background-color: #fff; |
||||
padding: 32rpx; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
gap: 24rpx; |
||||
.benchmark { |
||||
position: absolute; |
||||
top: 0; |
||||
right: 0; |
||||
padding-top: 8rpx; |
||||
text-align: center; |
||||
width: 124rpx; |
||||
height: 64rpx; |
||||
font-size: 28rpx; |
||||
color: #ffa300; |
||||
line-height: 32rpx; |
||||
} |
||||
.photo { |
||||
width: 140rpx; |
||||
height: 140rpx; |
||||
border-radius: 16rpx; |
||||
} |
||||
.wrap { |
||||
flex: 1; |
||||
.date { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
} |
||||
.tag { |
||||
margin-top: 16rpx; |
||||
padding: 4rpx 12rpx; |
||||
display: inline-block; |
||||
font-size: 24rpx; |
||||
color: #b073ff; |
||||
background: rgba(176, 115, 255, 0.16); |
||||
border-radius: 6rpx 6rpx 6rpx 6rpx; |
||||
} |
||||
.rotate { |
||||
margin-top: 28rpx; |
||||
font-size: 28rpx; |
||||
color: #adacb2; |
||||
line-height: 1; |
||||
} |
||||
} |
||||
.more { |
||||
align-self: center; |
||||
width: 44rpx; |
||||
height: 44rpx; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
const _app = getApp<IAppOption>() |
||||
|
||||
Page({ |
||||
data: { |
||||
background: '#fff', |
||||
}, |
||||
|
||||
onLoad() { |
||||
// 页面加载时的初始化
|
||||
}, |
||||
|
||||
// 返回上一页
|
||||
handleBack() { |
||||
wx.navigateBack() |
||||
}, |
||||
|
||||
// 新增记录
|
||||
addRecord() { |
||||
wx.navigateTo({ |
||||
url: '/patient/pages/noteAdd/index', |
||||
}) |
||||
}, |
||||
handleHistory() { |
||||
wx.navigateTo({ |
||||
url: '/patient/pages/noteHistory/index', |
||||
}) |
||||
}, |
||||
comparePhotos() { |
||||
wx.navigateTo({ |
||||
url: '/patient/pages/noteDiff/index', |
||||
}) |
||||
}, |
||||
}) |
||||
|
||||
export {} |
||||
@ -0,0 +1,70 @@
@@ -0,0 +1,70 @@
|
||||
<navbar fixed title="突眼日记" custom-style="background:{{background}}"> |
||||
<van-icon name="arrow-left" slot="left" size="18px" color="#000" bind:tap="handleBack" /> |
||||
</navbar> |
||||
|
||||
<view class="container" style="padding-top:{{pageTop+20}}px"> |
||||
<!-- 基准照片设置卡片 --> |
||||
<view class="setting-card-empty" bindtap="addRecord"> |
||||
<view class="setting-header"> |
||||
<view class="setting-title"> |
||||
<image class="icon" src="{{imageUrl}}icon144.png?t={{Timestamp}}"></image> |
||||
<text>基准照片设置</text> |
||||
</view> |
||||
<view class="setting-status">待设置</view> |
||||
</view> |
||||
<view class="setting-desc">请先上传一组完整的照片作为基准,后续记录将以此为参照进行对比。</view> |
||||
</view> |
||||
<view class="setting-card"> |
||||
<view class="setting-header"> |
||||
<view class="setting-title"> |
||||
<image class="icon" src="{{imageUrl}}icon143.png?t={{Timestamp}}"></image> |
||||
<text>基准照片设置</text> |
||||
</view> |
||||
</view> |
||||
<view class="setting-body"> |
||||
<image class="photo" src="{{imageUrl}}icon143.png?t={{Timestamp}}"></image> |
||||
<view class="wrap"> |
||||
<view class="name">已设置基准照</view> |
||||
<view class="date">记录日期:2026-04-01</view> |
||||
</view> |
||||
<view class="more">查看</view> |
||||
</view> |
||||
</view> |
||||
|
||||
<!-- 功能按钮区 --> |
||||
<view class="action-buttons"> |
||||
<view class="action-btn primary" bindtap="addRecord"> |
||||
<view class="corner-fold"></view> |
||||
<image class="btn-icon" src="{{imageUrl}}icon147.png?t={{Timestamp}}"></image> |
||||
<text class="btn-text">新增记录</text> |
||||
</view> |
||||
<view class="action-btn secondary" bindtap="comparePhotos"> |
||||
<image class="btn-icon" src="{{imageUrl}}icon145.png?t={{Timestamp}}"></image> |
||||
<text class="btn-text">照片对比</text> |
||||
</view> |
||||
</view> |
||||
|
||||
<!-- 历史记录 --> |
||||
<view class="history-section"> |
||||
<view class="section-title"> |
||||
<view class="title-bar"></view> |
||||
<text>历史记录</text> |
||||
</view> |
||||
<view class="history-empty"> |
||||
<image class="icon" src="{{imageUrl}}icon146.png?t={{Timestamp}}"></image> |
||||
<text class="empty-text">暂无记录,点击上方按钮开始</text> |
||||
</view> |
||||
<view class="history-list"> |
||||
<view class="list-item" bind:tap="handleHistory"> |
||||
<view class="benchmark" style="background: url('{{imageUrl}}bg50.png?t={{Timestamp}}') no-repeat top center/100%">基准照</view> |
||||
<image class="photo" src="{{imageUrl}}icon143.png?t={{Timestamp}}"></image> |
||||
<view class="wrap"> |
||||
<view class="date">2026-04-01</view> |
||||
<view class="tag">替妥尤单抗:2</view> |
||||
<view class="rotate">已上传1个角度</view> |
||||
</view> |
||||
<image class="more" src="{{imageUrl}}icon148.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
{ |
||||
"usingComponents": { |
||||
"navbar": "/components/navbar/index", |
||||
"van-icon": "@vant/weapp/icon/index", |
||||
"popup": "/components/popup/index", |
||||
"noteImagePreview": "/components/noteImagePreview/index", |
||||
"camera": "/patient/components/camera/index" |
||||
}, |
||||
"navigationBarTitleText": "记录新照片" |
||||
} |
||||
@ -0,0 +1,309 @@
@@ -0,0 +1,309 @@
|
||||
page { |
||||
background-color: #f6f8f9; |
||||
} |
||||
|
||||
.page { |
||||
.benchmark { |
||||
margin-top: 32rpx; |
||||
padding: 0 40rpx 28rpx; |
||||
.checkbox { |
||||
font-size: 28rpx; |
||||
color: #211d2e; |
||||
.wx-checkbox-input { |
||||
background: rgba(173, 172, 178, 0.36); |
||||
border-color: transparent; |
||||
width: 32rpx; |
||||
height: 32rpx; |
||||
} |
||||
} |
||||
} |
||||
.form { |
||||
margin: 0 40rpx 24rpx; |
||||
padding: 32rpx; |
||||
background: #ffffff; |
||||
border-radius: 32rpx 32rpx 32rpx 32rpx; |
||||
.form-title { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 16rpx; |
||||
&::before { |
||||
content: ''; |
||||
width: 8rpx; |
||||
height: 32rpx; |
||||
background: #b982ff; |
||||
border-radius: 44rpx 44rpx 44rpx 44rpx; |
||||
} |
||||
} |
||||
.form-title-gap { |
||||
margin-top: 48rpx; |
||||
} |
||||
.select { |
||||
margin-top: 24rpx; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
padding: 26rpx 32rpx; |
||||
background: #f6f8f9; |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
.content { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
&:empty::after { |
||||
content: attr(data-place); |
||||
color: rgba(173, 172, 178, 0.6); |
||||
} |
||||
} |
||||
} |
||||
.dobule { |
||||
margin-top: 44rpx; |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
display: flex; |
||||
gap: 26rpx; |
||||
.item { |
||||
.name { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
} |
||||
.i-content { |
||||
margin-top: 24rpx; |
||||
padding: 26rpx 32rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
background: #f6f8f9; |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
.num { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.container { |
||||
margin-top: 72rpx; |
||||
padding: 32rpx 40rpx 0; |
||||
background-color: #fff; |
||||
border-radius: 32rpx 32rpx 0 0; |
||||
.c-title { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 16rpx; |
||||
&::before { |
||||
content: ''; |
||||
width: 8rpx; |
||||
height: 32rpx; |
||||
background: #b982ff; |
||||
border-radius: 44rpx 44rpx 44rpx 44rpx; |
||||
} |
||||
} |
||||
.options { |
||||
margin-top: 30rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 22rpx; |
||||
.btn { |
||||
flex: 1; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 16rpx; |
||||
padding: 26rpx; |
||||
border-radius: 18rpx; |
||||
.icon { |
||||
width: 36rpx; |
||||
height: 36rpx; |
||||
} |
||||
font-size: 32rpx; |
||||
&.btn1 { |
||||
color: #b982ff; |
||||
background: rgba(185, 130, 255, 0.12); |
||||
} |
||||
&.btn2 { |
||||
color: #ffffff; |
||||
background: linear-gradient(180deg, #e98ff8 0%, #b073ff 100%); |
||||
} |
||||
} |
||||
} |
||||
.card { |
||||
margin-top: 32rpx; |
||||
padding: 32rpx; |
||||
background: #f6f8f9; |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
.card-title { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 16rpx; |
||||
.order { |
||||
width: 40rpx; |
||||
height: 40rpx; |
||||
font-size: 28rpx; |
||||
color: #b982ff; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
background: rgba(185, 130, 255, 0.1); |
||||
border-radius: 8rpx 8rpx 8rpx 8rpx; |
||||
} |
||||
} |
||||
.upload-container { |
||||
margin-top: 32rpx; |
||||
display: grid; |
||||
grid-template-columns: repeat(3, 1fr); |
||||
justify-content: space-between; |
||||
gap: 24rpx; |
||||
.upload-item { |
||||
$degs: ( |
||||
1: -45deg, |
||||
2: 0deg, |
||||
3: 45deg, |
||||
4: -90deg, |
||||
5: 90deg, |
||||
6: -135deg, |
||||
7: -180deg, |
||||
8: 135deg, |
||||
); |
||||
@each $index, $deg in $degs { |
||||
&:nth-of-type(#{$index}) { |
||||
.arrow { |
||||
transform: rotate(#{$deg}); |
||||
} |
||||
} |
||||
} |
||||
&:nth-of-type(3), |
||||
&:nth-of-type(5), |
||||
&:nth-of-type(8) { |
||||
.name { |
||||
flex-direction: row-reverse; |
||||
} |
||||
} |
||||
.upload-place { |
||||
border: 1px dashed #b982ff; |
||||
border-radius: 16rpx; |
||||
width: 186rpx; |
||||
height: 186rpx; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: center; |
||||
gap: 24rpx; |
||||
box-sizing: border-box; |
||||
.icon { |
||||
width: 52rpx; |
||||
height: 52rpx; |
||||
} |
||||
.name { |
||||
font-size: 24rpx; |
||||
display: flex; |
||||
align-items: flex-end; |
||||
gap: 8rpx; |
||||
color: #211d2e; |
||||
line-height: 1; |
||||
.arrow { |
||||
width: 24rpx; |
||||
height: 24rpx; |
||||
} |
||||
} |
||||
} |
||||
.upload-preview { |
||||
position: relative; |
||||
width: 186rpx; |
||||
height: 186rpx; |
||||
.photo { |
||||
width: 100%; |
||||
height: 100%; |
||||
border-radius: 16rpx; |
||||
} |
||||
.status { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
height: 100%; |
||||
border-radius: 16rpx; |
||||
background: rgba(9, 9, 9, 0.45); |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
.icon { |
||||
margin-top: 32rpx; |
||||
width: 40rpx; |
||||
height: 40rpx; |
||||
} |
||||
.content { |
||||
margin-top: 8rpx; |
||||
font-size: 24rpx; |
||||
color: #ffffff; |
||||
} |
||||
.guide { |
||||
margin-top: 26rpx; |
||||
width: 100%; |
||||
height: 40rpx; |
||||
text-align: center; |
||||
line-height: 40rpx; |
||||
font-size: 28rpx; |
||||
color: #ffffff; |
||||
border-radius: 0 0 16rpx 16rpx; |
||||
background: linear-gradient(0deg, #e98ff8 0%, #b073ff 100%); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
&.card3 .upload-container { |
||||
.upload-item:nth-child(1) { |
||||
grid-area: 1 / 1; |
||||
} /* 左上 */ |
||||
.upload-item:nth-child(2) { |
||||
grid-area: 1 / 2; |
||||
} /* 上 */ |
||||
.upload-item:nth-child(3) { |
||||
grid-area: 1 / 3; |
||||
} /* 右上 */ |
||||
.upload-item:nth-child(4) { |
||||
grid-area: 2 / 1; |
||||
} /* 左 */ |
||||
.upload-item:nth-child(5) { |
||||
grid-area: 2 / 3; |
||||
} /* 右 */ |
||||
.upload-item:nth-child(6) { |
||||
grid-area: 3 / 1; |
||||
} /* 左下 */ |
||||
.upload-item:nth-child(7) { |
||||
grid-area: 3 / 2; |
||||
} /* 下 */ |
||||
.upload-item:nth-child(8) { |
||||
grid-area: 3 / 3; |
||||
} /* 右下 */ |
||||
} |
||||
} |
||||
.c-footer { |
||||
position: sticky; |
||||
bottom: 0; |
||||
left: 0; |
||||
background-color: #fff; |
||||
padding: 32rpx 0 60rpx; |
||||
.btn { |
||||
height: 88rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 32rpx; |
||||
color: #ffffff; |
||||
background: linear-gradient(0deg, #e98ff8 0%, #b073ff 100%); |
||||
box-shadow: 0rpx 16rpx 32rpx 0rpx rgba(185, 130, 255, 0.25); |
||||
border-radius: 100rpx 100rpx 100rpx 100rpx; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.place { |
||||
color: rgba(173, 172, 178, 0.6); |
||||
} |
||||
@ -0,0 +1,132 @@
@@ -0,0 +1,132 @@
|
||||
const _app = getApp<IAppOption>() |
||||
|
||||
Page({ |
||||
data: { |
||||
popupShow: false, |
||||
popupType: 'popup16', // 提示保存弹窗
|
||||
popupParams: { |
||||
close: false, |
||||
position: 'bottom', |
||||
} as any, |
||||
|
||||
imagePreview: false, |
||||
|
||||
imageSrc: '', |
||||
|
||||
cameraList: { |
||||
frontend: [ |
||||
{ |
||||
name: '睁眼', |
||||
type: 1, |
||||
}, |
||||
{ |
||||
name: '闭眼', |
||||
type: 2, |
||||
}, |
||||
{ |
||||
name: '仰头', |
||||
type: 3, |
||||
}, |
||||
], |
||||
backend: [ |
||||
{ |
||||
name: '左侧-90°', |
||||
type: 4, |
||||
}, |
||||
{ |
||||
name: '右侧-90°', |
||||
type: 5, |
||||
}, |
||||
{ |
||||
name: '左侧-45°', |
||||
type: 6, |
||||
}, |
||||
{ |
||||
name: '右侧-45°', |
||||
type: 7, |
||||
}, |
||||
], |
||||
other: [ |
||||
{ |
||||
name: '左上', |
||||
type: 8, |
||||
}, |
||||
{ |
||||
name: '向上', |
||||
type: 9, |
||||
}, |
||||
{ |
||||
name: '左下', |
||||
type: 10, |
||||
}, |
||||
{ |
||||
name: '向左', |
||||
type: 11, |
||||
}, |
||||
{ |
||||
name: '向右', |
||||
type: 12, |
||||
}, |
||||
{ |
||||
name: '右上', |
||||
type: 13, |
||||
}, |
||||
{ |
||||
name: '向下', |
||||
type: 14, |
||||
}, |
||||
{ |
||||
name: '右下', |
||||
type: 15, |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
onLoad() {}, |
||||
handleDemo() { |
||||
wx.navigateTo({ |
||||
url: '/patient/pages/noteDemo/index', |
||||
}) |
||||
}, |
||||
handleImageRetake() { |
||||
this.setData({ |
||||
imagePreview: false, |
||||
}) |
||||
}, |
||||
handleImageDel() { |
||||
this.setData({ |
||||
imagePreview: false, |
||||
}) |
||||
}, |
||||
handleCamera(e) { |
||||
const { type } = e.currentTarget.dataset |
||||
const cameraComponent = this.selectComponent('#camera-component') |
||||
cameraComponent.handleSelect(type) |
||||
}, |
||||
onUploadSuccess(e) { |
||||
this.setData({ |
||||
imageSrc: e.detail.url, |
||||
}) |
||||
}, |
||||
onUploadError(e) { |
||||
console.log('DEBUGPRINT[221]: index.ts:34: e=', e) |
||||
}, |
||||
handlePreview() { |
||||
this.selectComponent('#note-image-preview').handlePreview(this.data.imageSrc) |
||||
}, |
||||
handlePopupOk() { |
||||
this.setData({ |
||||
popupShow: false, |
||||
}) |
||||
}, |
||||
handlePopupCancel() { |
||||
this.setData({ |
||||
popupShow: false, |
||||
}) |
||||
}, |
||||
handleBack() { |
||||
wx.navigateBack() |
||||
}, |
||||
}) |
||||
|
||||
export {} |
||||
@ -0,0 +1,146 @@
@@ -0,0 +1,146 @@
|
||||
<page-meta page-style="{{ popupShow || visible ? 'overflow: hidden;' : '' }}" /> |
||||
|
||||
<navbar fixed title="记录新照片" custom-style="background:{{background}}"> |
||||
<van-icon name="arrow-left" slot="left" size="18px" color="#000" bind:tap="handleBack" /> |
||||
</navbar> |
||||
|
||||
<view class="page" style="padding-top: {{pageTop+20}}px;"> |
||||
<view class="benchmark"> |
||||
<checkbox class="checkbox" color="#fff">设置为基准记录,用于对比</checkbox> |
||||
</view> |
||||
<view class="form"> |
||||
<view class="form-title">记录日期</view> |
||||
<picker mode="date"> |
||||
<view class="select"> |
||||
<view class="content" data-place="请选择记录日期"></view> |
||||
<van-icon class="more" name="arrow-down" /> |
||||
</view> |
||||
</picker> |
||||
<view class="form-title form-title-gap">当前记录对应的替妥尤单抗使用次数</view> |
||||
<picker mode="selector"> |
||||
<view class="select"> |
||||
<view class="content" data-place="请选择使用次数"></view> |
||||
<van-icon class="more" name="arrow-down" /> |
||||
</view> |
||||
</picker> |
||||
</view> |
||||
<view class="form"> |
||||
<view class="form-title">记录本次突眼度</view> |
||||
<view class="dobule"> |
||||
<view class="item"> |
||||
<view class="name">右眼</view> |
||||
<view class="i-content"> |
||||
<input type="digit" class="num" placeholder-class="place" placeholder="填写" /> |
||||
MM |
||||
</view> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="name">眶间距</view> |
||||
<view class="i-content"> |
||||
<input type="digit" class="num" placeholder-class="place" placeholder="填写" /> |
||||
MM |
||||
</view> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="name">左眼</view> |
||||
<view class="i-content"> |
||||
<input type="digit" class="num" placeholder-class="place" placeholder="填写" /> |
||||
MM |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="c-title">持续追踪、固定位置拍摄,以便对比评估变化</view> |
||||
<view class="options"> |
||||
<view class="btn btn1" bind:tap="handleDemo"> |
||||
<image class="icon" src="{{imageUrl}}icon149.png?t={{Timestamp}}"></image> |
||||
标准拍摄示范 |
||||
</view> |
||||
<view class="btn btn2"> |
||||
<image class="icon" src="{{imageUrl}}icon150.png?t={{Timestamp}}"></image> |
||||
一键顺序拍摄 |
||||
</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="card-title"> |
||||
<view class="order">1</view> |
||||
正面 |
||||
</view> |
||||
<view class="upload-container"> |
||||
<view class="upload-item" wx:for="{{cameraList.frontend}}" wx:key="index"> |
||||
<view class="upload-preview" wx:if="{{imageSrc}}" bind:tap="handlePreview"> |
||||
<image class="photo" src="{{imageSrc}}"></image> |
||||
<view class="status"> |
||||
<image class="icon" src="/images/icon164.png"></image> |
||||
<view class="content">不符合规范</view> |
||||
<view class="guide">重新上传</view> |
||||
</view> |
||||
</view> |
||||
<view class="upload-place" wx:else bind:tap="handleCamera" data-type="{{item.type}}"> |
||||
<image class="icon" src="{{imageUrl}}icon151.png?t={{Timestamp}}"></image> |
||||
<view class="name">{{item.name}}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="card-title"> |
||||
<view class="order">2</view> |
||||
侧面 |
||||
</view> |
||||
<view class="upload-container"> |
||||
<view class="upload-item" wx:for="{{cameraList.backend}}" wx:key="index"> |
||||
<view class="upload-preview" wx:if="{{imageSrc}}" bind:tap="handlePreview"> |
||||
<image class="photo" src="{{imageSrc}}"></image> |
||||
</view> |
||||
<view class="upload-place" wx:else bind:tap="handleCamera" data-type="{{item.type}}"> |
||||
<image class="icon" src="{{imageUrl}}icon151.png?t={{Timestamp}}"></image> |
||||
<view class="name">{{item.name}}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="card card3"> |
||||
<view class="card-title"> |
||||
<view class="order">3</view> |
||||
眼球运动八个方向 |
||||
</view> |
||||
<view class="upload-container"> |
||||
<view class="upload-item" wx:for="{{cameraList.other}}" wx:key="index"> |
||||
<view class="upload-preview" wx:if="{{imageSrc}}" bind:tap="handlePreview"> |
||||
<image class="photo" src="{{imageSrc}}"></image> |
||||
</view> |
||||
<view class="upload-place" wx:else bind:tap="handleCamera" data-type="{{item.type}}"> |
||||
<image class="icon" src="{{imageUrl}}icon151.png?t={{Timestamp}}"></image> |
||||
<view class="name"> |
||||
<image class="arrow" src="/images/icon167.png"></image> |
||||
{{item.name}} |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="c-footer"> |
||||
<view class="btn">诺和益托管视频</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
|
||||
<camera id="camera-component" bind:uploadsuccess="onUploadSuccess" bind:uploaderror="onUploadError" /> |
||||
|
||||
<noteImagePreview |
||||
id="note-image-preview" |
||||
visible="{{imagePreview}}" |
||||
src="{{imageUrl}}note-demo10.png?t={{Timestamp}}" |
||||
bind:delete="handleImageDel" |
||||
bind:retake="handleImageRetake" |
||||
></noteImagePreview> |
||||
|
||||
<popup |
||||
show="{{popupShow}}" |
||||
type="{{popupType}}" |
||||
params="{{popupParams}}" |
||||
bind:ok="handlePopupOk" |
||||
bind:cancel="handlePopupCancel" |
||||
></popup> |
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
{ |
||||
"usingComponents": { |
||||
"navbar": "/components/navbar/index", |
||||
"van-icon": "@vant/weapp/icon/index" |
||||
}, |
||||
"navigationBarTitleText": "标准拍照示范" |
||||
} |
||||
@ -0,0 +1,55 @@
@@ -0,0 +1,55 @@
|
||||
page { |
||||
background-color: #f6f8f9; |
||||
} |
||||
.page { |
||||
padding: 0 40rpx 40rpx; |
||||
.card { |
||||
margin-bottom: 32rpx; |
||||
padding: 116rpx 32rpx 32rpx; |
||||
border-radius: 32rpx; |
||||
background-color: #fff; |
||||
.tip { |
||||
background: #f7f1ff; |
||||
padding: 32rpx; |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
border: 2rpx solid #b982ff; |
||||
} |
||||
.item { |
||||
margin-top: 36rpx; |
||||
.title { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 12rpx; |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
&::before { |
||||
content: ''; |
||||
width: 6rpx; |
||||
height: 32rpx; |
||||
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%); |
||||
border-radius: 6rpx 6rpx 6rpx 6rpx; |
||||
} |
||||
} |
||||
.content { |
||||
margin-top: 22rpx; |
||||
font-size: 32rpx; |
||||
color: #69686e; |
||||
line-height: 48rpx; |
||||
} |
||||
.photo { |
||||
margin-top: 32rpx; |
||||
width: 100%; |
||||
display: block; |
||||
} |
||||
} |
||||
&.card-dobule { |
||||
display: grid; |
||||
grid-template-columns: repeat(2, 1fr); |
||||
gap: 48rpx 30rpx; |
||||
.item { |
||||
margin: 0; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
const _app = getApp<IAppOption>() |
||||
|
||||
Page({ |
||||
data: {}, |
||||
onLoad() {}, |
||||
handleBack() { |
||||
wx.navigateBack() |
||||
}, |
||||
}) |
||||
|
||||
export {} |
||||
@ -0,0 +1,86 @@
@@ -0,0 +1,86 @@
|
||||
<navbar fixed title="记录新照片" custom-style="background:{{background}}"> |
||||
<van-icon name="arrow-left" slot="left" size="18px" color="#000" bind:tap="handleBack" /> |
||||
</navbar> |
||||
|
||||
<view |
||||
class="page" |
||||
style="background: url('{{imageUrl}}bg51.png?t={{Timestamp}}') no-repeat top center/100% 716rpx;padding-top: {{pageTop+120}}px;" |
||||
> |
||||
<view class="card" style="background: #fff url('{{imageUrl}}bg52.png?t={{Timestamp}}') no-repeat top center/100% 210rpx"> |
||||
<view class="tip">拍摄时,正对镜头,面部居中,露出完整双眼及眼眶;光线均匀无阴影。</view> |
||||
<view class="item"> |
||||
<view class="title">正面睁眼照</view> |
||||
<view class="content">平视,目光看向镜头方向,自然睁眼,不眯眼、不瞪眼。</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo1.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">正面闭眼照</view> |
||||
<view class="content">正对镜头,面部居中,自然放松,双眼轻轻闭合,不皱眉、不挤眼。</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo2.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">正面仰头照</view> |
||||
<view class="content"> |
||||
拍摄时,正对镜头,面部居中,头部自然向上仰至约 45°,双眼同步平视,保持自然睁眼、不眯眼。 |
||||
</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo3.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
</view> |
||||
<view class="card" style="background: #fff url('{{imageUrl}}bg53.png?t={{Timestamp}}') no-repeat top center/100% 210rpx"> |
||||
<view class="tip">拍摄时,头部保持水平,不仰头、不低头,双眼平视前方;光线均匀无阴影。</view> |
||||
<view class="item"> |
||||
<view class="title">左侧-90°</view> |
||||
<view class="content">身体与头部完全转向右侧,呈标准 90° 侧面,仅可见左侧眼睛。</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo4.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">右侧-90°</view> |
||||
<view class="content">身体与头部完全转向左侧,呈标准 90° 侧面,仅可见右侧眼睛。</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo5.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">左侧-45°</view> |
||||
<view class="content">身体与头部转向右前方 45°。</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo6.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">右侧-45°</view> |
||||
<view class="content">身体与头部转向左前方 45°</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo7.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
</view> |
||||
<view class="card card-dobule" style="background: #fff url('{{imageUrl}}bg54.png?t={{Timestamp}}') no-repeat top center/100% 210rpx"> |
||||
<view class="item"> |
||||
<view class="title">正面眼睛上看</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo8.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">正面眼睛下看</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo9.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">正面眼睛左看</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo10.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">正面眼睛右看</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo11.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">正面眼睛左上看</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo12.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">正面眼睛右上看</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo13.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">正面眼睛左下看</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo14.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<view class="title">正面眼睛右下看</view> |
||||
<image class="photo" mode="widthFix" src="{{imageUrl}}note-demo15.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
@ -0,0 +1,7 @@
@@ -0,0 +1,7 @@
|
||||
{ |
||||
"navigationStyle": "default", |
||||
"usingComponents": { |
||||
"van-icon": "@vant/weapp/icon/index" |
||||
}, |
||||
"navigationBarTitleText": "照片对比分析" |
||||
} |
||||
@ -0,0 +1,284 @@
@@ -0,0 +1,284 @@
|
||||
page { |
||||
background-color: #f6f8f9; |
||||
} |
||||
.page-none { |
||||
padding: 290rpx 76rpx 0; |
||||
.icon { |
||||
display: block; |
||||
margin: 0 auto; |
||||
width: 458rpx; |
||||
height: 218rpx; |
||||
} |
||||
.title { |
||||
margin-top: 26rpx; |
||||
font-size: 38rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
text-align: center; |
||||
} |
||||
.content { |
||||
margin-top: 24rpx; |
||||
font-size: 32rpx; |
||||
color: #69686e; |
||||
line-height: 48rpx; |
||||
text-align: center; |
||||
} |
||||
.btn { |
||||
margin: 88rpx 0 0; |
||||
font-size: 32rpx; |
||||
color: #ffffff; |
||||
height: 88rpx; |
||||
text-align: center; |
||||
line-height: 88rpx; |
||||
background: linear-gradient(0deg, #e98ff8 0%, #b073ff 100%); |
||||
box-shadow: 0rpx 16rpx 32rpx 0rpx rgba(185, 130, 255, 0.25); |
||||
border-radius: 100rpx 100rpx 100rpx 100rpx; |
||||
} |
||||
} |
||||
.page { |
||||
padding-bottom: 80rpx; |
||||
.page-tip { |
||||
padding: 24rpx 28rpx; |
||||
background-color: #fff7e9; |
||||
display: flex; |
||||
.icon { |
||||
margin-top: 6rpx; |
||||
flex-shrink: 0; |
||||
width: 32rpx; |
||||
height: 32rpx; |
||||
} |
||||
.content { |
||||
margin-left: 16rpx; |
||||
font-size: 28rpx; |
||||
color: #ffa300; |
||||
line-height: 44rpx; |
||||
} |
||||
} |
||||
.form { |
||||
margin: 32rpx 40rpx 0; |
||||
padding: 38rpx 32rpx 32rpx; |
||||
background: #ffffff; |
||||
border-radius: 32rpx 32rpx 32rpx 32rpx; |
||||
.form-item { |
||||
margin-bottom: 48rpx; |
||||
&:last-of-type { |
||||
margin-bottom: 0; |
||||
} |
||||
.title { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 16rpx; |
||||
&::before { |
||||
content: ''; |
||||
width: 8rpx; |
||||
height: 32rpx; |
||||
background: #b982ff; |
||||
border-radius: 44rpx 44rpx 44rpx 44rpx; |
||||
} |
||||
} |
||||
.select { |
||||
margin-top: 24rpx; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
padding: 26rpx 32rpx; |
||||
background: #f6f8f9; |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
.content { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
&:empty::after { |
||||
content: attr(data-place); |
||||
color: rgba(173, 172, 178, 0.6); |
||||
} |
||||
} |
||||
} |
||||
.multiple { |
||||
margin-top: 24rpx; |
||||
display: grid; |
||||
grid-template-columns: repeat(2, 1fr); |
||||
gap: 24rpx 22rpx; |
||||
.item { |
||||
padding: 16rpx; |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
background: #f6f8f9; |
||||
border-radius: 24rpx 24rpx 24rpx 24rpx; |
||||
&.active { |
||||
color: #fff; |
||||
background: linear-gradient(180deg, #e98ff8 0%, #b073ff 100%); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.container { |
||||
margin: 76rpx 40rpx 0; |
||||
.title { |
||||
padding-bottom: 40rpx; |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 16rpx; |
||||
.date { |
||||
font-size: 28rpx; |
||||
color: #adacb2; |
||||
font-weight: normal; |
||||
align-self: flex-end; |
||||
} |
||||
&::before { |
||||
content: ''; |
||||
width: 8rpx; |
||||
height: 32rpx; |
||||
background: #b982ff; |
||||
border-radius: 44rpx 44rpx 44rpx 44rpx; |
||||
} |
||||
} |
||||
.card { |
||||
display: flex; |
||||
.aside { |
||||
flex-shrink: 0; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
.line-bottom { |
||||
border: 1px dashed #b982ff; |
||||
} |
||||
.line-bottom { |
||||
flex: 1; |
||||
} |
||||
.circle { |
||||
position: relative; |
||||
width: 32rpx; |
||||
height: 32rpx; |
||||
border-radius: 50%; |
||||
background: rgba(185, 130, 255, 0.29); |
||||
&::after { |
||||
position: relative; |
||||
top: 50%; |
||||
left: 50%; |
||||
transform: translate(-50%, -50%); |
||||
display: block; |
||||
content: ''; |
||||
width: 18rpx; |
||||
height: 18rpx; |
||||
border-radius: 50%; |
||||
background-color: #b982ff; |
||||
} |
||||
} |
||||
} |
||||
.c-container { |
||||
margin-top: -6rpx; |
||||
margin-left: 14rpx; |
||||
flex: 1; |
||||
padding-bottom: 48rpx; |
||||
.c-header { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
.date { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
} |
||||
.btn { |
||||
width: 164rpx; |
||||
height: 56rpx; |
||||
background: linear-gradient(0deg, #e98ff8 0%, #b073ff 100%); |
||||
border-radius: 124rpx 124rpx 124rpx 124rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
gap: 12rpx; |
||||
font-size: 32rpx; |
||||
color: #ffffff; |
||||
.icon { |
||||
width: 40rpx; |
||||
height: 40rpx; |
||||
} |
||||
} |
||||
} |
||||
.tags { |
||||
margin-top: 12rpx; |
||||
.tag { |
||||
display: inline-block; |
||||
margin-right: 16rpx; |
||||
padding: 2rpx 12rpx; |
||||
font-size: 24rpx; |
||||
color: #ffa300; |
||||
line-height: 32rpx; |
||||
border-radius: 6rpx; |
||||
&.tag1 { |
||||
background: rgba(255, 163, 0, 0.17); |
||||
color: #ffa300; |
||||
} |
||||
&.tag2 { |
||||
background: rgba(176, 115, 255, 0.16); |
||||
color: #b073ff; |
||||
} |
||||
} |
||||
} |
||||
.photo-card { |
||||
margin-top: 24rpx; |
||||
.photo { |
||||
border-radius: 32rpx 32rpx 0 0; |
||||
height: 352rpx; |
||||
display: block; |
||||
} |
||||
.row { |
||||
display: flex; |
||||
gap: 24rpx; |
||||
text-align: center; |
||||
border-radius: 0 0 32rpx 32rpx; |
||||
background-color: #fff; |
||||
.col { |
||||
padding: 24rpx; |
||||
flex: 1; |
||||
.name { |
||||
font-size: 28rpx; |
||||
color: #211d2e; |
||||
line-height: 32rpx; |
||||
} |
||||
.content { |
||||
margin-top: 16rpx; |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: baseline; |
||||
gap: 8rpx; |
||||
.num { |
||||
font-size: 56rpx; |
||||
color: #b073ff; |
||||
font-weight: bold; |
||||
} |
||||
.sub { |
||||
font-size: 28rpx; |
||||
color: #211d2e; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.footer { |
||||
margin-top: 46rpx; |
||||
.btn1 { |
||||
height: 88rpx; |
||||
font-size: 36rpx; |
||||
color: #ffffff; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
background: linear-gradient(0deg, #e98ff8 0%, #b073ff 100%); |
||||
border-radius: 100rpx 100rpx 100rpx 100rpx; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,13 @@
@@ -0,0 +1,13 @@
|
||||
const _app = getApp<IAppOption>() |
||||
|
||||
Page({ |
||||
data: {}, |
||||
onLoad() {}, |
||||
handleEdit() { |
||||
wx.navigateTo({ |
||||
url: '/patient/pages/noteDiffEdit/index', |
||||
}) |
||||
}, |
||||
}) |
||||
|
||||
export {} |
||||
@ -0,0 +1,85 @@
@@ -0,0 +1,85 @@
|
||||
<view class="page-none" wx:if="{{false}}"> |
||||
<image class="icon" src="{{imageUrl}}none3.png?t={{Timestamp}}"></image> |
||||
<view class="title">未设置基准照片</view> |
||||
<view class="content"> |
||||
请先上传一组照片并将其设为基准 |
||||
<view></view> |
||||
以便进行对比分析 |
||||
</view> |
||||
<view class="btn">去设置</view> |
||||
</view> |
||||
<view class="page"> |
||||
<view class="page-tip"> |
||||
<image class="icon" src="{{imageUrl}}icon154.png?t={{Timestamp}}"></image> |
||||
<view class="content"> |
||||
您可以同时选择多个日期,系统将按时间顺序排列照片。点击右上角按钮可预览并保存生成的对比长图。 |
||||
</view> |
||||
</view> |
||||
<view class="form"> |
||||
<view class="form-item"> |
||||
<view class="title">选择对比角度</view> |
||||
<picker mode="selector"> |
||||
<view class="select"> |
||||
<view class="content" data-place="请选择对比角度"></view> |
||||
<van-icon class="more" name="arrow-down" /> |
||||
</view> |
||||
</picker> |
||||
</view> |
||||
<view class="form-item"> |
||||
<view class="title">选择对比日期(可多选)</view> |
||||
<view class="multiple"> |
||||
<view class="item {{index==0&&'active'}}" wx:for="{{8}}" wx:key="index">2026-04-02</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="container"> |
||||
<view class="title"> |
||||
正面睁眼时间线对比 |
||||
<view class="date">生成日期:2026-04-02</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="aside"> |
||||
<view class="circle"></view> |
||||
<view class="line-bottom"></view> |
||||
</view> |
||||
<view class="c-container"> |
||||
<view class="c-header"> |
||||
<view class="date">基准照片 2026-04-02</view> |
||||
</view> |
||||
<view class="tags"> |
||||
<view class="tag tag1">基准照片</view> |
||||
<view class="tag tag2">替妥尤单抗:2</view> |
||||
</view> |
||||
<view class="photo-card"> |
||||
<image class="photo" src="{{imageUrl}}note-demo1.png?t={{Timestamp}}"></image> |
||||
<view class="row"> |
||||
<view class="col"> |
||||
<view class="name">右眼</view> |
||||
<view class="content"> |
||||
<view class="num">12</view> |
||||
<view class="sub">MM</view> |
||||
</view> |
||||
</view> |
||||
<view class="col"> |
||||
<view class="name">眶间距</view> |
||||
<view class="content"> |
||||
<view class="num">12</view> |
||||
<view class="sub">MM</view> |
||||
</view> |
||||
</view> |
||||
<view class="col"> |
||||
<view class="name">左眼</view> |
||||
<view class="content"> |
||||
<view class="num">12</view> |
||||
<view class="sub">MM</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="footer"> |
||||
<view class="btn1" bind:tap="handleEdit">生成对比图</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
{ |
||||
"navigationStyle": "default", |
||||
"usingComponents": { |
||||
"van-icon": "@vant/weapp/icon/index", |
||||
"imageMerge": "/patient/components/image-merge/index" |
||||
}, |
||||
"navigationBarTitleText": "照片对比分析" |
||||
} |
||||
@ -0,0 +1,157 @@
@@ -0,0 +1,157 @@
|
||||
page { |
||||
background-color: #f6f8f9; |
||||
} |
||||
.page { |
||||
padding-bottom: 80rpx; |
||||
.container { |
||||
margin: 40rpx 40rpx 0; |
||||
.title { |
||||
padding-bottom: 40rpx; |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 16rpx; |
||||
.date { |
||||
font-size: 28rpx; |
||||
color: #adacb2; |
||||
font-weight: normal; |
||||
align-self: flex-end; |
||||
} |
||||
&::before { |
||||
content: ''; |
||||
width: 8rpx; |
||||
height: 32rpx; |
||||
background: #b982ff; |
||||
border-radius: 44rpx 44rpx 44rpx 44rpx; |
||||
} |
||||
} |
||||
.card { |
||||
display: flex; |
||||
.aside { |
||||
flex-shrink: 0; |
||||
display: flex; |
||||
flex-direction: column; |
||||
align-items: center; |
||||
.line-bottom { |
||||
border: 1px dashed #b982ff; |
||||
} |
||||
.line-bottom { |
||||
flex: 1; |
||||
} |
||||
.circle { |
||||
position: relative; |
||||
width: 32rpx; |
||||
height: 32rpx; |
||||
border-radius: 50%; |
||||
background: rgba(185, 130, 255, 0.29); |
||||
&::after { |
||||
position: relative; |
||||
top: 50%; |
||||
left: 50%; |
||||
transform: translate(-50%, -50%); |
||||
display: block; |
||||
content: ''; |
||||
width: 18rpx; |
||||
height: 18rpx; |
||||
border-radius: 50%; |
||||
background-color: #b982ff; |
||||
} |
||||
} |
||||
} |
||||
.c-container { |
||||
margin-top: -6rpx; |
||||
margin-left: 14rpx; |
||||
flex: 1; |
||||
padding-bottom: 48rpx; |
||||
.c-header { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
.date { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
} |
||||
} |
||||
.tags { |
||||
margin-top: 12rpx; |
||||
.tag { |
||||
display: inline-block; |
||||
margin-right: 16rpx; |
||||
padding: 2rpx 12rpx; |
||||
font-size: 24rpx; |
||||
color: #ffa300; |
||||
line-height: 32rpx; |
||||
border-radius: 6rpx; |
||||
&.tag1 { |
||||
background: rgba(255, 163, 0, 0.17); |
||||
color: #ffa300; |
||||
} |
||||
&.tag2 { |
||||
background: rgba(176, 115, 255, 0.16); |
||||
color: #b073ff; |
||||
} |
||||
} |
||||
} |
||||
.photo-card { |
||||
margin-top: 24rpx; |
||||
position: relative; |
||||
.photo { |
||||
border-radius: 32rpx 32rpx 0 0; |
||||
height: 352rpx; |
||||
display: block; |
||||
} |
||||
.mask { |
||||
position: absolute; |
||||
bottom: 0; |
||||
left: 0; |
||||
width: 100%; |
||||
height: 85rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
gap: 16rpx; |
||||
background: rgba(0, 0, 0, 0.3); |
||||
font-size: 32rpx; |
||||
color: #ffffff; |
||||
.icon { |
||||
width: 40rpx; |
||||
height: 40rpx; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
.footer { |
||||
margin-top: 46rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 22rpx; |
||||
.btn1 { |
||||
flex: 1; |
||||
height: 88rpx; |
||||
font-size: 36rpx; |
||||
color: #b982ff; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
border: 1px solid #b982ff; |
||||
background-color: #fff; |
||||
border-radius: 100rpx 100rpx 100rpx 100rpx; |
||||
} |
||||
.btn2 { |
||||
flex: 1; |
||||
height: 88rpx; |
||||
font-size: 36rpx; |
||||
color: #ffffff; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
background: linear-gradient(0deg, #e98ff8 0%, #b073ff 100%); |
||||
border-radius: 100rpx 100rpx 100rpx 100rpx; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
const _app = getApp<IAppOption>() |
||||
|
||||
Page({ |
||||
data: {}, |
||||
onLoad() {}, |
||||
handleMergePreview() { |
||||
const mergeComponent = this.selectComponent('#merge') |
||||
console.log("DEBUGPRINT[224]: index.ts:7: mergeComponent=", mergeComponent) |
||||
if (mergeComponent) { |
||||
mergeComponent.mergeImages([ |
||||
{ src: 'https://picsum.photos/400/300', time: '2024-01-01 10:00' }, |
||||
{ src: 'https://picsum.photos/400/301', time: '2024-01-01 12:00' }, |
||||
{ src: 'https://picsum.photos/400/302' }, |
||||
]) |
||||
} |
||||
}, |
||||
}) |
||||
|
||||
export {} |
||||
@ -0,0 +1,40 @@
@@ -0,0 +1,40 @@
|
||||
<view class="page"> |
||||
<view class="container"> |
||||
<view class="title"> |
||||
正面睁眼时间线对比 |
||||
<view class="date">生成日期:2026-04-02</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="aside"> |
||||
<view class="circle"></view> |
||||
<view class="line-bottom"></view> |
||||
</view> |
||||
<view class="c-container"> |
||||
<view class="c-header"> |
||||
<view class="date">基准照片 2026-04-02</view> |
||||
</view> |
||||
<view class="tags"> |
||||
<view class="tag tag1">基准照片</view> |
||||
<view class="tag tag2">替妥尤单抗:2</view> |
||||
</view> |
||||
<view class="photo-card"> |
||||
<image class="photo" src="{{imageUrl}}note-demo1.png?t={{Timestamp}}"></image> |
||||
<view class="mask" wx:if="{{false}}"> |
||||
<image class="icon" src="/images/icon165.png"></image> |
||||
点击裁剪 |
||||
</view> |
||||
<view class="mask" wx:else> |
||||
<image class="icon" src="/images/icon166.png"></image> |
||||
点击还原 |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="footer"> |
||||
<view class="btn1" bind:tap="handleMergePreview">对比图预览</view> |
||||
<view class="btn2">保存到相册</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
|
||||
<imageMerge id="merge" bindsave="onMergeSave" binderror="onMergeError" /> |
||||
@ -0,0 +1,8 @@
@@ -0,0 +1,8 @@
|
||||
{ |
||||
"usingComponents": { |
||||
"navbar": "/components/navbar/index", |
||||
"van-icon": "@vant/weapp/icon/index", |
||||
"popup": "/components/popup/index" |
||||
}, |
||||
"navigationBarTitleText": "记录" |
||||
} |
||||
@ -0,0 +1,183 @@
@@ -0,0 +1,183 @@
|
||||
.page { |
||||
.header { |
||||
padding: 52rpx 32rpx 40rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
.wrap { |
||||
.date { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
} |
||||
.tags { |
||||
margin-top: 16rpx; |
||||
.tag { |
||||
display: inline-block; |
||||
margin-right: 16rpx; |
||||
padding: 2rpx 12rpx; |
||||
font-size: 24rpx; |
||||
color: #ffa300; |
||||
line-height: 32rpx; |
||||
border-radius: 6rpx; |
||||
&.tag1 { |
||||
background: rgba(255, 163, 0, 0.17); |
||||
color: #ffa300; |
||||
} |
||||
&.tag2 { |
||||
background: rgba(176, 115, 255, 0.16); |
||||
color: #b073ff; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.opt { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 24rpx; |
||||
.item { |
||||
width: 64rpx; |
||||
height: 64rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
background: #ffffff; |
||||
border-radius: 50%; |
||||
.icon { |
||||
width: 40rpx; |
||||
height: 40rpx; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.container { |
||||
padding: 40rpx; |
||||
border-radius: 32rpx 32rpx 0 0; |
||||
background-color: #fff; |
||||
.tip-card { |
||||
padding: 24rpx 32rpx; |
||||
border-radius: 32rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
background: #fff7e9; |
||||
gap: 16rpx; |
||||
.tip-icon { |
||||
margin-top: 6rpx; |
||||
align-self: flex-start; |
||||
flex-shrink: 0; |
||||
width: 32rpx; |
||||
height: 32rpx; |
||||
} |
||||
.wrap { |
||||
flex: 1; |
||||
line-height: 44rpx; |
||||
.title { |
||||
font-size: 28rpx; |
||||
color: #ffa300; |
||||
font-weight: bold; |
||||
} |
||||
.content { |
||||
font-size: 24rpx; |
||||
color: #ffa300; |
||||
} |
||||
} |
||||
.btn { |
||||
flex-shrink: 0; |
||||
font-size: 28rpx; |
||||
color: #ffffff; |
||||
width: 148rpx; |
||||
height: 56rpx; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
background: #ffa300; |
||||
border-radius: 92rpx 92rpx 92rpx 92rpx; |
||||
} |
||||
} |
||||
.banner { |
||||
margin-top: 24rpx; |
||||
padding: 32rpx; |
||||
background: #f6f8f9; |
||||
border-radius: 32rpx 32rpx 32rpx 32rpx; |
||||
border: 2rpx solid #ffffff; |
||||
.title { |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
} |
||||
.row { |
||||
margin-top: 24rpx; |
||||
display: flex; |
||||
gap: 24rpx; |
||||
text-align: center; |
||||
.col { |
||||
padding: 24rpx; |
||||
flex: 1; |
||||
background-color: #fff; |
||||
border-radius: 16rpx; |
||||
.name { |
||||
font-size: 28rpx; |
||||
color: #211d2e; |
||||
line-height: 32rpx; |
||||
} |
||||
.content { |
||||
margin-top: 16rpx; |
||||
display: flex; |
||||
justify-content: center; |
||||
align-items: baseline; |
||||
gap: 8rpx; |
||||
.num { |
||||
font-size: 56rpx; |
||||
color: #b073ff; |
||||
font-weight: bold; |
||||
} |
||||
.sub { |
||||
font-size: 28rpx; |
||||
color: #211d2e; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
.card { |
||||
margin-top: 48rpx; |
||||
.card-title { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 16rpx; |
||||
font-size: 32rpx; |
||||
color: #211d2e; |
||||
font-weight: bold; |
||||
&::before { |
||||
content: ''; |
||||
width: 8rpx; |
||||
height: 32rpx; |
||||
background: #b982ff; |
||||
border-radius: 44rpx 44rpx 44rpx 44rpx; |
||||
} |
||||
} |
||||
.card-container { |
||||
margin-top: 24rpx; |
||||
display: grid; |
||||
grid-template-columns: repeat(2, 320rpx); |
||||
justify-content: space-between; |
||||
gap: 30rpx; |
||||
.card-item { |
||||
.photo { |
||||
display: block; |
||||
width: 100%; |
||||
height: 320rpx; |
||||
border-radius: 24rpx; |
||||
} |
||||
.name{ |
||||
margin-top: 16rpx; |
||||
font-size: 28rpx; |
||||
color: #ADACB2; |
||||
text-align: center; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,94 @@
@@ -0,0 +1,94 @@
|
||||
const _app = getApp<IAppOption>() |
||||
|
||||
Page({ |
||||
data: { |
||||
popupShow: true, |
||||
popupType: 'popup15', // 确认删除弹窗
|
||||
popupParams: { |
||||
close: false, |
||||
} as any, |
||||
|
||||
history: { |
||||
frontend: [ |
||||
{ |
||||
title: '正面睁眼照', |
||||
content: '平视,目光看向镜头方向,自然睁眼,不眯眼、不瞪眼。', |
||||
}, |
||||
{ |
||||
title: '正面闭眼照', |
||||
content: '正对镜头,面部居中,自然放松,双眼轻轻闭合,不皱眉、不挤眼。', |
||||
}, |
||||
{ |
||||
title: '正面仰头照', |
||||
content: '拍摄时,正对镜头,面部居中,头部自然向上仰至约 45°,双眼同步平视,保持自然睁眼、不眯眼。', |
||||
}, |
||||
], |
||||
backend: [ |
||||
{ |
||||
title: '左侧-90°', |
||||
content: '身体与头部完全转向右侧,呈标准 90° 侧面,仅可见左侧眼睛。', |
||||
}, |
||||
{ |
||||
title: '右侧-90°', |
||||
content: '身体与头部完全转向左侧,呈标准 90° 侧面,仅可见右侧眼睛。', |
||||
}, |
||||
{ |
||||
title: '左侧-45°', |
||||
content: '身体与头部转向右前方 45°。', |
||||
}, |
||||
{ |
||||
title: '右侧-45°', |
||||
content: '身体与头部转向左前方 45°', |
||||
}, |
||||
], |
||||
other: [ |
||||
{ |
||||
title: '正面眼睛上看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛下看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛左看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛右看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛左上看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛右上看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛左下看', |
||||
content: '', |
||||
}, |
||||
{ |
||||
title: '正面眼睛右下看', |
||||
content: '', |
||||
}, |
||||
], |
||||
}, |
||||
}, |
||||
onLoad() {}, |
||||
|
||||
handlePopupOk() { |
||||
this.setData({ |
||||
popupShow: false, |
||||
}) |
||||
}, |
||||
handlePopupCancel() { |
||||
this.setData({ |
||||
popupShow: false, |
||||
}) |
||||
}, |
||||
}) |
||||
|
||||
export {} |
||||
@ -0,0 +1,98 @@
@@ -0,0 +1,98 @@
|
||||
<navbar fixed title="记录" custom-style="background:{{background}}"> |
||||
<van-icon name="arrow-left" slot="left" size="18px" color="#000" bind:tap="handleBack" /> |
||||
</navbar> |
||||
|
||||
<view |
||||
class="page" |
||||
style="background: url('{{imageUrl}}bg10.png?t={{Timestamp}}') no-repeat top center/100% 610rpx;padding-top:{{pageTop}}px;" |
||||
> |
||||
<view class="header"> |
||||
<view class="wrap"> |
||||
<view class="date">2026-04-02</view> |
||||
<view class="tags"> |
||||
<view class="tag tag1">基准照片</view> |
||||
<view class="tag tag2">替妥尤单抗:2</view> |
||||
</view> |
||||
</view> |
||||
<view class="opt"> |
||||
<view class="item"> |
||||
<image class="icon" src="{{imageUrl}}icon152.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
<view class="item"> |
||||
<image class="icon" src="{{imageUrl}}icon153.png?t={{Timestamp}}"></image> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
|
||||
<view class="container"> |
||||
<view class="tip-card"> |
||||
<image class="tip-icon" src="{{imageUrl}}icon154.png?t={{Timestamp}}"></image> |
||||
<view class="wrap"> |
||||
<view class="title">记录未录入完全</view> |
||||
<view class="content">当前已录入1/15个角度。您可以点击右上角的编辑按钮继续补充照片。</view> |
||||
</view> |
||||
<view class="btn">去补充</view> |
||||
</view> |
||||
<view class="banner"> |
||||
<view class="title">眼球突出度测量记录</view> |
||||
<view class="row"> |
||||
<view class="col"> |
||||
<view class="name">右眼</view> |
||||
<view class="content"> |
||||
<view class="num">12</view> |
||||
<view class="sub">MM</view> |
||||
</view> |
||||
</view> |
||||
<view class="col"> |
||||
<view class="name">眶间距</view> |
||||
<view class="content"> |
||||
<view class="num">12</view> |
||||
<view class="sub">MM</view> |
||||
</view> |
||||
</view> |
||||
<view class="col"> |
||||
<view class="name">左眼</view> |
||||
<view class="content"> |
||||
<view class="num">12</view> |
||||
<view class="sub">MM</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="card-title">正面</view> |
||||
<view class="card-container"> |
||||
<view class="card-item" wx:for="{{history.frontend}}" wx:key="index"> |
||||
<image class="photo" mode="aspectFill" src="{{imageUrl}}note-demo1.png?t={{Timestamp}}"></image> |
||||
<view class="name">{{item.title}}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="card-title">侧面</view> |
||||
<view class="card-container"> |
||||
<view class="card-item" wx:for="{{history.backend}}" wx:key="index"> |
||||
<image class="photo" mode="aspectFill" src="{{imageUrl}}note-demo1.png?t={{Timestamp}}"></image> |
||||
<view class="name">{{item.title}}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
<view class="card"> |
||||
<view class="card-title">眼球运动八个方向</view> |
||||
<view class="card-container"> |
||||
<view class="card-item" wx:for="{{history.other}}" wx:key="index"> |
||||
<image class="photo" mode="aspectFill" src="{{imageUrl}}note-demo1.png?t={{Timestamp}}"></image> |
||||
<view class="name">{{item.title}}</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
</view> |
||||
|
||||
<popup |
||||
show="{{popupShow}}" |
||||
type="{{popupType}}" |
||||
params="{{popupParams}}" |
||||
bind:ok="handlePopupOk" |
||||
bind:cancel="handlePopupCancel" |
||||
></popup> |
||||
@ -0,0 +1,220 @@
@@ -0,0 +1,220 @@
|
||||
/** |
||||
* 阿里云验证码2.0工具模块 |
||||
* 用于小程序发送验证码前的行为验证 |
||||
*/ |
||||
|
||||
// 验证码插件实例
|
||||
let AliyunCaptchaPluginInterface: any = null |
||||
|
||||
// 计时器
|
||||
let timer: number | null = null |
||||
|
||||
// 页面实例引用
|
||||
let pageInstance: any = null |
||||
|
||||
// 发送验证码的接口配置
|
||||
interface SendCodeConfig { |
||||
url: string |
||||
mobileField?: string |
||||
extraData?: Record<string, any> |
||||
} |
||||
|
||||
// 验证码配置选项
|
||||
interface CaptchaOptions { |
||||
sceneId: string |
||||
sendCodeConfig: SendCodeConfig |
||||
onSendSuccess?: () => void |
||||
onSendFail?: (err: any) => void |
||||
countdown?: number |
||||
} |
||||
|
||||
// 当前配置
|
||||
let currentOptions: CaptchaOptions | null = null |
||||
|
||||
/** |
||||
* 初始化验证码插件 |
||||
*/ |
||||
function initPlugin() { |
||||
if (!AliyunCaptchaPluginInterface) { |
||||
AliyunCaptchaPluginInterface = requirePlugin('AliyunCaptcha') |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 验证通过回调函数 |
||||
* @param captchaVerifyParam 验证码验证参数 |
||||
*/ |
||||
async function successCallback(captchaVerifyParam: string) { |
||||
if (!pageInstance || !currentOptions) return |
||||
|
||||
const { sendCodeConfig, onSendSuccess, onSendFail, countdown = 60 } = currentOptions |
||||
const mobileField = sendCodeConfig.mobileField || 'mobile' |
||||
const mobile = pageInstance.data[mobileField] |
||||
|
||||
try { |
||||
const res = await wx.ajax({ |
||||
method: 'POST', |
||||
url: sendCodeConfig.url, |
||||
data: { |
||||
[mobileField]: mobile, |
||||
captchaVerifyParam, |
||||
...sendCodeConfig.extraData, |
||||
}, |
||||
}) |
||||
|
||||
wx.showToast({ |
||||
icon: 'none', |
||||
title: '验证码已发送~', |
||||
}) |
||||
|
||||
// 开始倒计时
|
||||
startCountdown(countdown) |
||||
|
||||
// 执行成功回调
|
||||
onSendSuccess?.() |
||||
|
||||
return res |
||||
} |
||||
catch (err: any) { |
||||
wx.showToast({ |
||||
title: err.data?.msg || '发送失败,请重试', |
||||
icon: 'none', |
||||
}) |
||||
onSendFail?.(err) |
||||
throw err |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 验证失败回调函数 |
||||
* @param error 错误信息 |
||||
*/ |
||||
function failCallback(error: any) { |
||||
console.error('阿里云验证码验证失败:', error) |
||||
wx.showToast({ |
||||
title: '验证失败,请重试', |
||||
icon: 'none', |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* 开始倒计时 |
||||
* @param seconds 倒计时秒数 |
||||
*/ |
||||
function startCountdown(seconds: number) { |
||||
if (timer) { |
||||
clearInterval(timer) |
||||
timer = null |
||||
} |
||||
|
||||
let time = seconds |
||||
updateCountdownText(`${time}s后重新发送`) |
||||
|
||||
timer = setInterval(() => { |
||||
time-- |
||||
if (time <= 0) { |
||||
clearInterval(timer as number) |
||||
timer = null |
||||
updateCountdownText('发送验证码') |
||||
} |
||||
else { |
||||
updateCountdownText(`${time}s后重新发送`) |
||||
} |
||||
}, 1000) as unknown as number |
||||
} |
||||
|
||||
/** |
||||
* 更新倒计时文本 |
||||
* @param text 显示的文本 |
||||
*/ |
||||
function updateCountdownText(text: string) { |
||||
if (pageInstance) { |
||||
pageInstance.setData({ codeText: text }) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 初始化验证码功能 |
||||
* @param page 页面实例 |
||||
* @param options 配置选项 |
||||
* @returns 插件配置对象 |
||||
*/ |
||||
export function initCaptcha(page: any, options: CaptchaOptions) { |
||||
initPlugin() |
||||
pageInstance = page |
||||
currentOptions = options |
||||
|
||||
const pluginProps = { |
||||
SceneId: options.sceneId, |
||||
mode: 'popup', |
||||
success: successCallback.bind(page), |
||||
fail: failCallback.bind(page), |
||||
slideStyle: { |
||||
width: 540, |
||||
height: 60, |
||||
}, |
||||
language: 'cn', |
||||
region: 'cn', |
||||
} |
||||
|
||||
return { |
||||
loadCaptcha: true, |
||||
pluginProps, |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 显示验证码弹窗 |
||||
* @returns 是否成功触发 |
||||
*/ |
||||
export function showCaptcha(): boolean { |
||||
if (!AliyunCaptchaPluginInterface) { |
||||
initPlugin() |
||||
} |
||||
|
||||
if (isCountingDown()) { |
||||
return false |
||||
} |
||||
|
||||
AliyunCaptchaPluginInterface.show() |
||||
return true |
||||
} |
||||
|
||||
/** |
||||
* 检查是否正在倒计时 |
||||
* @returns 是否正在倒计时 |
||||
*/ |
||||
export function isCountingDown(): boolean { |
||||
return timer !== null |
||||
} |
||||
|
||||
/** |
||||
* 清除倒计时 |
||||
*/ |
||||
export function clearCountdown() { |
||||
if (timer) { |
||||
clearInterval(timer) |
||||
timer = null |
||||
} |
||||
updateCountdownText('发送验证码') |
||||
} |
||||
|
||||
/** |
||||
* 获取验证码插件接口 |
||||
* @returns 插件接口 |
||||
*/ |
||||
export function getCaptchaPlugin() { |
||||
if (!AliyunCaptchaPluginInterface) { |
||||
initPlugin() |
||||
} |
||||
return AliyunCaptchaPluginInterface |
||||
} |
||||
|
||||
/** |
||||
* 页面卸载时清理资源 |
||||
*/ |
||||
export function destroyCaptcha() { |
||||
clearCountdown() |
||||
pageInstance = null |
||||
currentOptions = null |
||||
} |
||||
Loading…
Reference in new issue