Compare commits

..

No commits in common. 'master' and 'lightspot' have entirely different histories.

  1. 2
      .gitignore
  2. 240
      .trae/documents/proptosis_api_integration_plan.md
  3. 419
      .trae/rules/project_rules.md
  4. 4
      .vscode/settings.json
  5. 16
      .zed/settings.json
  6. 28
      README.md
  7. 32
      eslint.config.js
  8. 28
      eslint.config.mjs
  9. 8
      package.json
  10. 2596
      pnpm-lock.yaml
  11. 2
      project.config.json
  12. 155
      project.private.config.json
  13. 61
      src/app.json
  14. 103
      src/app.ts
  15. 43
      src/components/calendar/core.js
  16. 2
      src/components/calendar/helper.js
  17. 2
      src/components/calendar/index.d.ts
  18. 97
      src/components/calendar/index.js
  19. 2
      src/components/calendar/index.json
  20. 122
      src/components/calendar/plugins/holidays/holidays-map.js
  21. 2
      src/components/calendar/plugins/holidays/index.d.ts
  22. 86
      src/components/calendar/plugins/holidays/index.js
  23. 2
      src/components/calendar/plugins/index.d.ts
  24. 11
      src/components/calendar/plugins/index.js
  25. 116
      src/components/calendar/plugins/preset/base.js
  26. 30
      src/components/calendar/plugins/preset/get-calendar-data.js
  27. 2
      src/components/calendar/plugins/preset/index.d.ts
  28. 2
      src/components/calendar/plugins/preset/index.js
  29. 2
      src/components/calendar/plugins/selectable.d.ts
  30. 104
      src/components/calendar/plugins/selectable.js
  31. 662
      src/components/calendar/plugins/solarLunar/convertSolarLunar.js
  32. 2
      src/components/calendar/plugins/solarLunar/index.d.ts
  33. 29
      src/components/calendar/plugins/solarLunar/index.js
  34. 126
      src/components/calendar/plugins/time-range.js
  35. 2
      src/components/calendar/plugins/todo.d.ts
  36. 56
      src/components/calendar/plugins/todo.js
  37. 156
      src/components/calendar/plugins/week.js
  38. 47
      src/components/calendar/render.js
  39. 290
      src/components/calendar/utils/index.js
  40. 18
      src/components/calendar/utils/logger.js
  41. 17
      src/components/calendar/utils/wxData.js
  42. 148
      src/components/customPoster/README.md
  43. 204
      src/components/customPoster/index.js
  44. 1968
      src/components/customPoster/wxml2canvas/index.js
  45. 148
      src/components/customTable/README.md
  46. 203
      src/components/customTable/index.js
  47. 1966
      src/components/customTable/wxml2canvas/index.js
  48. 216
      src/components/ec-canvas/ec-canvas.js
  49. 2
      src/components/ec-canvas/ec-canvas.json
  50. 66
      src/components/ec-canvas/wx-canvas.js
  51. 149
      src/components/freeAudio/index.js
  52. 8
      src/components/image-merge/index.json
  53. 7
      src/components/image-merge/index.scss
  54. 200
      src/components/image-merge/index.ts
  55. 1
      src/components/image-merge/index.wxml
  56. 6
      src/components/loginNavbar/index.ts
  57. 6
      src/components/navbar/index.ts
  58. 7
      src/components/noteImagePreview/index.json
  59. 157
      src/components/noteImagePreview/index.scss
  60. 157
      src/components/noteImagePreview/index.ts
  61. 31
      src/components/noteImagePreview/index.wxml
  62. 6
      src/components/pageNavbar/index.ts
  63. 40
      src/components/patient-tab-bar/index.scss
  64. 16
      src/components/patient-tab-bar/index.ts
  65. 7
      src/components/patient-tab-bar/index.wxml
  66. 10
      src/components/pickerArea/index.scss
  67. 76
      src/components/pickerArea/index.ts
  68. 7
      src/components/pickerArea/index.wxml
  69. 511
      src/components/popup/index.scss
  70. 3
      src/components/popup/index.ts
  71. 184
      src/components/popup/index.wxml
  72. 2
      src/components/referralFrom/index.json
  73. 95
      src/components/referralFrom/index.scss
  74. 139
      src/components/referralFrom/index.ts
  75. 52
      src/components/referralFrom/index.wxml
  76. 209
      src/components/star/index.ts
  77. 8
      src/components/text-expandsion/index.scss
  78. 50
      src/components/timeOut/index.ts
  79. 143
      src/components/toast/index.scss
  80. 72
      src/components/toast/index.ts
  81. 65
      src/components/toast/index.wxml
  82. 87
      src/components/uploadFile/index.ts
  83. 28
      src/components/viewFile/index.js
  84. 2
      src/components/viewFile/index.json
  85. 7
      src/components/viewVideo/index.scss
  86. 228
      src/components/zd-navBar/navBar.js
  87. 2
      src/components/zd-navBar/navBar.scss
  88. 164
      src/components/zdUploadFile/index.js
  89. 12
      src/config.ts
  90. 74
      src/custom-tab-bar/index.scss
  91. 68
      src/custom-tab-bar/index.ts
  92. 23
      src/custom-tab-bar/index.wxml
  93. 2
      src/doc/pages/doc1/index.scss
  94. 6
      src/doc/pages/doc1/index.ts
  95. 2
      src/doc/pages/doc2/index.scss
  96. 5184
      src/gift/compontnts/echart/echarts.js
  97. 6
      src/gift/pages/conformOrder/index.json
  98. 184
      src/gift/pages/conformOrder/index.scss
  99. 86
      src/gift/pages/conformOrder/index.ts
  100. 56
      src/gift/pages/conformOrder/index.wxml
  101. Some files were not shown because too many files have changed in this diff Show More

2
.gitignore vendored

@ -1,6 +1,4 @@
node_modules node_modules
src/images/.svn src/images/.svn
src/images/
.idea .idea
.DS_Store .DS_Store
/src/images

240
.trae/documents/proptosis_api_integration_plan.md

@ -1,240 +0,0 @@
# 突眼日记接口联调计划
## 一、项目现状分析
### 1.1 已有页面结构
**医生端 (d\_ 前缀)**
- `d_noteList` - 突眼记录列表页(拍摄示例页)
- `d_noteDetail` - 突眼记录详情页
- `d_noteDiffData` - 凸眼度对比数据页(表格展示)
_患者端 (patient/pages/note_)\*
- `note` - 突眼日记首页
- `noteAdd` - 新增记录页
- `noteHistory` - 历史记录页
- `noteDiff` - 照片对比页
- `noteDiffEdit` - 对比编辑页
- `noteDemo` - 拍摄示例页
### 1.2 当前状态
- 所有页面都是静态数据,未接入接口
- 请求工具已封装在 `utils/request.ts`
- 使用 `wx.ajax` 进行接口调用(在 app.ts 中挂载)
---
## 二、需要的信息
在开始联调前,需要你提供以下信息:
### 2.1 环境信息
| 信息项 | 说明 | 是否必需 |
| -------------- | --------------------------- | -------- |
| 后端环境地址 | 开发/测试服务器地址 | 是 |
| 接口是否已部署 | 后端接口是否已上线可调用 | 是 |
| 登录态获取方式 | 如何获取 loginState/session | 是 |
### 2.2 接口测试信息
| 信息项 | 说明 | 是否必需 |
| ---------- | -------------------------- | -------- |
| 测试账号 | 医生账号和患者账号 | 是 |
| 测试患者ID | 用于医生端接口测试 | 是 |
| 已有数据 | 是否有已创建的突眼记录数据 | 否 |
### 2.3 图片上传相关
| 信息项 | 说明 | 是否必需 |
| ------------- | ----------------------------- | -------- |
| 图片上传方式 | 上传到腾讯云COS还是自家服务器 | 是 |
| 腾讯云IMS配置 | 是否已配置图片内容安全校验 | 否 |
---
## 三、接口联调清单
### 3.1 患者端接口 (10个)
| 序号 | 接口 | 用途 | 对应页面 | 优先级 |
| ---- | ------------------- | ---------------- | ----------------- | ------ |
| 1 | `baseline-status` | 获取基准照状态 | note | P0 |
| 2 | `record-list` | 获取记录列表 | note, noteHistory | P0 |
| 3 | `record-detail` | 获取记录详情 | noteHistory | P0 |
| 4 | `record-save` | 创建/更新记录 | noteAdd | P0 |
| 5 | `photo-upload` | 上传照片 | noteAdd | P0 |
| 6 | `record-delete` | 删除记录 | noteHistory | P1 |
| 7 | `compare-dates` | 获取对比可用日期 | noteDiff | P1 |
| 8 | `compare-photos` | 获取对比照片 | noteDiff | P1 |
| 9 | `get-compare-angle` | 获取对比角度列表 | noteDiffEdit | P1 |
| 10 | `get-session-id` | 获取唯一标识 | noteAdd | P2 |
### 3.2 医生端接口 (6个)
| 序号 | 接口 | 用途 | 对应页面 | 优先级 |
| ---- | ------------------------------------ | ---------------- | --------------- | ------ |
| 1 | `doctor/proptosis/latest` | 获取最近记录 | d_patientDetail | P0 |
| 2 | `doctor/proptosis/list` | 获取患者记录列表 | d_noteList | P0 |
| 3 | `doctor/proptosis/detail` | 获取记录详情 | d_noteDetail | P0 |
| 4 | `doctor/proptosis/export` | Excel导出 | d_noteDiffData | P1 |
| 5 | `doctor/proptosis/compare` | 获取对比数据 | d_noteDiffData | P1 |
| 6 | `doctor/proptosis/get-compare-angle` | 获取对比角度 | d_noteDiffData | P1 |
---
## 四、实施步骤
### Phase 1: 基础联调准备
1. 确认后端环境可用
2. 获取测试账号和患者ID
3. 验证登录态获取
### Phase 2: 患者端核心功能
1. 实现记录列表获取 (`record-list`)
2. 实现记录详情获取 (`record-detail`)
3. 实现记录创建/更新 (`record-save`)
4. 实现照片上传 (`photo-upload`)
### Phase 3: 患者端对比功能
1. 实现对比日期获取 (`compare-dates`)
2. 实现对比照片获取 (`compare-photos`)
3. 实现对比角度获取 (`get-compare-angle`)
### Phase 4: 医生端功能
1. 实现患者最近记录获取 (`doctor/proptosis/latest`)
2. 实现患者记录列表 (`doctor/proptosis/list`)
3. 实现记录详情 (`doctor/proptosis/detail`)
4. 实现对比数据获取 (`doctor/proptosis/compare`)
### Phase 5: 导出功能
1. 实现Excel导出 (`doctor/proptosis/export`)
---
## 五、数据结构映射
### 5.1 患者端 - 记录列表
```typescript
// 接口返回
interface RecordItem {
recordId: string
recordDate: string
isBaseline: number
photoCount: number
firstPhotoUrl: string
treatmentCount: number
leftEye: number
rightEye: number
interorbitalDistance: number
uploadCompleted: number
}
// 页面使用
interface DataListItem {
date: string // recordDate 格式化
left: string // leftEye
spacing: string // interorbitalDistance
right: string // rightEye
count: string // treatmentCount
isBaseline: boolean
photoCount: number
firstPhotoUrl: string
}
```
### 5.2 医生端 - 凸眼度对比表格
```typescript
// 接口返回 (compare 接口)
interface CompareItem {
recordId: string
recordDate: string
photoUrl: string
leftEye: number
rightEye: number
interorbitalDistance: number
treatmentCount: number
}
// 页面使用 (d_noteDiffData)
interface TableItem {
date: string // recordDate 格式化 2026.1.5
left: string // leftEye
spacing: string // interorbitalDistance
right: string // rightEye
count: string // treatmentCount
}
```
---
## 六、注意事项
### 6.1 业务规则
1. 同一天只能创建一条记录
2. 必须先上传照片再保存记录(photoIds 关联)
3. 基准照只能有一张
4. 图片需要经过腾讯云IMS安全校验
### 6.2 技术注意
1. 使用 `wx.ajax` 进行请求(已挂载在 app 上)
2. 医生端页面需要等待登录态 `app.waitLogin({ type: [2] })`
3. 患者端页面需要等待登录态 `app.waitLogin({ type: [1] })`
4. 图片URL需要拼接 `{{imageUrl}}` 前缀
### 6.3 角度映射
接口角度值与页面显示名称映射:
```typescript
const angleMap = {
front_open: '正面睁眼',
front_closed: '正面闭眼',
front_looking_up: '正面仰头',
side_left_90: '90°左侧',
side_right_90: '90°右侧',
side_left_45: '45°左侧',
side_right_45: '45°右侧',
eye_up_left: '左上',
eye_up: '向上',
eye_up_right: '右上',
eye_left: '向左',
eye_right: '向右',
eye_down_left: '左下',
eye_down: '向下',
eye_down_right: '右下',
}
```
---
## 七、下一步
请提供以下信息,我将开始实施联调:
1. **后端环境地址**(如:<https://m.xd.hbraas.com>
2. **测试账号**(医生和患者各一个)
3. **测试患者ID**(用于医生端接口测试)
4. **接口是否已部署**(确认后端已完成开发)
5. **图片上传方式**(腾讯云COS或自家服务器)

419
.trae/rules/project_rules.md

@ -1,419 +0,0 @@
# 项目规则 - 信达小程序 (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',
})
```
### App Instance (Required)
`getApp()` should be called at the top of the file, not inside methods:
```ts
// ✅ Correct
const app = getApp<IAppOption>()
Page({
onLoad() {
// Use app directly
console.log(app.globalData)
}
})
// ❌ Incorrect
Page({
onLoad() {
const app = getApp<IAppOption>()
console.log(app.globalData)
}
})
```
## WXML 开发规范
### 1. 不支持在 WXML 中直接调用方法
**错误示例:**
```xml
<!-- ❌ 错误:WXML 中不能直接调用方法 -->
<view>{{getUploadedCount()}}</view>
<view wx:if="{{hasPhotos()}}">内容</view>
```
**正确做法:**
```xml
<!-- ✅ 正确:使用数据绑定 -->
<view>{{uploadedCount}}</view>
<view wx:if="{{hasPhotos}}">内容</view>
```
```typescript
// 在 TS 中计算好数据
this.setData({
uploadedCount: photos.length,
hasPhotos: photos.length > 0
})
```
### 2. 列表渲染时使用 wx:key
```xml
<view wx:for="{{list}}" wx:key="id">{{item.name}}</view>
```
### 3. 条件渲染
```xml
<view wx:if="{{condition}}">显示</view>
<view wx:else>隐藏</view>
```
### 4. WXML 表达式限制
WXML 中的双大括号 `{{}}` 只能使用简单的表达式,**不支持**以下语法:
**❌ 不支持的语法:**
```xml
<!-- 方法调用 -->
<view>{{arr.indexOf(item) > -1}}</view>
<!-- 复杂表达式 -->
<view>{{obj.method().property}}</view>
<!-- 正则表达式 -->
<view>{{str.match(/regex/)}}</view>
<!-- new 操作符 -->
<view>{{new Date().getTime()}}</view>
```
**✅ 支持的语法:**
```xml
<!-- 简单属性访问 -->
<view>{{item.name}}</view>
<!-- 三元表达式 -->
<view class="{{item.isActive ? 'active' : ''}}">内容</view>
<!-- 简单比较 -->
<view wx:if="{{count > 0}}">有数据</view>
<!-- 逻辑运算 -->
<view wx:if="{{isLogin && isVip}}">VIP用户</view>
```
**解决方案:**
```typescript
// 在 TS 中预处理数据,将复杂计算转换为简单布尔值
this.setData({
// ❌ 不要在 WXML 中使用 indexOf
// isSelected: selectedDates.indexOf(item.recordId) > -1
// ✅ 在数据中直接提供 isSelected 字段
list: rawList.map(item => ({
...item,
isSelected: selectedDates.includes(item.recordId)
}))
})
```
## 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()`
## 自定义导航栏规范
### 统一使用 navbar 组件
所有需要自定义导航的页面统一使用 `/components/navbar/index`。`/components/zd-navBar/navBar` 是历史遗留组件,新页面**不要使用**。
**JSON 配置:**
```json
{
"navigationStyle": "custom",
"usingComponents": {
"navbar": "/components/navbar/index"
}
}
```
**WXML 用法:**
```xml
<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;">
```
**TS 实现:**
```typescript
handleBack() {
wx.navigateBack()
}
```
### 关键参数
| 属性 | 说明 | 常用值 |
| -------------- | ------------ | --------------------------- |
| `fixed` | 固定导航栏 | `fixed` |
| `title` | 导航栏标题 | 字符串 |
| `custom-style` | 自定义样式 | `background:{{background}}` |
| `leftArrow` | 显示返回箭头 | Boolean |
| `slot="left"` | 左侧插槽 | van-icon 返回按钮 |
| `bind:tap` | 返回按钮点击 | `handleBack` |
### pageTop 变量
`pageTop``utils/page.ts` wrapper 自动注入,表示导航栏高度。页面内容区使用 `padding-top:{{pageTop+20}}px;` 避开导航栏。**不要手动计算 navBarHeight**。
## 返回拦截与弹窗规范
### 使用自定义弹窗替代系统弹窗
**禁止使用** `wx.showModal` 进行操作确认,统一使用项目内的 popup 组件:
```json
{
"usingComponents": {
"popup": "/components/popup/index"
}
}
```
```xml
<popup show="{{popupShow}}" type="{{popupType}}" params="{{popupParams}}" bind:ok="handlePopupOk" bind:cancel="handlePopupCancel" />
```
### 常用 popup 类型
| 类型 | 场景 | 标题 | 确认按钮 | 取消按钮 |
| --------- | -------------- | ------------------ | -------- | -------- |
| `popup15` | 删除确认 | "确认删除记录?" | 确认删除 | 取消 |
| `popup16` | 未保存数据退出 | "您的记录还未保存" | 保存记录 | 退出 |
| `popup17` | 裁剪未保存退出 | "您有裁剪的照片" | 退出 | 取消 |
### popup 数据定义
```typescript
data: {
popupShow: false,
popupType: 'popup16',
popupParams: {
close: false,
position: 'center',
} as any,
}
```
### 返回拦截模式
当页面有未保存数据时,使用自定义导航 + `bind:back` 拦截返回:
```typescript
handleBack() {
if (this.hasUnsavedData()) {
this.setData({ popupShow: true, popupType: 'popup16' })
} else {
wx.navigateBack()
}
}
handlePopupOk() {
this.setData({ popupShow: false })
this.handleSave()
}
handlePopupCancel() {
this.setData({ popupShow: false })
wx.navigateBack()
}
```
**注意**:`navigationStyle: "custom"` 后系统返回手势无法拦截,只有 navBar 的返回按钮可被拦截。如需拦截系统返回手势,需要额外使用 `wx.enableAlertBeforeUnload`
## wx.cropImage 规范
`wx.cropImage``src` 参数**只接受本地文件路径**,不支持网络 URL。裁剪网络图片时必须先用 `wx.getImageInfo` 下载到本地:
```typescript
handleCrop(e: any) {
const index = e.currentTarget.dataset.index
const photo = this.data.photos[index]
wx.showLoading({ title: '加载中...' })
wx.getImageInfo({
src: photo.photoUrl,
success: (imgRes) => {
wx.hideLoading()
wx.cropImage({
src: imgRes.path,
cropScale: '9:16',
success: (cropRes) => {
photos[index].croppedUrl = cropRes.tempFilePath
this.setData({ photos })
},
fail: (err) => {
if (err.errMsg?.includes('cancel')) return
wx.showToast({ title: '裁剪取消', icon: 'none' })
},
})
},
fail: () => {
wx.hideLoading()
wx.showToast({ title: '图片加载失败', icon: 'none' })
},
})
}
```
## 子包组件引用规范
主包页面(`src/pages/`)**不能引用**子包组件(`src/patient/components/`)。如果主包和子包都需要使用某个组件,需要将组件复制到 `src/components/` 目录下。
示例:`image-merge` 组件在 `patient/components/``components/` 各有一份,分别供子包和主包页面使用。

4
.vscode/settings.json vendored

@ -1,7 +1,7 @@
{ {
"path-autocomplete.pathMappings": { "path-autocomplete.pathMappings": {
"@": "${folder}/src", "@": "${folder}/src",
"/": "${folder}/src" "/": "${folder}/src",
}, },
"emmet.preferences": { "emmet.preferences": {
"css.intUnit": "rpx", "css.intUnit": "rpx",
@ -9,5 +9,5 @@
}, },
"css.customData": [ "css.customData": [
".vscode/css-data.json" ".vscode/css-data.json"
] ],
} }

16
.zed/settings.json

@ -1,16 +0,0 @@
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#settings-files
{
"lsp": {
"emmet-language-server": {
"initialization_options": {
"preferences": {
"css.intUnit": "rpx",
"css.floatUnitr": "rpx",
},
},
},
},
}

28
README.md

@ -10,19 +10,8 @@ images svn 地址
svn://39.106.86.127:28386/projects/xd/proj_src/shop/frontend/web/xd svn://39.106.86.127:28386/projects/xd/proj_src/shop/frontend/web/xd
svn://39.106.86.127:28386/projects/xd/proj_src/branches/dev_v2.0/shop/frontend/web/xd/ svn://39.106.86.127:28386/projects/xd/proj_src/branches/dev_v2.0/shop/frontend/web/xd/
## vscode
```
(/images/)(\S*(?=["|'])) (/images/)(\S*(?=["|']))
{{imageUrl}}$2?t={{Timestamp}} {{imageUrl}}$2?t={{Timestamp}}
```
## neovim
```
(/images/)([^\"|']*)
{{imageUrl}}$2?t={{Timestamp}}
```
ui问题 ui问题
@ -40,20 +29,3 @@ wx.showModal({
审核账号 审核账号
18910233000 1111 18910233000 1111
正整数 3
正整数 2
正整数 4
正整数 2
正整数 3
已修改未上线内容
1. 医生端首页 统计数据改为实时更新
2. 就诊地图重新定位,在非北京地区重新定位会重新定位到北京,再次切换才会定位到当地
3. 患者端注册页导航栏增加返回上一页按钮
4. 量表安奈德修改为甲泼尼龙
5. 患者端聊天页点击任意区域都可关闭底部操作浮层
6. 患者顿啊登录页底部隐私政策区域展示异常修复

32
eslint.config.js

@ -1,32 +0,0 @@
import antfu from '@antfu/eslint-config'
export default antfu({
env: {
es6: true,
},
ignores: [
'**/miniprogram_npm/**',
'src/miniprogram_npm/**',
],
parserOptions: { project: ['./tsconfig.json'] },
globals: {
wx: true,
App: true,
Page: true,
getCurrentPages: true,
getApp: true,
Component: true,
requirePlugin: true,
requireMiniProgram: true,
},
rules: {
'eslint-comments/no-unlimited-disable': 'off',
'ts/no-require-imports': 'off',
'eqeqeq': 'off',
},
formatters: {
css: 'prettier',
html: 'prettier',
markdown: 'prettier',
},
})

28
eslint.config.mjs

@ -0,0 +1,28 @@
// eslint.config.mjs
import antfu from '@antfu/eslint-config'
import prettierConfig from 'eslint-config-prettier'
export default antfu(
{
env: {
es6: true,
},
stylistic: false,
parserOptions: { project: ['./tsconfig.json'] },
globals: {
wx: true,
App: true,
Page: true,
getCurrentPages: true,
getApp: true,
Component: true,
requirePlugin: true,
requireMiniProgram: true,
},
rules: {
'eslint-comments/no-unlimited-disable': 'off',
'ts/no-require-imports': 'off',
},
},
prettierConfig,
)

8
package.json

@ -18,10 +18,10 @@
"typescript": "^5.3.3" "typescript": "^5.3.3"
}, },
"devDependencies": { "devDependencies": {
"@antfu/eslint-config": "^6.2.0", "@antfu/eslint-config": "^3.7.3",
"eslint": "^9.38.0", "eslint": "^9.12.0",
"eslint-plugin-format": "^1.0.2", "eslint-config-prettier": "^9.1.0",
"miniprogram-api-typings": "^4.1.0", "miniprogram-api-typings": "^4.0.1",
"prettier": "3.3.3" "prettier": "3.3.3"
} }
} }

2596
pnpm-lock.yaml

File diff suppressed because it is too large Load Diff

2
project.config.json

@ -72,4 +72,4 @@
] ]
}, },
"appid": "wxf9ce8010f1ad24aa" "appid": "wxf9ce8010f1ad24aa"
} }

155
project.private.config.json

@ -3,7 +3,7 @@
"projectname": "xinda-miniprogram", "projectname": "xinda-miniprogram",
"setting": { "setting": {
"compileHotReLoad": true, "compileHotReLoad": true,
"urlCheck": false, "urlCheck": true,
"coverView": false, "coverView": false,
"lazyloadPlaceholderEnable": false, "lazyloadPlaceholderEnable": false,
"skylineRenderEnable": true, "skylineRenderEnable": true,
@ -23,149 +23,23 @@
"miniprogram": { "miniprogram": {
"list": [ "list": [
{ {
"name": "医生端-眼突度-对比", "name": "patient/pages/liveDetail/index",
"pathName": "pages/d_noteDiffData/index", "pathName": "patient/pages/liveDetail/index",
"query": "", "query": "id=33",
"scene": null, "scene": null,
"launchMode": "default" "launchMode": "default"
}, },
{ {
"name": "医生端-日记列表", "name": "患者-个人信息",
"pathName": "pages/d_noteList/index", "pathName": "patient/pages/personalInformation/index",
"query": "", "query": "bottom=1",
"launchMode": "default",
"scene": null
},
{
"name": "医生-突眼日记单条记录",
"pathName": "pages/d_noteDetail/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "医生-患者详情",
"pathName": "pages/d_patientDetail/index",
"query": "id=319",
"launchMode": "default",
"scene": null
},
{
"name": "突眼日记照片对比编辑",
"pathName": "patient/pages/noteDiffEdit/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "眼突日记照片对比",
"pathName": "patient/pages/noteDiff/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "突眼日记-历史记录",
"pathName": "patient/pages/noteHistory/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "突眼日记拍照示例",
"pathName": "patient/pages/noteDemo/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "突眼日记添加",
"pathName": "patient/pages/noteAdd/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "突眼日记",
"pathName": "patient/pages/note/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "patient/pages/imageProcessing/index",
"pathName": "patient/pages/imageProcessing/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "患者-qol",
"pathName": "patient/pages/qol/index",
"query": "pushId=81",
"launchMode": "default",
"scene": null
},
{
"name": "医生-患者量表",
"pathName": "pages/d_qolDetail/index",
"query": "id=178",
"launchMode": "default",
"scene": null
},
{
"name": "医保-详情",
"pathName": "patient/pages/medicalDetail/index",
"query": "id=3",
"launchMode": "default",
"scene": null
},
{
"name": "患者-医保",
"pathName": "patient/pages/medical/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "医生-激素用药详情",
"pathName": "pages/d_patientHormones/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "激素量表-结果页",
"pathName": "patient/pages/hormonesResult/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "激素量表",
"pathName": "patient/pages/hormones/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "药房",
"pathName": "gift/pages/dtpDurg/index",
"query": "id=10",
"launchMode": "default",
"scene": null
},
{
"name": "就诊地图",
"pathName": "patient/pages/doctor/index",
"query": "",
"launchMode": "default", "launchMode": "default",
"scene": null "scene": null
}, },
{ {
"name": "患者-个人信息", "name": "patient/pages/liveResult/index",
"pathName": "patient/pages/personalInformation/index", "pathName": "patient/pages/liveResult/index",
"query": "bottom=1", "query": "id=30&rewardScore=undefined",
"launchMode": "default", "launchMode": "default",
"scene": null "scene": null
}, },
@ -198,6 +72,13 @@
"scene": null "scene": null
}, },
{ {
"name": "患者-qol",
"pathName": "patient/pages/qol/index",
"query": "",
"launchMode": "default",
"scene": null
},
{
"name": "患者-录入个人信息", "name": "患者-录入个人信息",
"pathName": "patient/pages/enterInfo/index", "pathName": "patient/pages/enterInfo/index",
"query": "", "query": "",
@ -320,4 +201,4 @@
} }
}, },
"libVersion": "3.8.9" "libVersion": "3.8.9"
} }

61
src/app.json

@ -14,14 +14,7 @@
"pages/d_patientDetail/index", "pages/d_patientDetail/index",
"pages/d_userInfo/index", "pages/d_userInfo/index",
"pages/d_invite/index", "pages/d_invite/index",
"pages/d_patient/index", "pages/d_patient/index"
"pages/d_patientHormones/index",
"pages/d_qolDetail/index",
"pages/d_noteDetail/index",
"pages/d_noteList/index",
"pages/d_noteDiffData/index",
"pages/d_noteDiff/index",
"pages/d_noteDiffEdit/index"
], ],
"subPackages": [ "subPackages": [
{ {
@ -33,7 +26,13 @@
"pages/vipLoginReject/index", "pages/vipLoginReject/index",
"pages/startReject/index", "pages/startReject/index",
"pages/startPending/index", "pages/startPending/index",
"pages/story/index",
"pages/publishStoryDetail/index", "pages/publishStoryDetail/index",
"pages/storyEnter/index",
"pages/storyEnterResult/index",
"pages/storyList/index",
"pages/storyGuide/index",
"pages/storyDetail/index",
"pages/my/index", "pages/my/index",
"pages/mySave/index", "pages/mySave/index",
"pages/myLive/index", "pages/myLive/index",
@ -59,6 +58,10 @@
"pages/liveResult/index", "pages/liveResult/index",
"pages/liveDetailVideo/index", "pages/liveDetailVideo/index",
"pages/signIn/index", "pages/signIn/index",
"pages/adl/index",
"pages/adlShare/index",
"pages/adlTest/index",
"pages/adlResult/index",
"pages/smallPage/index", "pages/smallPage/index",
"pages/hospital/index", "pages/hospital/index",
"pages/doctor/index", "pages/doctor/index",
@ -66,29 +69,42 @@
"pages/drugRecord/index", "pages/drugRecord/index",
"pages/comIns/index", "pages/comIns/index",
"pages/webview/index", "pages/webview/index",
"pages/nrdl/index",
"pages/nrdlDetail/index",
"pages/infusionCenter/index", "pages/infusionCenter/index",
"pages/nrdlTable/index",
"pages/interactivePatient/index", "pages/interactivePatient/index",
"pages/referral/index",
"pages/qol/index", "pages/qol/index",
"pages/qolAdd/index", "pages/qolAdd/index",
"pages/qolResult/index", "pages/qolResult/index",
"pages/qolReport/index", "pages/qolReport/index"
"pages/hormonesStart/index",
"pages/hormones/index",
"pages/hormonesResult/index",
"pages/medical/index",
"pages/medicalDetail/index",
"pages/note/index",
"pages/noteAdd/index",
"pages/noteDemo/index",
"pages/noteHistory/index",
"pages/noteDiff/index",
"pages/noteDiffEdit/index",
"pages/imageProcessing/index"
] ]
}, },
{ {
"root": "gift", "root": "gift",
"pages": ["pages/dtpDurg/index"] "independent": true,
"pages": [
"pages/giftList/index",
"pages/conformOrder/index",
"pages/siteList/index",
"pages/siteEdit/index",
"pages/orderEnd/index",
"pages/orderDetail/index",
"pages/myGift/index",
"pages/priceDetail/index",
"pages/scoreRule/index",
"pages/dtpDurg/index",
"pages/vipCert/index",
"pages/vipReject/index",
"pages/vipPending/index",
"pages/vipStartPending/index",
"pages/myHealthRecord/index",
"pages/myHealthRecordChart/index",
"pages/cutaneous/index",
"pages/cutaneousDetail/index",
"pages/cutaneousVideo/index"
]
}, },
{ {
"root": "doc", "root": "doc",
@ -152,7 +168,6 @@
}, },
"componentFramework": "glass-easel", "componentFramework": "glass-easel",
"sitemapLocation": "sitemap.json", "sitemapLocation": "sitemap.json",
"requiredPrivateInfos": ["getFuzzyLocation"],
"lazyCodeLoading": "requiredComponents", "lazyCodeLoading": "requiredComponents",
"requiredBackgroundModes": ["audio"] "requiredBackgroundModes": ["audio"]
} }

103
src/app.ts

@ -1,11 +1,10 @@
import dayjs from 'dayjs'
import licia from 'miniprogram-licia'
import component from '@/utils/component' import component from '@/utils/component'
import relativeTime from '@/utils/dayjs/relativeTime.js' import relativeTime from '@/utils/dayjs/relativeTime.js'
import page from '@/utils/page' import page from '@/utils/page'
import { request } from '@/utils/request' import { request } from '@/utils/request'
import config from './config'
import { parseScene } from './utils/util' import { parseScene } from './utils/util'
const dayjs = require('dayjs')
const licia = require('miniprogram-licia')
require('/utils/dayjs/day-zh-cn.js') require('/utils/dayjs/day-zh-cn.js')
@ -14,7 +13,6 @@ dayjs.extend(relativeTime)
App<IAppOption>({ App<IAppOption>({
globalData: { globalData: {
version: '2.0', // 在数据请求里面发送给后端的版本号[X-MP-Version]
// 测试号 wx2b0bb13edf717c1d // 测试号 wx2b0bb13edf717c1d
// dev // dev
// appid:wxf9ce8010f1ad24aa // appid:wxf9ce8010f1ad24aa
@ -99,20 +97,12 @@ App<IAppOption>({
99: '取消', 99: '取消',
100: '已删除', 100: '已删除',
}, },
liveSubscribe: {
sub: false,
tmplIds: [],
},
}, },
onLaunch() { onLaunch() {
const appid = wx.getAccountInfoSync().miniProgram.appId
Object.assign(this.globalData, config[appid] || {})
Page = page as WechatMiniprogram.Page.Constructor Page = page as WechatMiniprogram.Page.Constructor
Component = component as WechatMiniprogram.Component.Constructor Component = component as WechatMiniprogram.Component.Constructor
wx.ajax = licia.curry(request)({ gUrl: this.globalData.url, version: this.globalData.version }) wx.ajax = licia.curry(request)({ gUrl: this.globalData.url })
this.startLogin() this.startLogin()
@ -120,14 +110,11 @@ App<IAppOption>({
obeyMuteSwitch: false, obeyMuteSwitch: false,
mixWithOther: false, mixWithOther: false,
}) })
this.handleUpdateMiniprogram()
}, },
onShow(options) { onShow(options) {
if (options.query.scene) { if (options.query.scene) {
this.globalData.scene = parseScene(options.query.scene) this.globalData.scene = parseScene(options.query.scene)
} } else if (options.query.proMethodId) {
else if (options.query.proMethodId) {
this.globalData.scene.proMethodId = options.query.proMethodId this.globalData.scene.proMethodId = options.query.proMethodId
} }
}, },
@ -196,13 +183,13 @@ App<IAppOption>({
if (type.includes(0) && [0, 1, 2].includes(loginType)) { if (type.includes(0) && [0, 1, 2].includes(loginType)) {
return true return true
} }
if (type.includes(0) || type.includes(1)) { if ([0, 1].includes(loginType)) {
wx.reLaunch({ wx.reLaunch({
url: '/patient/pages/login/index', url: '/patient/pages/login/index',
}) })
return false return false
} }
if (type.includes(2)) { if (loginType === 2) {
wx.reLaunch({ wx.reLaunch({
url: '/pages/login/index', url: '/pages/login/index',
}) })
@ -248,7 +235,7 @@ App<IAppOption>({
data: {}, data: {},
}) as Promise<never> }) as Promise<never>
}, },
mpBehavior(data: { doctor?: boolean, PageName: string }) { mpBehavior(data: { doctor?: boolean; PageName: string }) {
let url = '?r=zd/mp-behavior/add' let url = '?r=zd/mp-behavior/add'
if (data.doctor) { if (data.doctor) {
url = '?r=zd/doctor/mp-behavior/add' url = '?r=zd/doctor/mp-behavior/add'
@ -280,10 +267,9 @@ App<IAppOption>({
}) })
}, },
// zd相关函数 // zd相关函数
zdMpBehavior(data: { PageName: string, doctor?: boolean }) { zdMpBehavior(data: { PageName: string; doctor?: boolean }) {
const { loginType } = this.globalData const { loginType } = this.globalData
if (loginType === 0) if (loginType === 0) return
return
let url = '?r=zd/mp-behavior/add' let url = '?r=zd/mp-behavior/add'
if (data.doctor) { if (data.doctor) {
url = '?r=zd/doctor/mp-behavior/add' url = '?r=zd/doctor/mp-behavior/add'
@ -310,15 +296,13 @@ App<IAppOption>({
if (this.zdVerifySys(pub)) { if (this.zdVerifySys(pub)) {
if (this.globalData.loginType === 1) { if (this.globalData.loginType === 1) {
this.zdRegistrationVerification(() => resolve(), loginPage) this.zdRegistrationVerification(() => resolve(), loginPage)
} } else {
else {
resolve() resolve()
} }
} }
} }
const unRegFun = (resolve) => { const unRegFun = (resolve) => {
if (!this.zdVerifySys(pub)) if (!this.zdVerifySys(pub)) return
return
resolve() resolve()
} }
return new Promise((resolve: (value?) => void) => { return new Promise((resolve: (value?) => void) => {
@ -376,14 +360,11 @@ App<IAppOption>({
let urlKey = '' let urlKey = ''
if (!PatientId) { if (!PatientId) {
urlKey = 'enterInfo' urlKey = 'enterInfo'
} } else if (AuditStatus == 0) {
else if (AuditStatus == 0) {
urlKey = 'noCert' urlKey = 'noCert'
} } else if (AuditStatus == 1) {
else if (AuditStatus == 1) {
urlKey = isFollow ? 'nopending' : 'pending' urlKey = isFollow ? 'nopending' : 'pending'
} } else if (AuditStatus == 2) {
else if (AuditStatus == 2) {
urlKey = 'reject' urlKey = 'reject'
} }
const navUrl = { const navUrl = {
@ -434,8 +415,7 @@ App<IAppOption>({
}) })
return false return false
} }
if (ignorePath.includes(url)) if (ignorePath.includes(url)) return true
return true
if (loginType === 1) { if (loginType === 1) {
if (url.includes('doctor/pages')) { if (url.includes('doctor/pages')) {
@ -443,16 +423,14 @@ App<IAppOption>({
url: '/pages/index/index', url: '/pages/index/index',
}) })
return false return false
} } else {
else {
return true return true
} }
} }
if (loginType === 2 && !pub) { if (loginType === 2 && !pub) {
if (url.includes('doctor/pages')) { if (url.includes('doctor/pages')) {
return true return true
} } else {
else {
const params = Object.entries(options) const params = Object.entries(options)
.map(([key, value]) => `${key}=${value}`) .map(([key, value]) => `${key}=${value}`)
.join('&') .join('&')
@ -477,8 +455,7 @@ App<IAppOption>({
url: '/patient/pages/login/index', url: '/patient/pages/login/index',
}) })
isReject = true isReject = true
} } else if (!isNewReg) {
else if (!isNewReg) {
wx.reLaunch({ wx.reLaunch({
url: '/patient/pages/enterInfo/index', url: '/patient/pages/enterInfo/index',
}) })
@ -487,7 +464,7 @@ App<IAppOption>({
} }
if (isReject) { if (isReject) {
that.globalData.backPage = backPage that.globalData.backPage = backPage
reject(new Error('非登录用户拦截')) reject(null)
return return
} }
resolve(null) resolve(null)
@ -541,46 +518,4 @@ App<IAppOption>({
callback(res) callback(res)
}) })
}, },
setTabbarNoticeMessage() {
wx.ajax({
method: 'GET',
url: '?r=zd/doctor/message-interact/get-unread-count',
data: {},
}).then((res) => {
if (res > 0) {
wx.setTabBarBadge({
index: 2,
text: res > 99 ? '99+' : res,
})
return
}
wx.removeTabBarBadge({ index: 2 })
})
},
handleUpdateMiniprogram() {
const updateManager = wx.getUpdateManager()
updateManager.onCheckForUpdate((res) => {
// 请求完新版本信息的回调
// eslint-disable-next-line no-console
console.log(res.hasUpdate)
})
updateManager.onUpdateReady(() => {
wx.showModal({
title: '更新提示',
content: '新版本已经准备好,是否重启应用?',
success(res) {
if (res.confirm) {
// 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
updateManager.applyUpdate()
}
},
})
})
updateManager.onUpdateFailed(() => {
// 新版本下载失败
})
},
}) })

43
src/components/calendar/core.js

@ -10,7 +10,7 @@ function calculateEmptyGrids(year, month, config) {
const nextMonthGrids = calculateNextMonthGrids(year, month, config) const nextMonthGrids = calculateNextMonthGrids(year, month, config)
return { return {
prevMonthGrids, prevMonthGrids,
nextMonthGrids, nextMonthGrids
} }
} }
@ -20,14 +20,13 @@ function calculateEmptyGrids(year, month, config) {
* @param {number} month 月份 * @param {number} month 月份
*/ */
function calculatePrevMonthGrids(year, month, config) { function calculatePrevMonthGrids(year, month, config) {
const emptyGrids = [] let emptyGrids = []
const prevMonthDays = dateUtil.getDatesCountOfMonth(year, month - 1) const prevMonthDays = dateUtil.getDatesCountOfMonth(year, month - 1)
let firstDayOfWeek = dateUtil.firstDayOfWeek(year, month) let firstDayOfWeek = dateUtil.firstDayOfWeek(year, month)
if (config.firstDayOfWeek === 'Mon') { if (config.firstDayOfWeek === 'Mon') {
if (firstDayOfWeek === 0) { if (firstDayOfWeek === 0) {
firstDayOfWeek = 6 firstDayOfWeek = 6
} } else {
else {
firstDayOfWeek -= 1 firstDayOfWeek -= 1
} }
} }
@ -38,13 +37,12 @@ function calculatePrevMonthGrids(year, month, config) {
for (let i = prevMonthDays; i > len; i--) { for (let i = prevMonthDays; i > len; i--) {
if (onlyShowCurrentMonth) { if (onlyShowCurrentMonth) {
emptyGrids.push('') emptyGrids.push('')
} } else {
else {
const week = dateUtil.getDayOfWeek(+year, +month, i) const week = dateUtil.getDayOfWeek(+year, +month, i)
emptyGrids.push({ emptyGrids.push({
...YMInfo, ...YMInfo,
date: i, date: i,
week, week
}) })
} }
} }
@ -63,24 +61,19 @@ function calculateExtraEmptyDate(year, month, config) {
let extDate = 0 let extDate = 0
if (+month === 2) { if (+month === 2) {
extDate += 7 extDate += 7
const firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1) let firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1)
if (config.firstDayOfWeek === 'Mon') { if (config.firstDayOfWeek === 'Mon') {
if (+firstDayofMonth === 1) if (+firstDayofMonth === 1) extDate += 7
extDate += 7 } else {
} if (+firstDayofMonth === 0) extDate += 7
else {
if (+firstDayofMonth === 0)
extDate += 7
} }
} } else {
else { let firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1)
const firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1)
if (config.firstDayOfWeek === 'Mon') { if (config.firstDayOfWeek === 'Mon') {
if (firstDayofMonth !== 0 && firstDayofMonth < 6) { if (firstDayofMonth !== 0 && firstDayofMonth < 6) {
extDate += 7 extDate += 7
} }
} } else {
else {
if (firstDayofMonth <= 5) { if (firstDayofMonth <= 5) {
extDate += 7 extDate += 7
} }
@ -94,14 +87,13 @@ function calculateExtraEmptyDate(year, month, config) {
* @param {number} month 月份 * @param {number} month 月份
*/ */
function calculateNextMonthGrids(year, month, config) { function calculateNextMonthGrids(year, month, config) {
const emptyGrids = [] let emptyGrids = []
const datesCount = dateUtil.getDatesCountOfMonth(year, month) const datesCount = dateUtil.getDatesCountOfMonth(year, month)
let lastDayWeek = dateUtil.getDayOfWeek(year, month, datesCount) let lastDayWeek = dateUtil.getDayOfWeek(year, month, datesCount)
if (config.firstDayOfWeek === 'Mon') { if (config.firstDayOfWeek === 'Mon') {
if (lastDayWeek === 0) { if (lastDayWeek === 0) {
lastDayWeek = 6 lastDayWeek = 6
} } else {
else {
lastDayWeek -= 1 lastDayWeek -= 1
} }
} }
@ -115,13 +107,12 @@ function calculateNextMonthGrids(year, month, config) {
const week = dateUtil.getDayOfWeek(+year, +month, i) const week = dateUtil.getDayOfWeek(+year, +month, i)
if (onlyShowCurrentMonth) { if (onlyShowCurrentMonth) {
emptyGrids.push('') emptyGrids.push('')
} } else {
else {
emptyGrids.push({ emptyGrids.push({
id: i - 1, id: i - 1,
...YMInfo, ...YMInfo,
date: i, date: i,
week: week || 7, week: week || 7
}) })
} }
} }
@ -147,7 +138,7 @@ export function calcJumpData({ dateInfo, config, component }) {
curMonth: month, curMonth: month,
curDate: date, curDate: date,
dates: calculateCurrentMonthDates(year, month), dates: calculateCurrentMonthDates(year, month),
...emptyGrids, ...emptyGrids
} }
return calendar return calendar
} }

2
src/components/calendar/helper.js

@ -7,6 +7,6 @@ export function calcTargetYMInfo() {
prev_month: dateUtil.getPrevMonthInfo, prev_month: dateUtil.getPrevMonthInfo,
next_month: dateUtil.getNextMonthInfo, next_month: dateUtil.getNextMonthInfo,
prev_year: dateUtil.getPrevYearInfo, prev_year: dateUtil.getPrevYearInfo,
next_year: dateUtil.getNextYearInfo, next_year: dateUtil.getNextYearInfo
} }
} }

2
src/components/calendar/index.d.ts vendored

@ -1 +1 @@
export {} export {};

97
src/components/calendar/index.js

@ -1,24 +1,24 @@
import { calcJumpData } from './core'
import { calcTargetYMInfo } from './helper'
import plugins from './plugins/index' import plugins from './plugins/index'
import { calcJumpData } from './core'
import { renderCalendar } from './render' import { renderCalendar } from './render'
import { calendarGesture, dateUtil, logger } from './utils/index' import { calcTargetYMInfo } from './helper'
import { dateUtil, calendarGesture, logger } from './utils/index'
Component({ Component({
options: { options: {
styleIsolation: 'apply-shared', styleIsolation: 'apply-shared',
multipleSlots: true, // 在组件定义时的选项中启用多slot支持 multipleSlots: true // 在组件定义时的选项中启用多slot支持
}, },
properties: { properties: {
config: { config: {
type: Object, type: Object,
value: {}, value: {}
}, }
}, },
lifetimes: { lifetimes: {
attached() { attached: function() {
this.initComp() this.initComp()
}, }
}, },
methods: { methods: {
initComp() { initComp() {
@ -30,7 +30,7 @@ Component({
const calendarConfig = this.properties.config || {} const calendarConfig = this.properties.config || {}
if (calendarConfig.disableMode && !calendarConfig.disableMode.date) { if (calendarConfig.disableMode && !calendarConfig.disableMode.date) {
calendarConfig.disableMode.date = dateUtil.toTimeStr( calendarConfig.disableMode.date = dateUtil.toTimeStr(
dateUtil.todayFMD(), dateUtil.todayFMD()
) )
} }
return calendarConfig return calendarConfig
@ -42,29 +42,27 @@ Component({
const dateInfo = defaultDate.split('-') const dateInfo = defaultDate.split('-')
if (dateInfo.length < 3) { if (dateInfo.length < 3) {
return logger.warn('defaultDate配置格式应为: 2018-4-2 或 2018-04-02') return logger.warn('defaultDate配置格式应为: 2018-4-2 或 2018-04-02')
} } else {
else {
date = { date = {
year: +dateInfo[0], year: +dateInfo[0],
month: +dateInfo[1], month: +dateInfo[1],
date: +dateInfo[2], date: +dateInfo[2]
} }
} }
} }
const waitRenderData = calcJumpData({ const waitRenderData = calcJumpData({
dateInfo: date, dateInfo: date,
config, config
}) })
const timestamp = dateUtil.todayTimestamp() const timestamp = dateUtil.todayTimestamp()
if (config.autoChoosedWhenJump) { if (config.autoChoosedWhenJump) {
const target = waitRenderData.dates.filter( const target = waitRenderData.dates.filter(
item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(date), item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(date)
) )
if (target && target.length) { if (target && target.length) {
if (!waitRenderData.selectedDates) { if (!waitRenderData.selectedDates) {
waitRenderData.selectedDates = target waitRenderData.selectedDates = target
} } else {
else {
waitRenderData.selectedDates.push(target[0]) waitRenderData.selectedDates.push(target[0])
} }
} }
@ -72,7 +70,7 @@ Component({
return { return {
...waitRenderData, ...waitRenderData,
todayTimestamp: timestamp, todayTimestamp: timestamp,
weeksCh: dateUtil.getWeekHeader(config.firstDayOfWeek), weeksCh: dateUtil.getWeekHeader(config.firstDayOfWeek)
} }
}, },
setConfig(config) { setConfig(config) {
@ -82,23 +80,21 @@ Component({
config.theme = config.theme || 'default' config.theme = config.theme || 'default'
this.setData( this.setData(
{ {
config, config
}, },
() => { () => {
for (const plugin of plugins.installed) { for (let plugin of plugins.installed) {
const [, p] = plugin const [, p] = plugin
if (typeof p.install === 'function') { if (typeof p.install === 'function') {
p.install(this) p.install(this)
} }
if (typeof p.methods === 'function') { if (typeof p.methods === 'function') {
const methods = p.methods(this) const methods = p.methods(this)
for (const fnName in methods) { for (let fnName in methods) {
if (fnName.startsWith('__')) if (fnName.startsWith('__')) continue
continue
const fn = methods[fnName] const fn = methods[fnName]
if (typeof fn === 'function') { if (typeof fn === 'function') {
if (!this.calendar) if (!this.calendar) this.calendar = {}
this.calendar = {}
this.calendar[fnName] = fn this.calendar[fnName] = fn
} }
} }
@ -106,26 +102,25 @@ Component({
} }
const initData = this.initCalendar(config) const initData = this.initCalendar(config)
renderCalendar.call(this, initData, config) renderCalendar.call(this, initData, config)
}, }
) )
}, },
tapDate(e) { tapDate(e) {
const { info } = e.currentTarget.dataset const { info } = e.currentTarget.dataset
const { date, disable } = info || {} const { date, disable } = info || {}
if (disable || !date) if (disable || !date) return
return
const { calendar, config } = this.data const { calendar, config } = this.data
let calendarData = calendar let calendarData = calendar
let calendarConfig = config let calendarConfig = config
if (config.takeoverTap) { if (config.takeoverTap) {
return this.triggerEvent('takeoverTap', info) return this.triggerEvent('takeoverTap', info)
} }
for (const plugin of plugins.installed) { for (let plugin of plugins.installed) {
const [, p] = plugin const [, p] = plugin
if (typeof p.onTapDate === 'function') { if (typeof p.onTapDate === 'function') {
const { const {
calendarData: __calendarData, calendarData: __calendarData,
calendarConfig: __calendarConfig, calendarConfig: __calendarConfig
} = p.onTapDate(info, calendarData, calendarConfig) } = p.onTapDate(info, calendarData, calendarConfig)
calendarData = __calendarData calendarData = __calendarData
calendarConfig = __calendarConfig calendarConfig = __calendarConfig
@ -146,7 +141,7 @@ Component({
this.swipeLock = true this.swipeLock = true
this.setData({ this.setData({
'gesture.startX': startX, 'gesture.startX': startX,
'gesture.startY': startY, 'gesture.startY': startY
}) })
}, },
/** /**
@ -156,8 +151,7 @@ Component({
calendarTouchmove(e) { calendarTouchmove(e) {
const { gesture } = this.data const { gesture } = this.data
const { preventSwipe } = this.properties.config const { preventSwipe } = this.properties.config
if (!this.swipeLock || preventSwipe) if (!this.swipeLock || preventSwipe) return
return
if (calendarGesture.isLeft(gesture, e.touches[0])) { if (calendarGesture.isLeft(gesture, e.touches[0])) {
this.handleSwipe('left') this.handleSwipe('left')
this.swipeLock = false this.swipeLock = false
@ -170,7 +164,7 @@ Component({
calendarTouchend(e) { calendarTouchend(e) {
this.setData({ this.setData({
'calendar.leftSwipe': 0, 'calendar.leftSwipe': 0,
'calendar.rightSwipe': 0, 'calendar.rightSwipe': 0
}) })
}, },
handleSwipe(direction) { handleSwipe(direction) {
@ -179,15 +173,15 @@ Component({
swipeKey = 'calendar.rightSwipe' swipeKey = 'calendar.rightSwipe'
} }
this.setData({ this.setData({
[swipeKey]: 1, [swipeKey]: 1
}) })
const { calendar } = this.data const { calendar } = this.data
const calendarData = calendar let calendarData = calendar
const { curYear, curMonth } = calendarData const { curYear, curMonth } = calendarData
const getMonthInfo = calcTargetYMInfo()[direction] const getMonthInfo = calcTargetYMInfo()[direction]
const target = getMonthInfo({ const target = getMonthInfo({
year: +curYear, year: +curYear,
month: +curMonth, month: +curMonth
}) })
target.direction = direction target.direction = direction
this.renderCalendar(target) this.renderCalendar(target)
@ -199,7 +193,7 @@ Component({
const getMonthInfo = calcTargetYMInfo()[type] const getMonthInfo = calcTargetYMInfo()[type]
const target = getMonthInfo({ const target = getMonthInfo({
year: +curYear, year: +curYear,
month: +curMonth, month: +curMonth
}) })
target.direction = type target.direction = type
this.renderCalendar(target) this.renderCalendar(target)
@ -207,7 +201,7 @@ Component({
renderCalendar(target) { renderCalendar(target) {
let { calendar: calendarData, config } = this.data let { calendar: calendarData, config } = this.data
const { curYear, curMonth } = calendarData || {} const { curYear, curMonth } = calendarData || {}
for (const plugin of plugins.installed) { for (let plugin of plugins.installed) {
const [, p] = plugin const [, p] = plugin
if (typeof p.onSwitchCalendar === 'function') { if (typeof p.onSwitchCalendar === 'function') {
calendarData = p.onSwitchCalendar(target, calendarData, this) calendarData = p.onSwitchCalendar(target, calendarData, this)
@ -221,47 +215,44 @@ Component({
this.triggerEvent(triggerEventName, { this.triggerEvent(triggerEventName, {
current: { current: {
year: +curYear, year: +curYear,
month: +curMonth, month: +curMonth
}, },
next: target, next: target
}) })
this.triggerEvent('onSwipe', { this.triggerEvent('onSwipe', {
current: { current: {
year: +curYear, year: +curYear,
month: +curMonth, month: +curMonth
}, },
next: target, next: target,
type: triggerEventName, type: triggerEventName
}) })
}) })
}, },
doubleClickJumpToToday() { doubleClickJumpToToday() {
const { multi, weekMode } = this.calendar.getCalendarConfig() || {} const { multi, weekMode } = this.calendar.getCalendarConfig() || {}
if (multi || weekMode) if (multi || weekMode) return
return
if (this.count === undefined) { if (this.count === undefined) {
this.count = 1 this.count = 1
} } else {
else {
this.count += 1 this.count += 1
} }
if (this.lastClick) { if (this.lastClick) {
const difference = new Date().getTime() - this.lastClick const difference = new Date().getTime() - this.lastClick
if ( if (
difference < 500 difference < 500 &&
&& this.count >= 2 this.count >= 2 &&
&& typeof this.calendar.jump === 'function' typeof this.calendar.jump === 'function'
) { ) {
const today = dateUtil.todayFMD() const today = dateUtil.todayFMD()
this.calendar.jump(today) this.calendar.jump(today)
} }
this.count = undefined this.count = undefined
this.lastClick = undefined this.lastClick = undefined
} } else {
else {
this.lastClick = new Date().getTime() this.lastClick = new Date().getTime()
} }
this.triggerEvent('jumpToToday') this.triggerEvent('jumpToToday')
}, }
}, }
}) })

2
src/components/calendar/index.json

@ -1,3 +1,3 @@
{ {
"component": true "component": true
} }

122
src/components/calendar/plugins/holidays/holidays-map.js

@ -14,38 +14,38 @@ export const festival = {
1: { 1: {
type: 'festival', type: 'festival',
name: '春节', name: '春节',
label: '春节', label: '春节'
}, },
8: { 8: {
type: 'festival', type: 'festival',
name: '腊八节', name: '腊八节',
label: '腊八', label: '腊八'
}, },
15: { 15: {
type: 'festival', type: 'festival',
name: '元宵节', name: '元宵节',
label: '元宵', label: '元宵'
}, }
}, },
7: { 7: {
7: { 7: {
type: 'festival', type: 'festival',
name: '七夕节', name: '七夕节',
label: '七夕', label: '七夕'
}, },
15: { 15: {
type: 'festival', type: 'festival',
name: '中元节', name: '中元节',
label: '中元节', label: '中元节'
}, }
}, },
9: { 9: {
9: { 9: {
type: 'festival', type: 'festival',
name: '重阳节', name: '重阳节',
label: '重阳节', label: '重阳节'
}, }
}, }
}, },
// 阳历固定日期节日 // 阳历固定日期节日
solar: { solar: {
@ -53,160 +53,160 @@ export const festival = {
14: { 14: {
type: 'festival', type: 'festival',
name: '情人节', name: '情人节',
label: '情人节', label: '情人节'
}, }
}, },
3: { 3: {
12: { 12: {
type: 'festival', type: 'festival',
name: '植树节', name: '植树节',
label: '植树节', label: '植树节'
}, }
}, },
4: { 4: {
1: { 1: {
type: 'festival', type: 'festival',
name: '愚人节', name: '愚人节',
label: '愚人节', label: '愚人节'
}, },
5: { 5: {
type: 'festival', type: 'festival',
name: '清明节', name: '清明节',
label: '清明节', label: '清明节'
}, }
}, },
5: { 5: {
1: { 1: {
type: 'festival', type: 'festival',
name: '劳动节', name: '劳动节',
label: '劳动节', label: '劳动节'
}, }
}, },
6: { 6: {
1: { 1: {
type: 'festival', type: 'festival',
name: '儿童节', name: '儿童节',
label: '儿童节', label: '儿童节'
}, }
}, },
7: { 7: {
1: { 1: {
type: 'festival', type: 'festival',
name: '建党节', name: '建党节',
label: '建党节', label: '建党节'
}, }
}, },
8: { 8: {
1: { 1: {
type: 'festival', type: 'festival',
name: '建军节', name: '建军节',
label: '建军节', label: '建军节'
}, }
}, },
9: { 9: {
10: { 10: {
type: 'festival', type: 'festival',
name: '教师节', name: '教师节',
label: '教师节', label: '教师节'
}, }
}, },
10: { 10: {
1: { 1: {
type: 'festival', type: 'festival',
name: '国庆节', name: '国庆节',
label: '国庆节', label: '国庆节'
}, }
}, },
12: { 12: {
25: { 25: {
type: 'festival', type: 'festival',
name: '圣诞节', name: '圣诞节',
label: '圣诞节', label: '圣诞节'
}, }
}, }
}, }
} }
export const holidays = { export const holidays = {
2020: { 2020: {
1: { 1: {
'1': { 1: {
type: 'holiday', type: 'holiday',
name: '元旦', name: '元旦',
label: '休', label: '休'
}, },
'19': { 19: {
type: 'work', type: 'work',
name: '调班', name: '调班',
label: '班', label: '班'
}, },
'24-30': { '24-30': {
type: 'holiday', type: 'holiday',
name: '春节', name: '春节',
label: '休', label: '休'
}, }
}, },
2: { 2: {
1: { 1: {
type: 'work', type: 'work',
name: '调班', name: '调班',
label: '班', label: '班'
}, }
}, },
4: { 4: {
'4-6': { '4-6': {
type: 'holiday', type: 'holiday',
name: '清明节', name: '清明节',
label: '休', label: '休'
}, },
'26': { 26: {
type: 'work', type: 'work',
name: '调班', name: '调班',
label: '班', label: '班'
}, }
}, },
5: { 5: {
'1-5': { '1-5': {
type: 'holiday', type: 'holiday',
name: '劳动节', name: '劳动节',
label: '休', label: '休'
}, },
'9': { 9: {
type: 'work', type: 'work',
name: '调班', name: '调班',
label: '班', label: '班'
}, }
}, },
6: { 6: {
'25-27': { '25-27': {
type: 'holiday', type: 'holiday',
name: '端午节', name: '端午节',
label: '休', label: '休'
}, },
'28': { 28: {
type: 'work', type: 'work',
name: '调班', name: '调班',
label: '班', label: '班'
}, }
}, },
9: { 9: {
27: { 27: {
type: 'work', type: 'work',
name: '调班', name: '调班',
label: '班', label: '班'
}, }
}, },
10: { 10: {
'1-8': { '1-8': {
type: 'holiday', type: 'holiday',
name: '国庆节/中秋节', name: '国庆节/中秋节',
label: '休', label: '休'
}, },
'10': { 10: {
type: 'work', type: 'work',
name: '调班', name: '调班',
label: '班', label: '班'
}, }
}, }
}, }
} }

2
src/components/calendar/plugins/holidays/index.d.ts vendored

@ -1 +1 @@
export {} export {};

86
src/components/calendar/plugins/holidays/index.js

@ -6,8 +6,8 @@
* @Last Modified time: 2020-10-16 17:34:13 * @Last Modified time: 2020-10-16 17:34:13
*/ */
import { holidays, festival } from './holidays-map'
import { dateUtil, getCalendarData, logger } from '../../utils/index' import { dateUtil, getCalendarData, logger } from '../../utils/index'
import { festival, holidays } from './holidays-map'
/** /**
* 当前是否在休假期内 * 当前是否在休假期内
@ -20,21 +20,21 @@ function inHolidays({ year, month }, { start, end, current }) {
const startTimestamp = getTimeStamp({ const startTimestamp = getTimeStamp({
year, year,
month, month,
date: start, date: start
}) })
const endTimestamp = getTimeStamp({ const endTimestamp = getTimeStamp({
year, year,
month, month,
date: end, date: end
}) })
const currentDateTimestamp = getTimeStamp({ const currentDateTimestamp = getTimeStamp({
year, year,
month, month,
date: current, date: current
}) })
if ( if (
currentDateTimestamp >= startTimestamp currentDateTimestamp >= startTimestamp &&
&& currentDateTimestamp <= endTimestamp currentDateTimestamp <= endTimestamp
) { ) {
return true return true
} }
@ -49,15 +49,13 @@ function addSpecialFestival(date, component) {
const info = { const info = {
type: 'festival', type: 'festival',
name: '除夕', name: '除夕',
label: '除夕', label: '除夕'
} }
if (lMonth === 12) { if (lMonth === 12) {
if (!festival.lunar['12']) if (!festival.lunar['12']) festival.lunar['12'] = {}
festival.lunar['12'] = {}
if (convertlLunar2Solar(`${lYear}-12-30`) === -1) { if (convertlLunar2Solar(`${lYear}-12-30`) === -1) {
festival.lunar['12']['29'] = info festival.lunar['12']['29'] = info
} } else {
else {
festival.lunar['12']['30'] = info festival.lunar['12']['30'] = info
} }
} }
@ -65,8 +63,8 @@ function addSpecialFestival(date, component) {
/** /**
* 是否匹配到节日 * 是否匹配到节日
* @param {object} [dateInfo] * @param {object} [dateInfo={}]
* @param {object} [component] * @param {object} [component={}]
* @returns {object|boolean} 匹配到的节日数据或者false * @returns {object|boolean} 匹配到的节日数据或者false
*/ */
function hasFestivalDate(dateInfo = {}, component = {}) { function hasFestivalDate(dateInfo = {}, component = {}) {
@ -80,22 +78,19 @@ function hasFestivalDate(dateInfo = {}, component = {}) {
if (!festivalDate) { if (!festivalDate) {
const festivalOfMonth = festival.lunar[lMonth] || {} const festivalOfMonth = festival.lunar[lMonth] || {}
const festivalDateKey = Object.keys(festivalOfMonth).find(item => const festivalDateKey = Object.keys(festivalOfMonth).find(item =>
item.match(new RegExp(`\\b${lDay}\\b`)), item.match(new RegExp(`\\b${lDay}\\b`))
) )
if (!festivalDateKey) { if (!festivalDateKey) {
festivalDate = false festivalDate = false
} } else {
else {
const festivalInfo = festival.lunar[lMonth][festivalDateKey] const festivalInfo = festival.lunar[lMonth][festivalDateKey]
if (!festivalInfo) { if (!festivalInfo) {
festivalDate = false festivalDate = false
} } else {
else {
const { condition } = festivalInfo const { condition } = festivalInfo
if (typeof condition === 'function') { if (typeof condition === 'function') {
festivalDate = condition(lunarDateInfo) festivalDate = condition(lunarDateInfo)
} } else {
else {
festivalDate = false festivalDate = false
} }
} }
@ -111,24 +106,23 @@ export default () => {
beforeRender(calendarData = {}, calendarConfig = {}, component) { beforeRender(calendarData = {}, calendarConfig = {}, component) {
let { dates = [] } = calendarData let { dates = [] } = calendarData
if (calendarConfig.showHolidays || calendarConfig.showFestival) { if (calendarConfig.showHolidays || calendarConfig.showFestival) {
dates = dates.map((d) => { dates = dates.map(d => {
let item = { ...d } let item = { ...d }
const { year, month, date } = item const { year, month, date } = item
const holidaysOfMonth const holidaysOfMonth =
= (holidays[year] && holidays[year][month]) || {} (holidays[year] && holidays[year][month]) || {}
const holidayDate = holidaysOfMonth[date] const holidayDate = holidaysOfMonth[date]
if (holidayDate) { if (holidayDate) {
item = { item = {
...item, ...item,
...holidayDate, ...holidayDate
} }
} } else {
else {
const holidayKeys = Object.keys(holidaysOfMonth).filter(item => const holidayKeys = Object.keys(holidaysOfMonth).filter(item =>
item.includes('-'), item.includes('-')
) )
let target = '' let target = ''
for (const v of holidayKeys) { for (let v of holidayKeys) {
const [start, end] = v.split('-') const [start, end] = v.split('-')
if (+d.date >= +start && +d.date <= +end) { if (+d.date >= +start && +d.date <= +end) {
target = v target = v
@ -139,29 +133,28 @@ export default () => {
const isInHolidays = inHolidays( const isInHolidays = inHolidays(
{ {
year, year,
month, month
}, },
{ {
start, start,
end, end,
current: date, current: date
}, }
) )
if (isInHolidays) { if (isInHolidays) {
item = { item = {
...item, ...item,
...holidaysOfMonth[target], ...holidaysOfMonth[target]
} }
} } else if (calendarConfig.showFestival) {
else if (calendarConfig.showFestival) { const { convertSolarLunar, convertlLunar2Solar } =
const { convertSolarLunar, convertlLunar2Solar } component.calendar || {}
= component.calendar || {}
if ( if (
typeof convertSolarLunar !== 'function' typeof convertSolarLunar !== 'function' ||
|| typeof convertlLunar2Solar !== 'function' typeof convertlLunar2Solar !== 'function'
) { ) {
return logger.warn( return logger.warn(
'农历节日显示需要引入农历插件(/component/v2/plugins/solarLunar)', '农历节日显示需要引入农历插件(/component/v2/plugins/solarLunar)'
) )
} }
addSpecialFestival(item, component) addSpecialFestival(item, component)
@ -169,7 +162,7 @@ export default () => {
if (festivalDate) { if (festivalDate) {
item = { item = {
...item, ...item,
...festivalDate, ...festivalDate
} }
} }
} }
@ -180,9 +173,9 @@ export default () => {
return { return {
calendarData: { calendarData: {
...calendarData, ...calendarData,
dates, dates: dates
}, },
calendarConfig, calendarConfig
} }
}, },
methods(component) { methods(component) {
@ -193,17 +186,16 @@ export default () => {
return this.methods(component).getHolidaysOfYear(curYear) return this.methods(component).getHolidaysOfYear(curYear)
}, },
getHolidaysOfYear(year) { getHolidaysOfYear(year) {
if (!year) if (!year) return logger.warn('getHolidaysOfCurrentYear() 入参错误')
return logger.warn('getHolidaysOfCurrentYear() 入参错误')
if (!holidays[year]) { if (!holidays[year]) {
logger.warn('未匹配到当前年份节假日信息,请自行补充') logger.warn('未匹配到当前年份节假日信息,请自行补充')
return { return {
err: 'not match', err: 'not match'
} }
} }
return holidays[year] return holidays[year]
}, }
} }
}, }
} }
} }

2
src/components/calendar/plugins/index.d.ts vendored

@ -1 +1 @@
export {} export {};

11
src/components/calendar/plugins/index.js

@ -3,17 +3,16 @@ import preset from './preset/index'
export default { export default {
installed: [...preset], installed: [...preset],
use(plugin) { use(plugin) {
if (typeof plugin !== 'function') if (typeof plugin !== 'function') return
return
const info = plugin() || {} const info = plugin() || {}
const { name } = info const { name } = info
if ( if (
name name &&
&& name !== 'methods' name !== 'methods' &&
&& !this.installed.some(p => p[0] === name) !this.installed.some(p => p[0] === name)
) { ) {
this.installed.unshift([name, info]) this.installed.unshift([name, info])
} }
return this return this
}, }
} }

116
src/components/calendar/plugins/preset/base.js

@ -4,15 +4,15 @@
* @Date: 2020-10-08 21:22:09* * @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu * @Last Modified by: drfu
* @Last Modified time: 2020-10-11 13:28:52 * @Last Modified time: 2020-10-11 13:28:52
*/ * */
import { calcJumpData } from '../../core' import { calcJumpData } from '../../core'
import { renderCalendar } from '../../render' import { renderCalendar } from '../../render'
import { import {
dateUtil, dateUtil,
getCalendarConfig,
getCalendarData, getCalendarData,
setCalendarData, setCalendarData,
getCalendarConfig
} from '../../utils/index' } from '../../utils/index'
export default () => { export default () => {
@ -21,12 +21,12 @@ export default () => {
beforeRender(calendarData = {}, calendarConfig) { beforeRender(calendarData = {}, calendarConfig) {
const calendar = calendarData const calendar = calendarData
const { selectedDates = [], dates } = calendar const { selectedDates = [], dates } = calendar
const _dates = [...dates] let _dates = [...dates]
if (selectedDates.length) { if (selectedDates.length) {
const selectedDatesStr = selectedDates.map(date => const selectedDatesStr = selectedDates.map(date =>
dateUtil.toTimeStr(date), dateUtil.toTimeStr(date)
) )
_dates.forEach((date) => { _dates.forEach(date => {
const dateStr = dateUtil.toTimeStr(date) const dateStr = dateUtil.toTimeStr(date)
if (selectedDatesStr.includes(dateStr)) { if (selectedDatesStr.includes(dateStr)) {
date.choosed = true date.choosed = true
@ -36,21 +36,21 @@ export default () => {
return { return {
calendarData: { calendarData: {
...calendarData, ...calendarData,
dates: _dates, dates: _dates
}, },
calendarConfig, calendarConfig
} }
}, },
onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) { onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) {
const calendar = { const calendar = {
...calendarData, ...calendarData
} }
const dateIndex = dateUtil.findDateIndexInArray( const dateIndex = dateUtil.findDateIndexInArray(
tapedDate, tapedDate,
calendarData.dates, calendarData.dates
) )
const { multi, inverse } = calendarConfig const { multi, inverse } = calendarConfig
const dates = [...calendar.dates] let dates = [...calendar.dates]
const { selectedDates = [] } = calendar const { selectedDates = [] } = calendar
if (!multi) { if (!multi) {
let preSelectedDate = {} let preSelectedDate = {}
@ -61,7 +61,7 @@ export default () => {
if (!inverse && timeStr(preSelectedDate) === timeStr(tapedDate)) { if (!inverse && timeStr(preSelectedDate) === timeStr(tapedDate)) {
return calendar return calendar
} }
const _tapedDate = { ...tapedDate, choosed: !tapedDate.choosed } let _tapedDate = { ...tapedDate, choosed: !tapedDate.choosed }
dates[dateIndex] = _tapedDate dates[dateIndex] = _tapedDate
if (preSelectedDate.date) { if (preSelectedDate.date) {
@ -73,35 +73,32 @@ export default () => {
} }
if (dates[dateIndex].choosed) { if (dates[dateIndex].choosed) {
calendar.selectedDates = [dates[dateIndex]] calendar.selectedDates = [dates[dateIndex]]
} } else {
else {
calendar.selectedDates = [] calendar.selectedDates = []
} }
} } else {
else {
dates[dateIndex] = { dates[dateIndex] = {
...dates[dateIndex], ...dates[dateIndex],
choosed: !dates[dateIndex].choosed, choosed: !dates[dateIndex].choosed
} }
if (!calendar.selectedDates) { if (!calendar.selectedDates) {
calendar.selectedDates = [] calendar.selectedDates = []
} }
if (dates[dateIndex].choosed) { if (dates[dateIndex].choosed) {
calendar.selectedDates.push(dates[dateIndex]) calendar.selectedDates.push(dates[dateIndex])
} } else {
else {
calendar.selectedDates = calendar.selectedDates.filter( calendar.selectedDates = calendar.selectedDates.filter(
date => date =>
dateUtil.toTimeStr(date) !== dateUtil.toTimeStr(dates[dateIndex]), dateUtil.toTimeStr(date) !== dateUtil.toTimeStr(dates[dateIndex])
) )
} }
} }
return { return {
calendarData: { calendarData: {
...calendar, ...calendar,
dates, dates
}, },
calendarConfig, calendarConfig
} }
}, },
onSwitchCalendar(date, calendarData = {}, component) { onSwitchCalendar(date, calendarData = {}, component) {
@ -111,21 +108,21 @@ export default () => {
} }
const updatedRenderData = calcJumpData({ const updatedRenderData = calcJumpData({
dateInfo: date, dateInfo: date,
config: calendarConfig, config: calendarConfig
}) })
return { return {
...calendarData, ...calendarData,
...updatedRenderData, ...updatedRenderData
} }
}, },
methods(component) { methods(component) {
return { return {
jump: (dateInfo) => { jump: dateInfo => {
if (Object.prototype.toString.call(dateInfo) !== '[object Object]') if (Object.prototype.toString.call(dateInfo) !== '[object Object]')
return return
const updatedRenderData = calcJumpData({ const updatedRenderData = calcJumpData({
dateInfo, dateInfo,
component, component
}) })
const existCalendarData = getCalendarData('calendar', component) const existCalendarData = getCalendarData('calendar', component)
const config = getCalendarConfig(component) const config = getCalendarConfig(component)
@ -133,14 +130,13 @@ export default () => {
const target = updatedRenderData.dates[dateInfo.date - 1] const target = updatedRenderData.dates[dateInfo.date - 1]
if (!updatedRenderData.selectedDates) { if (!updatedRenderData.selectedDates) {
updatedRenderData.selectedDates = [target] updatedRenderData.selectedDates = [target]
} } else {
else {
updatedRenderData.selectedDates.push(target) updatedRenderData.selectedDates.push(target)
} }
} }
return renderCalendar.call(component, { return renderCalendar.call(component, {
...existCalendarData, ...existCalendarData,
...updatedRenderData, ...updatedRenderData
}) })
}, },
getCalendarConfig() { getCalendarConfig() {
@ -152,7 +148,7 @@ export default () => {
reject('异常:未找到组件配置信息') reject('异常:未找到组件配置信息')
return return
} }
const conf = { ...component.config, ...config } let conf = { ...component.config, ...config }
component.config = conf component.config = conf
setCalendarData({ config: conf }, component) setCalendarData({ config: conf }, component)
.then(resolve) .then(resolve)
@ -168,69 +164,66 @@ export default () => {
if (config.chooseAreaMode) { if (config.chooseAreaMode) {
chooseAreaData = { chooseAreaData = {
chooseAreaTimestamp: [], chooseAreaTimestamp: [],
tempChooseAreaTimestamp: [], tempChooseAreaTimestamp: []
} }
} }
if (!cancelDates.length) { if (!cancelDates.length) {
dates.forEach((item) => { dates.forEach(item => {
item.choosed = false item.choosed = false
}) })
updatedRenderData = { updatedRenderData = {
dates, dates,
selectedDates: [], selectedDates: []
} }
} } else {
else {
const cancelDatesStr = cancelDates.map(date => const cancelDatesStr = cancelDates.map(date =>
dateUtil.toTimeStr(date), dateUtil.toTimeStr(date)
) )
const filterSelectedDates = selectedDates.filter( const filterSelectedDates = selectedDates.filter(
date => !cancelDatesStr.includes(dateUtil.toTimeStr(date)), date => !cancelDatesStr.includes(dateUtil.toTimeStr(date))
) )
dates.forEach((date) => { dates.forEach(date => {
if (cancelDatesStr.includes(dateUtil.toTimeStr(date))) { if (cancelDatesStr.includes(dateUtil.toTimeStr(date))) {
date.choosed = false date.choosed = false
} }
}) })
updatedRenderData = { updatedRenderData = {
dates, dates,
selectedDates: filterSelectedDates, selectedDates: filterSelectedDates
} }
} }
return renderCalendar.call(component, { return renderCalendar.call(component, {
...existCalendarData, ...existCalendarData,
...updatedRenderData, ...updatedRenderData,
...chooseAreaData, ...chooseAreaData
}) })
}, },
setSelectedDates: (targetDates) => { setSelectedDates: targetDates => {
const existCalendarData = getCalendarData('calendar', component) const existCalendarData = getCalendarData('calendar', component)
const { dates, selectedDates = [] } = existCalendarData || {} let { dates, selectedDates = [] } = existCalendarData || {}
let __selectedDates = [] let __selectedDates = []
let __dates = dates let __dates = dates
if (!targetDates) { if (!targetDates) {
__dates = dates.map((item) => { __dates = dates.map(item => {
const date = { ...item } const date = { ...item }
date.choosed = true date.choosed = true
if (existCalendarData.showLabelAlways && date.showTodoLabel) { if (existCalendarData.showLabelAlways && date.showTodoLabel) {
date.showTodoLabel = true date.showTodoLabel = true
} } else {
else {
date.showTodoLabel = false date.showTodoLabel = false
} }
return date return date
}) })
__selectedDates = dates __selectedDates = dates
} } else if (targetDates && targetDates.length) {
else if (targetDates && targetDates.length) {
const allSelected = dateUtil.uniqueArrayByDate( const allSelected = dateUtil.uniqueArrayByDate(
selectedDates.concat(targetDates), selectedDates.concat(targetDates)
) )
const allSelectedDateStr = allSelected.map(d => const allSelectedDateStr = allSelected.map(d =>
dateUtil.toTimeStr(d), dateUtil.toTimeStr(d)
) )
__dates = dates.map((item) => { __dates = dates.map(item => {
const date = { ...item } const date = { ...item }
if (allSelectedDateStr.includes(dateUtil.toTimeStr(date))) { if (allSelectedDateStr.includes(dateUtil.toTimeStr(date))) {
date.choosed = true date.choosed = true
@ -238,8 +231,7 @@ export default () => {
} }
if (existCalendarData.showLabelAlways && date.showTodoLabel) { if (existCalendarData.showLabelAlways && date.showTodoLabel) {
date.showTodoLabel = true date.showTodoLabel = true
} } else {
else {
date.showTodoLabel = false date.showTodoLabel = false
} }
return date return date
@ -248,40 +240,38 @@ export default () => {
return renderCalendar.call(component, { return renderCalendar.call(component, {
...existCalendarData, ...existCalendarData,
dates: __dates, dates: __dates,
selectedDates: __selectedDates, selectedDates: __selectedDates
}) })
}, },
setDateStyle: (toSetDates) => { setDateStyle: toSetDates => {
if (!Array.isArray(toSetDates)) if (!Array.isArray(toSetDates)) return Promise.reject()
return Promise.reject()
const existCalendarData = getCalendarData('calendar', component) const existCalendarData = getCalendarData('calendar', component)
const { dates = [], specialStyleDates } = existCalendarData || {} const { dates = [], specialStyleDates } = existCalendarData || {}
if (Array.isArray(specialStyleDates)) { if (Array.isArray(specialStyleDates)) {
toSetDates = dateUtil.uniqueArrayByDate([ toSetDates = dateUtil.uniqueArrayByDate([
...specialStyleDates, ...specialStyleDates,
...toSetDates, ...toSetDates
]) ])
} }
const toSetDatesStr = toSetDates.map(item => dateUtil.toTimeStr(item)) const toSetDatesStr = toSetDates.map(item => dateUtil.toTimeStr(item))
const _dates = dates.map((item) => { const _dates = dates.map(item => {
const idx = toSetDatesStr.indexOf(dateUtil.toTimeStr(item)) const idx = toSetDatesStr.indexOf(dateUtil.toTimeStr(item))
if (idx > -1) { if (idx > -1) {
return { return {
...item, ...item,
class: toSetDates[idx].class, class: toSetDates[idx].class
} }
} } else {
else {
return item return item
} }
}) })
return renderCalendar.call(component, { return renderCalendar.call(component, {
...existCalendarData, ...existCalendarData,
dates: _dates, dates: _dates,
specialStyleDates: toSetDates, specialStyleDates: toSetDates
}) })
}, }
} }
}, }
} }
} }

30
src/components/calendar/plugins/preset/get-calendar-data.js

@ -4,14 +4,14 @@
* @Date: 2020-10-08 21:22:09* * @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu * @Last Modified by: drfu
* @Last Modified time: 2020-10-11 13:42:37 * @Last Modified time: 2020-10-11 13:42:37
*/ * */
import { getCalendarConfig, getCalendarData, logger } from '../../utils/index' import { getCalendarData, logger, getCalendarConfig } from '../../utils/index'
function wrapDateWithLunar(dates = [], convertFn) { function wrapDateWithLunar(dates = [], convertFn) {
const datesWithLunar = JSON.parse(JSON.stringify(dates)).map(date => ({ const datesWithLunar = JSON.parse(JSON.stringify(dates)).map(date => ({
...date, ...date,
lunar: convertFn(date), lunar: convertFn(date)
})) }))
return datesWithLunar return datesWithLunar
} }
@ -25,23 +25,21 @@ export default () => {
const { curYear, curMonth } = getCalendarData('calendar', component) const { curYear, curMonth } = getCalendarData('calendar', component)
return { return {
year: curYear, year: curYear,
month: curMonth, month: curMonth
} }
}, },
getSelectedDates: (options = {}) => { getSelectedDates: (options = {}) => {
const dates const dates =
= getCalendarData('calendar.selectedDates', component) || [] getCalendarData('calendar.selectedDates', component) || []
const config = getCalendarConfig(component) || {} const config = getCalendarConfig(component) || {}
if (options.lunar && !config.showLunar) { if (options.lunar && !config.showLunar) {
const injectedFns = component.calendar || {} const injectedFns = component.calendar || {}
if (typeof injectedFns.convertSolarLunar === 'function') { if (typeof injectedFns.convertSolarLunar === 'function') {
return wrapDateWithLunar(dates, injectedFns.convertSolarLunar) return wrapDateWithLunar(dates, injectedFns.convertSolarLunar)
} } else {
else {
logger.warn('获取农历信息需引入农历插件') logger.warn('获取农历信息需引入农历插件')
} }
} } else {
else {
return dates return dates
} }
}, },
@ -52,22 +50,20 @@ export default () => {
const injectedFns = component.calendar || {} const injectedFns = component.calendar || {}
if (typeof injectedFns.convertSolarLunar === 'function') { if (typeof injectedFns.convertSolarLunar === 'function') {
return wrapDateWithLunar(dates, injectedFns.convertSolarLunar) return wrapDateWithLunar(dates, injectedFns.convertSolarLunar)
} } else {
else {
logger.warn('获取农历信息需引入农历插件') logger.warn('获取农历信息需引入农历插件')
} }
} } else {
else {
return dates return dates
} }
}, },
getCalendarAllData: () => { getCalendarAllData: () => {
return { return {
data: getCalendarData('calendar', component) || {}, data: getCalendarData('calendar', component) || {},
config: getCalendarConfig(component) || {}, config: getCalendarConfig(component) || {}
} }
}, }
} }
}, }
} }
} }

2
src/components/calendar/plugins/preset/index.d.ts vendored

@ -1 +1 @@
export {} export {};

2
src/components/calendar/plugins/preset/index.js

@ -3,7 +3,7 @@ import getCalendarData from './get-calendar-data'
const preset = [ const preset = [
['base', base()], ['base', base()],
['get-calendar-data', getCalendarData()], ['get-calendar-data', getCalendarData()]
] ]
export default preset export default preset

2
src/components/calendar/plugins/selectable.d.ts vendored

@ -1 +1 @@
export {} export {};

104
src/components/calendar/plugins/selectable.js

@ -4,10 +4,10 @@
* @Date: 2020-10-08 21:22:09* * @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu * @Last Modified by: drfu
* @Last Modified time: 2020-10-08 21:25:00 * @Last Modified time: 2020-10-08 21:25:00
*/ * */
import { getCalendarData, dateUtil, logger } from '../utils/index'
import { renderCalendar } from '../render' import { renderCalendar } from '../render'
import { dateUtil, getCalendarData, logger } from '../utils/index'
function convertEnableAreaToTimestamp(timearea = []) { function convertEnableAreaToTimestamp(timearea = []) {
const start = timearea[0].split('-') const start = timearea[0].split('-')
@ -24,7 +24,7 @@ function convertEnableAreaToTimestamp(timearea = []) {
start, start,
end, end,
startTimestamp, startTimestamp,
endTimestamp, endTimestamp
} }
} }
@ -33,46 +33,39 @@ function isValiditeOfDateArea(dateArea) {
start, start,
end, end,
startTimestamp, startTimestamp,
endTimestamp, endTimestamp
} = convertEnableAreaToTimestamp(dateArea) } = convertEnableAreaToTimestamp(dateArea)
if (!start || !end) if (!start || !end) return
return
const datesCountOfStart = dateUtil.getDatesCountOfMonth(start[0], start[1]) const datesCountOfStart = dateUtil.getDatesCountOfMonth(start[0], start[1])
const datesCountOfEnd = dateUtil.getDatesCountOfMonth(end[0], end[1]) const datesCountOfEnd = dateUtil.getDatesCountOfMonth(end[0], end[1])
if (start[2] > datesCountOfStart || start[2] < 1) { if (start[2] > datesCountOfStart || start[2] < 1) {
logger.warn('enableArea() 开始日期错误,指定日期不在指定月份天数范围内') logger.warn('enableArea() 开始日期错误,指定日期不在指定月份天数范围内')
return false return false
} } else if (start[1] > 12 || start[1] < 1) {
else if (start[1] > 12 || start[1] < 1) {
logger.warn('enableArea() 开始日期错误,月份超出1-12月份') logger.warn('enableArea() 开始日期错误,月份超出1-12月份')
return false return false
} } else if (end[2] > datesCountOfEnd || end[2] < 1) {
else if (end[2] > datesCountOfEnd || end[2] < 1) {
logger.warn('enableArea() 截止日期错误,指定日期不在指定月份天数范围内') logger.warn('enableArea() 截止日期错误,指定日期不在指定月份天数范围内')
return false return false
} } else if (end[1] > 12 || end[1] < 1) {
else if (end[1] > 12 || end[1] < 1) {
logger.warn('enableArea() 截止日期错误,月份超出1-12月份') logger.warn('enableArea() 截止日期错误,月份超出1-12月份')
return false return false
} } else if (startTimestamp > endTimestamp) {
else if (startTimestamp > endTimestamp) {
logger.warn('enableArea()参数最小日期大于了最大日期') logger.warn('enableArea()参数最小日期大于了最大日期')
return false return false
} } else {
else {
return true return true
} }
} }
function handleDisableMode(calendarConfig) { function handleDisableMode(calendarConfig) {
const { disableMode } = calendarConfig const { disableMode } = calendarConfig
if (!disableMode) if (!disableMode) return {}
return {} const disableBound =
const disableBound dateUtil.getTimeStamp(disableMode.date) || dateUtil.todayTimestamp()
= dateUtil.getTimeStamp(disableMode.date) || dateUtil.todayTimestamp()
return { return {
disableBound, disableBound,
disableType: disableMode.type, disableType: disableMode.type
} }
} }
@ -80,12 +73,11 @@ function disabledByConfig(dateInfo, currentDate, calendarConfig) {
const date = { ...dateInfo } const date = { ...dateInfo }
const { disableType, disableBound } = handleDisableMode(calendarConfig) const { disableType, disableBound } = handleDisableMode(calendarConfig)
if ( if (
(disableType === 'before' && disableBound && currentDate < disableBound) (disableType === 'before' && disableBound && currentDate < disableBound) ||
|| (disableType === 'after' && disableBound && currentDate > disableBound) (disableType === 'after' && disableBound && currentDate > disableBound)
) { ) {
date.disable = true date.disable = true
} } else {
else {
date.disable = false date.disable = false
} }
return date return date
@ -100,38 +92,34 @@ export default () => {
enableArea, enableArea,
enableDates, enableDates,
disableDates, disableDates,
renderCausedBy, renderCausedBy
} = calendarData } = calendarData
const _dates = [...dates].map((date) => { const _dates = [...dates].map(date => {
const item = { ...date } let item = { ...date }
const timeStr = dateUtil.toTimeStr(date) const timeStr = dateUtil.toTimeStr(date)
const timestamp = +dateUtil.getTimeStamp(item) const timestamp = +dateUtil.getTimeStamp(item)
if (renderCausedBy === 'enableDates') { if (renderCausedBy === 'enableDates') {
if (enableDates && enableDates.length) { if (enableDates && enableDates.length) {
if (enableDates.includes(timeStr)) { if (enableDates.includes(timeStr)) {
item.disable = false item.disable = false
} } else {
else {
item.disable = true item.disable = true
} }
return item return item
} }
} } else if (renderCausedBy === 'enableArea') {
else if (renderCausedBy === 'enableArea') {
if (enableArea && enableArea.length) { if (enableArea && enableArea.length) {
const [startTimestamp, endTimestamp] = enableArea || [] const [startTimestamp, endTimestamp] = enableArea || []
const ifOutofArea const ifOutofArea =
= +startTimestamp > timestamp || timestamp > +endTimestamp +startTimestamp > timestamp || timestamp > +endTimestamp
item.disable = ifOutofArea item.disable = ifOutofArea
return item return item
} }
} } else if (renderCausedBy === 'disableDates') {
else if (renderCausedBy === 'disableDates') {
if (disableDates && disableDates.length) { if (disableDates && disableDates.length) {
if (disableDates && disableDates.includes(timeStr)) { if (disableDates && disableDates.includes(timeStr)) {
item.disable = true item.disable = true
} } else {
else {
item.disable = false item.disable = false
} }
return item return item
@ -143,9 +131,9 @@ export default () => {
return { return {
calendarData: { calendarData: {
...calendarData, ...calendarData,
dates: _dates, dates: _dates
}, },
calendarConfig, calendarConfig
} }
}, },
methods(component) { methods(component) {
@ -157,28 +145,26 @@ export default () => {
const existCalendarData = getCalendarData('calendar', component) const existCalendarData = getCalendarData('calendar', component)
const { const {
startTimestamp, startTimestamp,
endTimestamp, endTimestamp
} = convertEnableAreaToTimestamp(dateArea) } = convertEnableAreaToTimestamp(dateArea)
return renderCalendar.call(component, { return renderCalendar.call(component, {
...existCalendarData, ...existCalendarData,
renderCausedBy: 'enableArea', renderCausedBy: 'enableArea',
enableArea: [startTimestamp, endTimestamp], enableArea: [startTimestamp, endTimestamp]
}) })
} }
} } else {
else {
return Promise.inject( return Promise.inject(
'enableArea()参数需为时间范围数组,形如:["2018-8-4" , "2018-8-24"]', 'enableArea()参数需为时间范围数组,形如:["2018-8-4" , "2018-8-24"]'
) )
} }
}, },
enableDates: (toSet = []) => { enableDates: (toSet = []) => {
if (!toSet.length) if (!toSet.length) return
return
const existCalendarData = getCalendarData('calendar', component) const existCalendarData = getCalendarData('calendar', component)
const { enableDates = [] } = existCalendarData || {} const { enableDates = [] } = existCalendarData || {}
let toSetDates = toSet.map((item) => { let toSetDates = toSet.map(item => {
if (typeof item === 'string') { if (typeof item === 'string') {
return dateUtil.transformDateRow2Dict(item) return dateUtil.transformDateRow2Dict(item)
} }
@ -187,25 +173,25 @@ export default () => {
if (enableDates.length) { if (enableDates.length) {
toSetDates = dateUtil.uniqueArrayByDate([ toSetDates = dateUtil.uniqueArrayByDate([
...toSetDates, ...toSetDates,
...enableDates.map(d => dateUtil.transformDateRow2Dict(d)), ...enableDates.map(d => dateUtil.transformDateRow2Dict(d))
]) ])
} }
return renderCalendar.call(component, { return renderCalendar.call(component, {
...existCalendarData, ...existCalendarData,
renderCausedBy: 'enableDates', renderCausedBy: 'enableDates',
enableDates: toSetDates.map((date) => { enableDates: toSetDates.map(date => {
if (typeof date !== 'string') { if (typeof date !== 'string') {
return dateUtil.toTimeStr(date) return dateUtil.toTimeStr(date)
} }
return date return date
}), })
}) })
}, },
disableDates: (toSet) => { disableDates: toSet => {
const existCalendarData = getCalendarData('calendar', component) const existCalendarData = getCalendarData('calendar', component)
const { disableDates = [], dates = [] } = existCalendarData || {} const { disableDates = [], dates = [] } = existCalendarData || {}
let toSetDates = toSet.map((item) => { let toSetDates = toSet.map(item => {
const date = { ...item } let date = { ...item }
if (typeof date === 'string') { if (typeof date === 'string') {
return dateUtil.transformDateRow2Dict(item) return dateUtil.transformDateRow2Dict(item)
} }
@ -214,22 +200,22 @@ export default () => {
if (disableDates && disableDates.length) { if (disableDates && disableDates.length) {
toSetDates = dateUtil.uniqueArrayByDate([ toSetDates = dateUtil.uniqueArrayByDate([
...toSetDates, ...toSetDates,
...disableDates.map(d => dateUtil.transformDateRow2Dict(d)), ...disableDates.map(d => dateUtil.transformDateRow2Dict(d))
]) ])
} }
return renderCalendar.call(component, { return renderCalendar.call(component, {
...existCalendarData, ...existCalendarData,
renderCausedBy: 'disableDates', renderCausedBy: 'disableDates',
dates, dates,
disableDates: toSetDates.map((date) => { disableDates: toSetDates.map(date => {
if (typeof date !== 'string') { if (typeof date !== 'string') {
return dateUtil.toTimeStr(date) return dateUtil.toTimeStr(date)
} }
return date return date
}), })
}) })
}, }
} }
}, }
} }
} }

662
src/components/calendar/plugins/solarLunar/convertSolarLunar.js

@ -6,7 +6,7 @@
*/ */
/* 公历年月日转农历数据 返回json */ /* 公历年月日转农历数据 返回json */
// calendar.solar2lunar(1987,11,01); // calendar.solar2lunar(1987,11,01);
/** 农历年月日转公历年月日 */ /** 农历年月日转公历年月日 **/
// calendar.lunar2solar(1987,9,10); // calendar.lunar2solar(1987,9,10);
// 调用以上方法后返回类似如下object(json)具体以上就不需要解释了吧! // 调用以上方法后返回类似如下object(json)具体以上就不需要解释了吧!
// c开头的是公历各属性值 l开头的自然就是农历咯 gz开头的就是天干地支纪年的数据啦~ // c开头的是公历各属性值 l开头的自然就是农历咯 gz开头的就是天干地支纪年的数据啦~
@ -39,208 +39,208 @@ const calendar = {
* @return Hex * @return Hex
*/ */
lunarInfo: [ lunarInfo: [
0x04BD8, 0x04bd8,
0x04AE0, 0x04ae0,
0x0A570, 0x0a570,
0x054D5, 0x054d5,
0x0D260, 0x0d260,
0x0D950, 0x0d950,
0x16554, 0x16554,
0x056A0, 0x056a0,
0x09AD0, 0x09ad0,
0x055D2, // 1900-1909 0x055d2, // 1900-1909
0x04AE0, 0x04ae0,
0x0A5B6, 0x0a5b6,
0x0A4D0, 0x0a4d0,
0x0D250, 0x0d250,
0x1D255, 0x1d255,
0x0B540, 0x0b540,
0x0D6A0, 0x0d6a0,
0x0ADA2, 0x0ada2,
0x095B0, 0x095b0,
0x14977, // 1910-1919 0x14977, // 1910-1919
0x04970, 0x04970,
0x0A4B0, 0x0a4b0,
0x0B4B5, 0x0b4b5,
0x06A50, 0x06a50,
0x06D40, 0x06d40,
0x1AB54, 0x1ab54,
0x02B60, 0x02b60,
0x09570, 0x09570,
0x052F2, 0x052f2,
0x04970, // 1920-1929 0x04970, // 1920-1929
0x06566, 0x06566,
0x0D4A0, 0x0d4a0,
0x0EA50, 0x0ea50,
0x06E95, 0x06e95,
0x05AD0, 0x05ad0,
0x02B60, 0x02b60,
0x186E3, 0x186e3,
0x092E0, 0x092e0,
0x1C8D7, 0x1c8d7,
0x0C950, // 1930-1939 0x0c950, // 1930-1939
0x0D4A0, 0x0d4a0,
0x1D8A6, 0x1d8a6,
0x0B550, 0x0b550,
0x056A0, 0x056a0,
0x1A5B4, 0x1a5b4,
0x025D0, 0x025d0,
0x092D0, 0x092d0,
0x0D2B2, 0x0d2b2,
0x0A950, 0x0a950,
0x0B557, // 1940-1949 0x0b557, // 1940-1949
0x06CA0, 0x06ca0,
0x0B550, 0x0b550,
0x15355, 0x15355,
0x04DA0, 0x04da0,
0x0A5B0, 0x0a5b0,
0x14573, 0x14573,
0x052B0, 0x052b0,
0x0A9A8, 0x0a9a8,
0x0E950, 0x0e950,
0x06AA0, // 1950-1959 0x06aa0, // 1950-1959
0x0AEA6, 0x0aea6,
0x0AB50, 0x0ab50,
0x04B60, 0x04b60,
0x0AAE4, 0x0aae4,
0x0A570, 0x0a570,
0x05260, 0x05260,
0x0F263, 0x0f263,
0x0D950, 0x0d950,
0x05B57, 0x05b57,
0x056A0, // 1960-1969 0x056a0, // 1960-1969
0x096D0, 0x096d0,
0x04DD5, 0x04dd5,
0x04AD0, 0x04ad0,
0x0A4D0, 0x0a4d0,
0x0D4D4, 0x0d4d4,
0x0D250, 0x0d250,
0x0D558, 0x0d558,
0x0B540, 0x0b540,
0x0B6A0, 0x0b6a0,
0x195A6, // 1970-1979 0x195a6, // 1970-1979
0x095B0, 0x095b0,
0x049B0, 0x049b0,
0x0A974, 0x0a974,
0x0A4B0, 0x0a4b0,
0x0B27A, 0x0b27a,
0x06A50, 0x06a50,
0x06D40, 0x06d40,
0x0AF46, 0x0af46,
0x0AB60, 0x0ab60,
0x09570, // 1980-1989 0x09570, // 1980-1989
0x04AF5, 0x04af5,
0x04970, 0x04970,
0x064B0, 0x064b0,
0x074A3, 0x074a3,
0x0EA50, 0x0ea50,
0x06B58, 0x06b58,
0x055C0, 0x055c0,
0x0AB60, 0x0ab60,
0x096D5, 0x096d5,
0x092E0, // 1990-1999 0x092e0, // 1990-1999
0x0C960, 0x0c960,
0x0D954, 0x0d954,
0x0D4A0, 0x0d4a0,
0x0DA50, 0x0da50,
0x07552, 0x07552,
0x056A0, 0x056a0,
0x0ABB7, 0x0abb7,
0x025D0, 0x025d0,
0x092D0, 0x092d0,
0x0CAB5, // 2000-2009 0x0cab5, // 2000-2009
0x0A950, 0x0a950,
0x0B4A0, 0x0b4a0,
0x0BAA4, 0x0baa4,
0x0AD50, 0x0ad50,
0x055D9, 0x055d9,
0x04BA0, 0x04ba0,
0x0A5B0, 0x0a5b0,
0x15176, 0x15176,
0x052B0, 0x052b0,
0x0A930, // 2010-2019 0x0a930, // 2010-2019
0x07954, 0x07954,
0x06AA0, 0x06aa0,
0x0AD50, 0x0ad50,
0x05B52, 0x05b52,
0x04B60, 0x04b60,
0x0A6E6, 0x0a6e6,
0x0A4E0, 0x0a4e0,
0x0D260, 0x0d260,
0x0EA65, 0x0ea65,
0x0D530, // 2020-2029 0x0d530, // 2020-2029
0x05AA0, 0x05aa0,
0x076A3, 0x076a3,
0x096D0, 0x096d0,
0x04AFB, 0x04afb,
0x04AD0, 0x04ad0,
0x0A4D0, 0x0a4d0,
0x1D0B6, 0x1d0b6,
0x0D250, 0x0d250,
0x0D520, 0x0d520,
0x0DD45, // 2030-2039 0x0dd45, // 2030-2039
0x0B5A0, 0x0b5a0,
0x056D0, 0x056d0,
0x055B2, 0x055b2,
0x049B0, 0x049b0,
0x0A577, 0x0a577,
0x0A4B0, 0x0a4b0,
0x0AA50, 0x0aa50,
0x1B255, 0x1b255,
0x06D20, 0x06d20,
0x0ADA0, // 2040-2049 0x0ada0, // 2040-2049
/** Add By JJonline@JJonline.Cn */ /** Add By JJonline@JJonline.Cn **/
0x14B63, 0x14b63,
0x09370, 0x09370,
0x049F8, 0x049f8,
0x04970, 0x04970,
0x064B0, 0x064b0,
0x168A6, 0x168a6,
0x0EA50, 0x0ea50,
0x06B20, 0x06b20,
0x1A6C4, 0x1a6c4,
0x0AAE0, // 2050-2059 0x0aae0, // 2050-2059
0x0A2E0, 0x0a2e0,
0x0D2E3, 0x0d2e3,
0x0C960, 0x0c960,
0x0D557, 0x0d557,
0x0D4A0, 0x0d4a0,
0x0DA50, 0x0da50,
0x05D55, 0x05d55,
0x056A0, 0x056a0,
0x0A6D0, 0x0a6d0,
0x055D4, // 2060-2069 0x055d4, // 2060-2069
0x052D0, 0x052d0,
0x0A9B8, 0x0a9b8,
0x0A950, 0x0a950,
0x0B4A0, 0x0b4a0,
0x0B6A6, 0x0b6a6,
0x0AD50, 0x0ad50,
0x055A0, 0x055a0,
0x0ABA4, 0x0aba4,
0x0A5B0, 0x0a5b0,
0x052B0, // 2070-2079 0x052b0, // 2070-2079
0x0B273, 0x0b273,
0x06930, 0x06930,
0x07337, 0x07337,
0x06AA0, 0x06aa0,
0x0AD50, 0x0ad50,
0x14B55, 0x14b55,
0x04B60, 0x04b60,
0x0A570, 0x0a570,
0x054E4, 0x054e4,
0x0D160, // 2080-2089 0x0d160, // 2080-2089
0x0E968, 0x0e968,
0x0D520, 0x0d520,
0x0DAA0, 0x0daa0,
0x16AA6, 0x16aa6,
0x056D0, 0x056d0,
0x04AE0, 0x04ae0,
0x0A9D4, 0x0a9d4,
0x0A2D0, 0x0a2d0,
0x0D150, 0x0d150,
0x0F252, // 2090-2099 0x0f252, // 2090-2099
0x0D520, 0x0d520
], // 2100 ], // 2100
/** /**
@ -257,15 +257,15 @@ const calendar = {
*/ */
Gan: [ Gan: [
'\u7532', '\u7532',
'\u4E59', '\u4e59',
'\u4E19', '\u4e19',
'\u4E01', '\u4e01',
'\u620A', '\u620a',
'\u5DF1', '\u5df1',
'\u5E9A', '\u5e9a',
'\u8F9B', '\u8f9b',
'\u58EC', '\u58ec',
'\u7678', '\u7678'
], ],
/** /**
@ -275,18 +275,18 @@ const calendar = {
* @return Cn string * @return Cn string
*/ */
Zhi: [ Zhi: [
'\u5B50', '\u5b50',
'\u4E11', '\u4e11',
'\u5BC5', '\u5bc5',
'\u536F', '\u536f',
'\u8FB0', '\u8fb0',
'\u5DF3', '\u5df3',
'\u5348', '\u5348',
'\u672A', '\u672a',
'\u7533', '\u7533',
'\u9149', '\u9149',
'\u620C', '\u620c',
'\u4EA5', '\u4ea5'
], ],
/** /**
@ -296,18 +296,18 @@ const calendar = {
* @return Cn string * @return Cn string
*/ */
Animals: [ Animals: [
'\u9F20', '\u9f20',
'\u725B', '\u725b',
'\u864E', '\u864e',
'\u5154', '\u5154',
'\u9F99', '\u9f99',
'\u86C7', '\u86c7',
'\u9A6C', '\u9a6c',
'\u7F8A', '\u7f8a',
'\u7334', '\u7334',
'\u9E21', '\u9e21',
'\u72D7', '\u72d7',
'\u732A', '\u732a'
], ],
/** /**
@ -317,30 +317,30 @@ const calendar = {
* @return Cn string * @return Cn string
*/ */
solarTerm: [ solarTerm: [
'\u5C0F\u5BD2', '\u5c0f\u5bd2',
'\u5927\u5BD2', '\u5927\u5bd2',
'\u7ACB\u6625', '\u7acb\u6625',
'\u96E8\u6C34', '\u96e8\u6c34',
'\u60CA\u86F0', '\u60ca\u86f0',
'\u6625\u5206', '\u6625\u5206',
'\u6E05\u660E', '\u6e05\u660e',
'\u8C37\u96E8', '\u8c37\u96e8',
'\u7ACB\u590F', '\u7acb\u590f',
'\u5C0F\u6EE1', '\u5c0f\u6ee1',
'\u8292\u79CD', '\u8292\u79cd',
'\u590F\u81F3', '\u590f\u81f3',
'\u5C0F\u6691', '\u5c0f\u6691',
'\u5927\u6691', '\u5927\u6691',
'\u7ACB\u79CB', '\u7acb\u79cb',
'\u5904\u6691', '\u5904\u6691',
'\u767D\u9732', '\u767d\u9732',
'\u79CB\u5206', '\u79cb\u5206',
'\u5BD2\u9732', '\u5bd2\u9732',
'\u971C\u964D', '\u971c\u964d',
'\u7ACB\u51AC', '\u7acb\u51ac',
'\u5C0F\u96EA', '\u5c0f\u96ea',
'\u5927\u96EA', '\u5927\u96ea',
'\u51AC\u81F3', '\u51ac\u81f3'
], ],
/** /**
@ -549,7 +549,7 @@ const calendar = {
'665f67f0e37f1489801eb072297c35', '665f67f0e37f1489801eb072297c35',
'7ec967f0e37f14998082b0787b06bd', '7ec967f0e37f14998082b0787b06bd',
'7f07e7f0e47f531b0723b0b6fb0721', '7f07e7f0e47f531b0723b0b6fb0721',
'7f0e27f1487f531b0b0bb0b6fb0722', '7f0e27f1487f531b0b0bb0b6fb0722'
], ],
/** /**
@ -559,17 +559,17 @@ const calendar = {
* @return Cn string * @return Cn string
*/ */
nStr1: [ nStr1: [
'\u65E5', '\u65e5',
'\u4E00', '\u4e00',
'\u4E8C', '\u4e8c',
'\u4E09', '\u4e09',
'\u56DB', '\u56db',
'\u4E94', '\u4e94',
'\u516D', '\u516d',
'\u4E03', '\u4e03',
'\u516B', '\u516b',
'\u4E5D', '\u4e5d',
'\u5341', '\u5341'
], ],
/** /**
@ -578,7 +578,7 @@ const calendar = {
* @trans ['初','十','廿','卅'] * @trans ['初','十','廿','卅']
* @return Cn string * @return Cn string
*/ */
nStr2: ['\u521D', '\u5341', '\u5EFF', '\u5345'], nStr2: ['\u521d', '\u5341', '\u5eff', '\u5345'],
/** /**
* 月份转农历称呼速查表 * 月份转农历称呼速查表
@ -587,18 +587,18 @@ const calendar = {
* @return Cn string * @return Cn string
*/ */
nStr3: [ nStr3: [
'\u6B63', '\u6b63',
'\u4E8C', '\u4e8c',
'\u4E09', '\u4e09',
'\u56DB', '\u56db',
'\u4E94', '\u4e94',
'\u516D', '\u516d',
'\u4E03', '\u4e03',
'\u516B', '\u516b',
'\u4E5D', '\u4e5d',
'\u5341', '\u5341',
'\u51AC', '\u51ac',
'\u814A', '\u814a'
], ],
/** /**
@ -607,7 +607,7 @@ const calendar = {
* @return Number * @return Number
* @eg:var count = calendar.lYearDays(1987) ;//count=387 * @eg:var count = calendar.lYearDays(1987) ;//count=387
*/ */
lYearDays(y) { lYearDays: function(y) {
let i let i
let sum = 348 let sum = 348
for (i = 0x8000; i > 0x8; i >>= 1) { for (i = 0x8000; i > 0x8; i >>= 1) {
@ -622,9 +622,9 @@ const calendar = {
* @return Number (0-12) * @return Number (0-12)
* @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6 * @eg:var leapMonth = calendar.leapMonth(1987) ;//leapMonth=6
*/ */
leapMonth(y) { leapMonth: function(y) {
// 闰字编码 \u95f0 // 闰字编码 \u95f0
return calendar.lunarInfo[y - 1900] & 0xF return calendar.lunarInfo[y - 1900] & 0xf
}, },
/** /**
@ -633,7 +633,7 @@ const calendar = {
* @return Number (02930) * @return Number (02930)
* @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29 * @eg:var leapMonthDay = calendar.leapDays(1987) ;//leapMonthDay=29
*/ */
leapDays(y) { leapDays: function(y) {
if (calendar.leapMonth(y)) { if (calendar.leapMonth(y)) {
return calendar.lunarInfo[y - 1900] & 0x10000 ? 30 : 29 return calendar.lunarInfo[y - 1900] & 0x10000 ? 30 : 29
} }
@ -646,9 +646,8 @@ const calendar = {
* @return Number (-12930) * @return Number (-12930)
* @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29 * @eg:var MonthDay = calendar.monthDays(1987,9) ;//MonthDay=29
*/ */
monthDays(y, m) { monthDays: function(y, m) {
if (m > 12 || m < 1) if (m > 12 || m < 1) return -1 // 月份参数从1至12,参数错误返回-1
return -1 // 月份参数从1至12,参数错误返回-1
return calendar.lunarInfo[y - 1900] & (0x10000 >> m) ? 30 : 29 return calendar.lunarInfo[y - 1900] & (0x10000 >> m) ? 30 : 29
}, },
@ -658,15 +657,13 @@ const calendar = {
* @return Number (-128293031) * @return Number (-128293031)
* @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30 * @eg:var solarMonthDay = calendar.leapDays(1987) ;//solarMonthDay=30
*/ */
solarDays(y, m) { solarDays: function(y, m) {
if (m > 12 || m < 1) if (m > 12 || m < 1) return -1 // 若参数错误 返回-1
return -1 // 若参数错误 返回-1
const ms = m - 1 const ms = m - 1
if (+ms === 1) { if (+ms === 1) {
// 2月份的闰平规律测算后确认返回28或29 // 2月份的闰平规律测算后确认返回28或29
return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 ? 29 : 28 return (y % 4 === 0 && y % 100 !== 0) || y % 400 === 0 ? 29 : 28
} } else {
else {
return calendar.solarMonth[ms] return calendar.solarMonth[ms]
} }
}, },
@ -676,13 +673,11 @@ const calendar = {
* @param lYear 农历年的年份数 * @param lYear 农历年的年份数
* @return Cn string * @return Cn string
*/ */
toGanZhiYear(lYear) { toGanZhiYear: function(lYear) {
let ganKey = (lYear - 3) % 10 let ganKey = (lYear - 3) % 10
let zhiKey = (lYear - 3) % 12 let zhiKey = (lYear - 3) % 12
if (+ganKey === 0) if (+ganKey === 0) ganKey = 10 // 如果余数为0则为最后一个天干
ganKey = 10 // 如果余数为0则为最后一个天干 if (+zhiKey === 0) zhiKey = 12 // 如果余数为0则为最后一个地支
if (+zhiKey === 0)
zhiKey = 12 // 如果余数为0则为最后一个地支
return calendar.Gan[ganKey - 1] + calendar.Zhi[zhiKey - 1] return calendar.Gan[ganKey - 1] + calendar.Zhi[zhiKey - 1]
}, },
@ -692,11 +687,11 @@ const calendar = {
* @param cDay [description] * @param cDay [description]
* @return Cn string * @return Cn string
*/ */
toAstro(cMonth, cDay) { toAstro: function(cMonth, cDay) {
const s const s =
= '\u9B54\u7FAF\u6C34\u74F6\u53CC\u9C7C\u767D\u7F8A\u91D1\u725B\u53CC\u5B50\u5DE8\u87F9\u72EE\u5B50\u5904\u5973\u5929\u79E4\u5929\u874E\u5C04\u624B\u9B54\u7FAF' '\u9b54\u7faf\u6c34\u74f6\u53cc\u9c7c\u767d\u7f8a\u91d1\u725b\u53cc\u5b50\u5de8\u87f9\u72ee\u5b50\u5904\u5973\u5929\u79e4\u5929\u874e\u5c04\u624b\u9b54\u7faf'
const arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22] const arr = [20, 19, 21, 21, 21, 22, 23, 23, 23, 23, 22, 22]
return `${s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2)}\u5EA7` // 座 return s.substr(cMonth * 2 - (cDay < arr[cMonth - 1] ? 2 : 0), 2) + '\u5ea7' // 座
}, },
/** /**
@ -704,7 +699,7 @@ const calendar = {
* @param offset 相对甲子的偏移量 * @param offset 相对甲子的偏移量
* @return Cn string * @return Cn string
*/ */
toGanZhi(offset) { toGanZhi: function(offset) {
return calendar.Gan[offset % 10] + calendar.Zhi[offset % 12] return calendar.Gan[offset % 10] + calendar.Zhi[offset % 12]
}, },
@ -714,19 +709,17 @@ const calendar = {
* @return day Number * @return day Number
* @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春 * @eg:var _24 = calendar.getTerm(1987,3) ;//_24=4;意即1987年2月4日立春
*/ */
getTerm(y, n) { getTerm: function(y, n) {
if (y < 1900 || y > 2100) if (y < 1900 || y > 2100) return -1
return -1 if (n < 1 || n > 24) return -1
if (n < 1 || n > 24)
return -1
const _table = calendar.sTermInfo[y - 1900] const _table = calendar.sTermInfo[y - 1900]
const _info = [ const _info = [
Number.parseInt(`0x${_table.substr(0, 5)}`).toString(), parseInt('0x' + _table.substr(0, 5)).toString(),
Number.parseInt(`0x${_table.substr(5, 5)}`).toString(), parseInt('0x' + _table.substr(5, 5)).toString(),
Number.parseInt(`0x${_table.substr(10, 5)}`).toString(), parseInt('0x' + _table.substr(10, 5)).toString(),
Number.parseInt(`0x${_table.substr(15, 5)}`).toString(), parseInt('0x' + _table.substr(15, 5)).toString(),
Number.parseInt(`0x${_table.substr(20, 5)}`).toString(), parseInt('0x' + _table.substr(20, 5)).toString(),
Number.parseInt(`0x${_table.substr(25, 5)}`).toString(), parseInt('0x' + _table.substr(25, 5)).toString()
] ]
const _calday = [ const _calday = [
_info[0].substr(0, 1), _info[0].substr(0, 1),
@ -757,9 +750,9 @@ const calendar = {
_info[5].substr(0, 1), _info[5].substr(0, 1),
_info[5].substr(1, 2), _info[5].substr(1, 2),
_info[5].substr(3, 1), _info[5].substr(3, 1),
_info[5].substr(4, 2), _info[5].substr(4, 2)
] ]
return Number.parseInt(_calday[n - 1]) return parseInt(_calday[n - 1])
}, },
/** /**
@ -768,10 +761,9 @@ const calendar = {
* @return Cn string * @return Cn string
* @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月' * @eg:var cnMonth = calendar.toChinaMonth(12) ;//cnMonth='腊月'
*/ */
toChinaMonth(m) { toChinaMonth: function(m) {
// 月 => \u6708 // 月 => \u6708
if (m > 12 || m < 1) if (m > 12 || m < 1) return -1 // 若参数错误 返回-1
return -1 // 若参数错误 返回-1
let s = calendar.nStr3[m - 1] let s = calendar.nStr3[m - 1]
s += '\u6708' // 加上月字 s += '\u6708' // 加上月字
return s return s
@ -783,18 +775,18 @@ const calendar = {
* @return Cn string * @return Cn string
* @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一' * @eg:var cnDay = calendar.toChinaDay(21) ;//cnMonth='廿一'
*/ */
toChinaDay(d) { toChinaDay: function(d) {
// 日 => \u65e5 // 日 => \u65e5
let s let s
switch (d) { switch (d) {
case 10: case 10:
s = '\u521D\u5341' s = '\u521d\u5341'
break break
case 20: case 20:
s = '\u4E8C\u5341' s = '\u4e8c\u5341'
break break
case 30: case 30:
s = '\u4E09\u5341' s = '\u4e09\u5341'
break break
default: default:
s = calendar.nStr2[Math.floor(d / 10)] s = calendar.nStr2[Math.floor(d / 10)]
@ -809,7 +801,7 @@ const calendar = {
* @return Cn string * @return Cn string
* @eg:var animal = calendar.getAnimal(1987) ;//animal='兔' * @eg:var animal = calendar.getAnimal(1987) ;//animal='兔'
*/ */
getAnimal(y) { getAnimal: function(y) {
return calendar.Animals[(y - 4) % 12] return calendar.Animals[(y - 4) % 12]
}, },
@ -821,7 +813,7 @@ const calendar = {
* @return JSON object * @return JSON object
* @eg:console.log(calendar.solar2lunar(1987,11,01)); * @eg:console.log(calendar.solar2lunar(1987,11,01));
*/ */
solar2lunar(y, m, d) { solar2lunar: function(y, m, d) {
// 参数区间1900.1.31~2100.12.31 // 参数区间1900.1.31~2100.12.31
// 年份限定、上限 // 年份限定、上限
if (y < 1900 || y > 2100) { if (y < 1900 || y > 2100) {
@ -835,9 +827,8 @@ const calendar = {
let objDate let objDate
if (!y) { if (!y) {
objDate = new Date() objDate = new Date()
} } else {
else { objDate = new Date(y, parseInt(m) - 1, d)
objDate = new Date(y, Number.parseInt(m) - 1, d)
} }
let i let i
let leap = 0 let leap = 0
@ -846,10 +837,10 @@ const calendar = {
y = objDate.getFullYear() y = objDate.getFullYear()
m = objDate.getMonth() + 1 m = objDate.getMonth() + 1
d = objDate.getDate() d = objDate.getDate()
let offset let offset =
= (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) -
- Date.UTC(1900, 0, 31)) Date.UTC(1900, 0, 31)) /
/ 86400000 86400000
for (i = 1900; i < 2101 && offset > 0; i++) { for (i = 1900; i < 2101 && offset > 0; i++) {
temp = calendar.lYearDays(i) temp = calendar.lYearDays(i)
offset -= temp offset -= temp
@ -863,9 +854,9 @@ const calendar = {
const isTodayObj = new Date() const isTodayObj = new Date()
let isToday = false let isToday = false
if ( if (
isTodayObj.getFullYear() === +y isTodayObj.getFullYear() === +y &&
&& isTodayObj.getMonth() + 1 === +m isTodayObj.getMonth() + 1 === +m &&
&& isTodayObj.getDate() === +d isTodayObj.getDate() === +d
) { ) {
isToday = true isToday = true
} }
@ -888,21 +879,18 @@ const calendar = {
--i --i
isLeap = true isLeap = true
temp = calendar.leapDays(year) // 计算农历闰月天数 temp = calendar.leapDays(year) // 计算农历闰月天数
} } else {
else {
temp = calendar.monthDays(year, i) // 计算农历普通月天数 temp = calendar.monthDays(year, i) // 计算农历普通月天数
} }
// 解除闰月 // 解除闰月
if (isLeap === true && i === leap + 1) if (isLeap === true && i === leap + 1) isLeap = false
isLeap = false
offset -= temp offset -= temp
} }
// 闰月导致数组下标重叠取反 // 闰月导致数组下标重叠取反
if (offset === 0 && leap > 0 && i === leap + 1) { if (offset === 0 && leap > 0 && i === leap + 1) {
if (isLeap) { if (isLeap) {
isLeap = false isLeap = false
} } else {
else {
isLeap = true isLeap = true
--i --i
} }
@ -952,7 +940,7 @@ const calendar = {
lMonth: month, lMonth: month,
lDay: day, lDay: day,
Animal: calendar.getAnimal(year), Animal: calendar.getAnimal(year),
IMonthCn: (isLeap ? '\u95F0' : '') + calendar.toChinaMonth(month), IMonthCn: (isLeap ? '\u95f0' : '') + calendar.toChinaMonth(month),
IDayCn: calendar.toChinaDay(day), IDayCn: calendar.toChinaDay(day),
cYear: y, cYear: y,
cMonth: m, cMonth: m,
@ -960,13 +948,13 @@ const calendar = {
gzYear: gzY, gzYear: gzY,
gzMonth: gzM, gzMonth: gzM,
gzDay: gzD, gzDay: gzD,
isToday, isToday: isToday,
isLeap, isLeap: isLeap,
nWeek, nWeek: nWeek,
ncWeek: `\u661F\u671F${cWeek}`, ncWeek: '\u661f\u671f' + cWeek,
isTerm, isTerm: isTerm,
Term, Term: Term,
astro, astro: astro
} }
}, },
@ -979,20 +967,18 @@ const calendar = {
* @return JSON object * @return JSON object
* @eg:console.log(calendar.lunar2solar(1987,9,10)); * @eg:console.log(calendar.lunar2solar(1987,9,10));
*/ */
lunar2solar(y, m, d, isLeapMonth) { lunar2solar: function(y, m, d, isLeapMonth) {
// 参数区间1900.1.31~2100.12.1 // 参数区间1900.1.31~2100.12.1
isLeapMonth = !!isLeapMonth isLeapMonth = !!isLeapMonth
// let leapOffset = 0; // let leapOffset = 0;
const leapMonth = calendar.leapMonth(y) const leapMonth = calendar.leapMonth(y)
// let leapDay = calendar.leapDays(y); // let leapDay = calendar.leapDays(y);
if (isLeapMonth && leapMonth !== m) if (isLeapMonth && leapMonth !== m) return -1 // 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
return -1 // 传参要求计算该闰月公历 但该年得出的闰月与传参的月份并不同
if ( if (
(+y === 2100 && +m === 12 && +d > 1) (+y === 2100 && +m === 12 && +d > 1) ||
|| (+y === 1900 && +m === 1 && +d < 31) (+y === 1900 && +m === 1 && +d < 31)
) { )
return -1 return -1 // 超出了最大极限值
} // 超出了最大极限值
const day = calendar.monthDays(y, m) const day = calendar.monthDays(y, m)
let _day = day let _day = day
// bugFix 2016-9-25 // bugFix 2016-9-25
@ -1000,8 +986,7 @@ const calendar = {
if (isLeapMonth) { if (isLeapMonth) {
_day = calendar.leapDays(y, m) _day = calendar.leapDays(y, m)
} }
if (y < 1900 || y > 2100 || d > _day) if (y < 1900 || y > 2100 || d > _day) return -1 // 参数合法性效验
return -1 // 参数合法性效验
// 计算农历的时间差 // 计算农历的时间差
let offset = 0 let offset = 0
@ -1022,8 +1007,7 @@ const calendar = {
offset += calendar.monthDays(y, i) offset += calendar.monthDays(y, i)
} }
// 转换闰月农历 需补充该年闰月的前一个月的时差 // 转换闰月农历 需补充该年闰月的前一个月的时差
if (isLeapMonth) if (isLeapMonth) offset += day
offset += day
// 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点) // 1900年农历正月一日的公历时间为1900年1月30日0时0分0秒(该时间也是本农历的最开始起始点)
const stmap = Date.UTC(1900, 1, 30, 0, 0, 0) const stmap = Date.UTC(1900, 1, 30, 0, 0, 0)
const calObj = new Date((offset + d - 31) * 86400000 + stmap) const calObj = new Date((offset + d - 31) * 86400000 + stmap)
@ -1032,7 +1016,7 @@ const calendar = {
const cD = calObj.getUTCDate() const cD = calObj.getUTCDate()
return calendar.solar2lunar(cY, cM, cD) return calendar.solar2lunar(cY, cM, cD)
}, }
} }
const { const {

2
src/components/calendar/plugins/solarLunar/index.d.ts vendored

@ -1 +1 @@
export {} export {};

29
src/components/calendar/plugins/solarLunar/index.js

@ -2,8 +2,7 @@ import { dateUtil } from '../../utils/index'
import convertSolarLunar from './convertSolarLunar' import convertSolarLunar from './convertSolarLunar'
function getDateRow2Dict(dateInfo) { function getDateRow2Dict(dateInfo) {
if (!dateInfo) if (!dateInfo) return dateInfo
return dateInfo
if (typeof dateInfo === 'string' && dateInfo.includes('-')) { if (typeof dateInfo === 'string' && dateInfo.includes('-')) {
dateInfo = dateUtil.transformDateRow2Dict(dateInfo) dateInfo = dateUtil.transformDateRow2Dict(dateInfo)
} }
@ -16,47 +15,45 @@ export default () => {
beforeRender(calendarData = {}, calendarConfig = {}) { beforeRender(calendarData = {}, calendarConfig = {}) {
let { dates = [], selectedDates = [] } = calendarData let { dates = [], selectedDates = [] } = calendarData
if (calendarConfig.showLunar) { if (calendarConfig.showLunar) {
dates = dates.map((dataInfo) => { dates = dates.map(dataInfo => {
const { year, month, date } = dataInfo const { year, month, date } = dataInfo
return { return {
...dataInfo, ...dataInfo,
lunar: convertSolarLunar.solar2lunar(year, month, date), lunar: convertSolarLunar.solar2lunar(year, month, date)
} }
}) })
selectedDates = selectedDates.map((dataInfo) => { selectedDates = selectedDates.map(dataInfo => {
const { year, month, date } = dataInfo const { year, month, date } = dataInfo
return { return {
...dataInfo, ...dataInfo,
lunar: convertSolarLunar.solar2lunar(year, month, date), lunar: convertSolarLunar.solar2lunar(year, month, date)
} }
}) })
} }
return { return {
calendarData: { calendarData: {
...calendarData, ...calendarData,
dates, dates: dates,
selectedDates, selectedDates: selectedDates
}, },
calendarConfig, calendarConfig
} }
}, },
methods() { methods() {
return { return {
convertSolarLunar: (dateInfo) => { convertSolarLunar: dateInfo => {
dateInfo = getDateRow2Dict(dateInfo) dateInfo = getDateRow2Dict(dateInfo)
if (!dateInfo) if (!dateInfo) return dateInfo
return dateInfo
const { year, month, date } = dateInfo const { year, month, date } = dateInfo
return convertSolarLunar.solar2lunar(year, month, date) return convertSolarLunar.solar2lunar(year, month, date)
}, },
convertlLunar2Solar: (dateInfo, isLeapMonth) => { convertlLunar2Solar: (dateInfo, isLeapMonth) => {
dateInfo = getDateRow2Dict(dateInfo) dateInfo = getDateRow2Dict(dateInfo)
if (!dateInfo) if (!dateInfo) return dateInfo
return dateInfo
const { year, month, date } = dateInfo const { year, month, date } = dateInfo
return convertSolarLunar.lunar2solar(year, month, date, isLeapMonth) return convertSolarLunar.lunar2solar(year, month, date, isLeapMonth)
}, }
} }
}, }
} }
} }

126
src/components/calendar/plugins/time-range.js

@ -4,32 +4,32 @@
* @Date: 2020-10-08 21:22:09* * @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu * @Last Modified by: drfu
* @Last Modified time: 2020-10-11 13:56:32 * @Last Modified time: 2020-10-11 13:56:32
*/ * */
import { renderCalendar } from '../render' import { renderCalendar } from '../render'
import { import {
logger,
dateUtil, dateUtil,
getCalendarConfig, getCalendarConfig,
getCalendarData, getCalendarData
logger,
} from '../utils/index' } from '../utils/index'
function pusheNextMonthDateArea( function pusheNextMonthDateArea(
dateInfo = {}, dateInfo = {},
startTimestamp, startTimestamp,
endTimestamp, endTimestamp,
selectedDates = [], selectedDates = []
) { ) {
const tempOfSelectedDate = [...selectedDates] let tempOfSelectedDate = [...selectedDates]
const dates = dateUtil.calcDates(dateInfo.year, dateInfo.month) const dates = dateUtil.calcDates(dateInfo.year, dateInfo.month)
const datesLen = dates.length let datesLen = dates.length
for (let i = 0; i < datesLen; i++) { for (let i = 0; i < datesLen; i++) {
const date = dates[i] const date = dates[i]
const timeStamp = dateUtil.getTimeStamp(date) const timeStamp = dateUtil.getTimeStamp(date)
if (timeStamp <= endTimestamp && timeStamp >= startTimestamp) { if (timeStamp <= endTimestamp && timeStamp >= startTimestamp) {
tempOfSelectedDate.push({ tempOfSelectedDate.push({
...date, ...date,
choosed: true, choosed: true
}) })
} }
if (i === datesLen - 1 && timeStamp < endTimestamp) { if (i === datesLen - 1 && timeStamp < endTimestamp) {
@ -37,7 +37,7 @@ function pusheNextMonthDateArea(
dateUtil.getNextMonthInfo(date), dateUtil.getNextMonthInfo(date),
startTimestamp, startTimestamp,
endTimestamp, endTimestamp,
tempOfSelectedDate, tempOfSelectedDate
) )
} }
} }
@ -47,22 +47,22 @@ function pushPrevMonthDateArea(
dateInfo = {}, dateInfo = {},
startTimestamp, startTimestamp,
endTimestamp, endTimestamp,
selectedDates = [], selectedDates = []
) { ) {
const tempOfSelectedDate = [...selectedDates] let tempOfSelectedDate = [...selectedDates]
const dates = dateUtil.sortDatesByTime( const dates = dateUtil.sortDatesByTime(
dateUtil.calcDates(dateInfo.year, dateInfo.month), dateUtil.calcDates(dateInfo.year, dateInfo.month),
'desc', 'desc'
) )
const datesLen = dates.length let datesLen = dates.length
const firstDate = dateUtil.getTimeStamp(dates[0]) let firstDate = dateUtil.getTimeStamp(dates[0])
for (let i = 0; i < datesLen; i++) { for (let i = 0; i < datesLen; i++) {
const date = dates[i] const date = dates[i]
const timeStamp = dateUtil.getTimeStamp(date) const timeStamp = dateUtil.getTimeStamp(date)
if (timeStamp >= startTimestamp && timeStamp <= endTimestamp) { if (timeStamp >= startTimestamp && timeStamp <= endTimestamp) {
tempOfSelectedDate.push({ tempOfSelectedDate.push({
...date, ...date,
choosed: true, choosed: true
}) })
} }
if (i === datesLen - 1 && firstDate > startTimestamp) { if (i === datesLen - 1 && firstDate > startTimestamp) {
@ -70,7 +70,7 @@ function pushPrevMonthDateArea(
dateUtil.getPrevMonthInfo(date), dateUtil.getPrevMonthInfo(date),
startTimestamp, startTimestamp,
endTimestamp, endTimestamp,
tempOfSelectedDate, tempOfSelectedDate
) )
} }
} }
@ -88,7 +88,7 @@ function calcDateWhenNotInOneMonth(info) {
dateUtil.getPrevMonthInfo(firstDate), dateUtil.getPrevMonthInfo(firstDate),
startTimestamp, startTimestamp,
endTimestamp, endTimestamp,
selectedDate, selectedDate
) )
} }
if (dateUtil.getTimeStamp(lastDate) < endTimestamp) { if (dateUtil.getTimeStamp(lastDate) < endTimestamp) {
@ -96,7 +96,7 @@ function calcDateWhenNotInOneMonth(info) {
dateUtil.getNextMonthInfo(lastDate), dateUtil.getNextMonthInfo(lastDate),
startTimestamp, startTimestamp,
endTimestamp, endTimestamp,
selectedDate, selectedDate
) )
} }
return [...selectedDate] return [...selectedDate]
@ -104,7 +104,7 @@ function calcDateWhenNotInOneMonth(info) {
/** /**
* 指定日期区域转时间戳 * 指定日期区域转时间戳
* @param {Array} timearea 时间区域 * @param {array} timearea 时间区域
*/ */
export function convertTimeRangeToTimestamp(timearea = []) { export function convertTimeRangeToTimestamp(timearea = []) {
const start = timearea[0].split('-') const start = timearea[0].split('-')
@ -121,46 +121,40 @@ export function convertTimeRangeToTimestamp(timearea = []) {
start, start,
end, end,
startTimestamp, startTimestamp,
endTimestamp, endTimestamp
} }
} }
/** /**
* 校验时间区域是否合法 * 校验时间区域是否合法
* @param {Array} dateArea 时间区域 * @param {array} dateArea 时间区域
*/ */
function validateTimeRange(dateArea) { function validateTimeRange(dateArea) {
const { const {
start, start,
end, end,
startTimestamp, startTimestamp,
endTimestamp, endTimestamp
} = convertTimeRangeToTimestamp(dateArea) } = convertTimeRangeToTimestamp(dateArea)
if (!start || !end) if (!start || !end) return
return
const startMonthDays = dateUtil.getDatesCountOfMonth(start[0], start[1]) const startMonthDays = dateUtil.getDatesCountOfMonth(start[0], start[1])
const endMonthDays = dateUtil.getDatesCountOfMonth(end[0], end[1]) const endMonthDays = dateUtil.getDatesCountOfMonth(end[0], end[1])
if (start[2] > startMonthDays || start[2] < 1) { if (start[2] > startMonthDays || start[2] < 1) {
logger.warn('enableArea() 开始日期错误,指定日期不在当前月份天数范围内') logger.warn('enableArea() 开始日期错误,指定日期不在当前月份天数范围内')
return false return false
} } else if (start[1] > 12 || start[1] < 1) {
else if (start[1] > 12 || start[1] < 1) {
logger.warn('enableArea() 开始日期错误,月份超出1-12月份') logger.warn('enableArea() 开始日期错误,月份超出1-12月份')
return false return false
} } else if (end[2] > endMonthDays || end[2] < 1) {
else if (end[2] > endMonthDays || end[2] < 1) {
logger.warn('enableArea() 截止日期错误,指定日期不在当前月份天数范围内') logger.warn('enableArea() 截止日期错误,指定日期不在当前月份天数范围内')
return false return false
} } else if (end[1] > 12 || end[1] < 1) {
else if (end[1] > 12 || end[1] < 1) {
logger.warn('enableArea() 截止日期错误,月份超出1-12月份') logger.warn('enableArea() 截止日期错误,月份超出1-12月份')
return false return false
} } else if (startTimestamp > endTimestamp) {
else if (startTimestamp > endTimestamp) {
logger.warn('enableArea()参数最小日期大于了最大日期') logger.warn('enableArea()参数最小日期大于了最大日期')
return false return false
} } else {
else {
return true return true
} }
} }
@ -172,27 +166,26 @@ export default () => {
const { const {
chooseAreaTimestamp = [], chooseAreaTimestamp = [],
dates = [], dates = [],
selectedDates = [], selectedDates = []
} = calendarData } = calendarData
let __dates = dates let __dates = dates
let __selectedDates = selectedDates let __selectedDates = selectedDates
const [startDateTimestamp, endDateTimestamp] = chooseAreaTimestamp const [startDateTimestamp, endDateTimestamp] = chooseAreaTimestamp
if (chooseAreaTimestamp.length === 2) { if (chooseAreaTimestamp.length === 2) {
__selectedDates = [] __selectedDates = []
__dates = dates.map((d) => { __dates = dates.map(d => {
const date = { ...d } const date = { ...d }
const dateTimeStamp = dateUtil.getTimeStamp(date) const dateTimeStamp = dateUtil.getTimeStamp(date)
if ( if (
dateTimeStamp >= startDateTimestamp dateTimeStamp >= startDateTimestamp &&
&& endDateTimestamp >= dateTimeStamp endDateTimestamp >= dateTimeStamp
) { ) {
date.choosed = true date.choosed = true
__selectedDates.push(date) __selectedDates.push(date)
} } else {
else {
date.choosed = false date.choosed = false
__selectedDates = __selectedDates.filter( __selectedDates = __selectedDates.filter(
item => dateUtil.getTimeStamp(item) !== dateTimeStamp, item => dateUtil.getTimeStamp(item) !== dateTimeStamp
) )
} }
return date return date
@ -205,7 +198,7 @@ export default () => {
lastDate: __dates[__dates.length - 1], lastDate: __dates[__dates.length - 1],
startTimestamp: startDateTimestamp, startTimestamp: startDateTimestamp,
endTimestamp: endDateTimestamp, endTimestamp: endDateTimestamp,
selectedDate: __selectedDates, selectedDate: __selectedDates
}) })
} }
} }
@ -214,47 +207,44 @@ export default () => {
...calendarData, ...calendarData,
dates: __dates, dates: __dates,
selectedDates: dateUtil.sortDatesByTime( selectedDates: dateUtil.sortDatesByTime(
dateUtil.uniqueArrayByDate(__selectedDates), dateUtil.uniqueArrayByDate(__selectedDates)
), )
}, },
calendarConfig, calendarConfig
} }
}, },
onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) { onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) {
if (!calendarConfig.chooseAreaMode) { if (!calendarConfig.chooseAreaMode) {
return { return {
calendarData, calendarData,
calendarConfig, calendarConfig
} }
} }
let { let {
tempChooseAreaTimestamp = [], tempChooseAreaTimestamp = [],
chooseAreaTimestamp: existChooseAreaTimestamp = [], chooseAreaTimestamp: existChooseAreaTimestamp = [],
selectedDates = [], selectedDates = [],
dates = [], dates = []
} = calendarData } = calendarData
const timestamp = dateUtil.getTimeStamp(tapedDate) const timestamp = dateUtil.getTimeStamp(tapedDate)
const __dates = [...dates] let __dates = [...dates]
let __selectedDates = [...selectedDates] let __selectedDates = [...selectedDates]
if ( if (
tempChooseAreaTimestamp.length === 2 tempChooseAreaTimestamp.length === 2 ||
|| existChooseAreaTimestamp.length === 2 existChooseAreaTimestamp.length === 2
) { ) {
tempChooseAreaTimestamp = [tapedDate] tempChooseAreaTimestamp = [tapedDate]
__selectedDates = [] __selectedDates = []
__dates.forEach(d => (d.choosed = false)) __dates.forEach(d => (d.choosed = false))
} } else if (tempChooseAreaTimestamp.length === 1) {
else if (tempChooseAreaTimestamp.length === 1) {
const preChoosedDate = tempChooseAreaTimestamp[0] const preChoosedDate = tempChooseAreaTimestamp[0]
const preTimestamp = dateUtil.getTimeStamp(preChoosedDate) const preTimestamp = dateUtil.getTimeStamp(preChoosedDate)
if (preTimestamp <= timestamp) { if (preTimestamp <= timestamp) {
tempChooseAreaTimestamp.push(tapedDate) tempChooseAreaTimestamp.push(tapedDate)
} } else if (preTimestamp > timestamp) {
else if (preTimestamp > timestamp) {
tempChooseAreaTimestamp.unshift(tapedDate) tempChooseAreaTimestamp.unshift(tapedDate)
} }
} } else {
else {
tempChooseAreaTimestamp = [tapedDate] tempChooseAreaTimestamp = [tapedDate]
} }
let chooseAreaTimestamp = [] let chooseAreaTimestamp = []
@ -270,48 +260,46 @@ export default () => {
chooseAreaTimestamp, chooseAreaTimestamp,
tempChooseAreaTimestamp, tempChooseAreaTimestamp,
dates: __dates, dates: __dates,
selectedDates: __selectedDates, selectedDates: __selectedDates
}, },
calendarConfig: { calendarConfig: {
...calendarConfig, ...calendarConfig,
multi: true, multi: true
}, }
} }
}, },
methods(component) { methods(component) {
return { return {
/** /**
* 设置连续日期选择区域 * 设置连续日期选择区域
* @param {Array} dateArea 区域开始结束日期数组 * @param {array} dateArea 区域开始结束日期数组
*/ */
chooseDateArea: (dateArea = []) => { chooseDateArea: (dateArea = []) => {
if (dateArea.length === 1) { if (dateArea.length === 1) {
dateArea = dateArea.concat(dateArea) dateArea = dateArea.concat(dateArea)
} }
if (dateArea.length !== 2) if (dateArea.length !== 2) return
return
const isRight = validateTimeRange(dateArea) const isRight = validateTimeRange(dateArea)
if (!isRight) if (!isRight) return
return
const config = getCalendarConfig(component) || {} const config = getCalendarConfig(component) || {}
const { startTimestamp, endTimestamp } = convertTimeRangeToTimestamp( const { startTimestamp, endTimestamp } = convertTimeRangeToTimestamp(
dateArea, dateArea
) )
const existCalendarData = getCalendarData('calendar', component) const existCalendarData = getCalendarData('calendar', component)
return renderCalendar.call( return renderCalendar.call(
component, component,
{ {
...existCalendarData, ...existCalendarData,
chooseAreaTimestamp: [startTimestamp, endTimestamp], chooseAreaTimestamp: [startTimestamp, endTimestamp]
}, },
{ {
...config, ...config,
multi: true, multi: true,
chooseAreaMode: true, chooseAreaMode: true
}, }
) )
}, }
} }
}, }
} }
} }

2
src/components/calendar/plugins/todo.d.ts vendored

@ -1 +1 @@
export {} export {};

56
src/components/calendar/plugins/todo.js

@ -4,24 +4,22 @@
* @Date: 2020-10-08 21:22:09* * @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu * @Last Modified by: drfu
* @Last Modified time: 2020-10-11 14:23:02 * @Last Modified time: 2020-10-11 14:23:02
*/ * */
import { getCalendarData, dateUtil } from '../utils/index'
import { renderCalendar } from '../render' import { renderCalendar } from '../render'
import { dateUtil, getCalendarData } from '../utils/index'
function updateDatePropertyOfTodoLabel(todos, dates, showLabelAlways) { function updateDatePropertyOfTodoLabel(todos, dates, showLabelAlways) {
const datesInfo = [...dates] const datesInfo = [...dates]
for (const todo of todos) { for (let todo of todos) {
const targetIdx = datesInfo.findIndex( let targetIdx = datesInfo.findIndex(
item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(todo), item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(todo)
) )
const target = datesInfo[targetIdx] let target = datesInfo[targetIdx]
if (!target) if (!target) continue
continue
if (showLabelAlways) { if (showLabelAlways) {
target.showTodoLabel = true target.showTodoLabel = true
} } else {
else {
target.showTodoLabel = !target.choosed target.showTodoLabel = !target.choosed
} }
if (target.showTodoLabel) { if (target.showTodoLabel) {
@ -40,14 +38,14 @@ export default () => {
const dateWithTodoInfo = updateDatePropertyOfTodoLabel( const dateWithTodoInfo = updateDatePropertyOfTodoLabel(
todos, todos,
dates, dates,
showLabelAlways, showLabelAlways
) )
return { return {
calendarData: { calendarData: {
...calendarData, ...calendarData,
dates: dateWithTodoInfo, dates: dateWithTodoInfo
}, },
calendarConfig, calendarConfig
} }
}, },
methods(component) { methods(component) {
@ -62,17 +60,17 @@ export default () => {
dotColor = '', dotColor = '',
pos = 'bottom', pos = 'bottom',
showLabelAlways, showLabelAlways,
dates: todoDates = [], dates: todoDates = []
} = options } = options
const { todos = [] } = calendar const { todos = [] } = calendar
const tranformStr2NumOfTodo = todoDates.map(date => const tranformStr2NumOfTodo = todoDates.map(date =>
dateUtil.tranformStr2NumOfDate(date), dateUtil.tranformStr2NumOfDate(date)
) )
const calendarData = { const calendarData = {
dates: calendar.dates, dates: calendar.dates,
todos: dateUtil.uniqueArrayByDate( todos: dateUtil.uniqueArrayByDate(
todos.concat(tranformStr2NumOfTodo), todos.concat(tranformStr2NumOfTodo)
), )
} }
if (!circle) { if (!circle) {
calendarData.todoLabelPos = pos calendarData.todoLabelPos = pos
@ -83,55 +81,55 @@ export default () => {
const existCalendarData = getCalendarData('calendar', component) const existCalendarData = getCalendarData('calendar', component)
return renderCalendar.call(component, { return renderCalendar.call(component, {
...existCalendarData, ...existCalendarData,
...calendarData, ...calendarData
}) })
}, },
deleteTodos(todos = []) { deleteTodos(todos = []) {
if (!(Array.isArray(todos)) || !todos.length) if (!(todos instanceof Array) || !todos.length)
return Promise.reject('deleteTodos()应为入参为非空数组') return Promise.reject('deleteTodos()应为入参为非空数组')
const existCalendarData = getCalendarData('calendar', component) const existCalendarData = getCalendarData('calendar', component)
const allTodos = existCalendarData.todos || [] const allTodos = existCalendarData.todos || []
const toDeleteTodos = todos.map(item => dateUtil.toTimeStr(item)) const toDeleteTodos = todos.map(item => dateUtil.toTimeStr(item))
const remainTodos = allTodos.filter( const remainTodos = allTodos.filter(
item => !toDeleteTodos.includes(dateUtil.toTimeStr(item)), item => !toDeleteTodos.includes(dateUtil.toTimeStr(item))
) )
const { dates, curYear, curMonth } = existCalendarData const { dates, curYear, curMonth } = existCalendarData
const _dates = [...dates] const _dates = [...dates]
const currentMonthTodos = dateUtil.filterDatesByYM( const currentMonthTodos = dateUtil.filterDatesByYM(
{ {
year: curYear, year: curYear,
month: curMonth, month: curMonth
}, },
remainTodos, remainTodos
) )
_dates.forEach((item) => { _dates.forEach(item => {
item.showTodoLabel = false item.showTodoLabel = false
}) })
currentMonthTodos.forEach((item) => { currentMonthTodos.forEach(item => {
_dates[item.date - 1].showTodoLabel = !_dates[item.date - 1].choosed _dates[item.date - 1].showTodoLabel = !_dates[item.date - 1].choosed
}) })
return renderCalendar.call(component, { return renderCalendar.call(component, {
...existCalendarData, ...existCalendarData,
dates: _dates, dates: _dates,
todos: remainTodos, todos: remainTodos
}) })
}, },
clearTodos() { clearTodos() {
const existCalendarData = getCalendarData('calendar', component) const existCalendarData = getCalendarData('calendar', component)
const _dates = [...existCalendarData.dates] const _dates = [...existCalendarData.dates]
_dates.forEach((item) => { _dates.forEach(item => {
item.showTodoLabel = false item.showTodoLabel = false
}) })
return renderCalendar.call(component, { return renderCalendar.call(component, {
...existCalendarData, ...existCalendarData,
dates: _dates, dates: _dates,
todos: [], todos: []
}) })
}, },
getTodos() { getTodos() {
return getCalendarData('calendar.todos', component) || [] return getCalendarData('calendar.todos', component) || []
}, }
} }
}, }
} }
} }

156
src/components/calendar/plugins/week.js

@ -4,16 +4,16 @@
* @Date: 2020-10-08 21:22:09* * @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu * @Last Modified by: drfu
* @Last Modified time: 2020-10-12 14:39:45 * @Last Modified time: 2020-10-12 14:39:45
*/ * */
import { calcJumpData } from '../core'
import { renderCalendar } from '../render' import { renderCalendar } from '../render'
import { import {
dateUtil,
getCalendarConfig, getCalendarConfig,
getCalendarData, getCalendarData,
logger, logger,
dateUtil
} from '../utils/index' } from '../utils/index'
import { calcJumpData } from '../core'
/** /**
* 当月第一周所有日期 * 当月第一周所有日期
@ -21,7 +21,7 @@ import {
function firstWeekInMonth( function firstWeekInMonth(
target = {}, target = {},
calendarDates = [], calendarDates = [],
calendarConfig = {}, calendarConfig = {}
) { ) {
const { firstDayOfWeek } = calendarConfig const { firstDayOfWeek } = calendarConfig
const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon' const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
@ -54,11 +54,10 @@ function lastWeekInMonth(target = {}, calendarDates = [], calendarConfig = {}) {
* 判断目标日期是否在某些指定日历内 * 判断目标日期是否在某些指定日历内
*/ */
function dateIsInDatesRange(target, dates) { function dateIsInDatesRange(target, dates) {
if (!target || !dates || !dates.length) if (!target || !dates || !dates.length) return false
return false
const targetDateStr = dateUtil.toTimeStr(target) const targetDateStr = dateUtil.toTimeStr(target)
let rst = false let rst = false
for (const date of dates) { for (let date of dates) {
const dateStr = dateUtil.toTimeStr(date) const dateStr = dateUtil.toTimeStr(date)
if (dateStr === targetDateStr) { if (dateStr === targetDateStr) {
rst = true rst = true
@ -74,17 +73,17 @@ function getDatesWhenTargetInFirstWeek(target, firstWeekDates) {
const prevMonthInfo = dateUtil.getPrevMonthInfo({ year, month }) const prevMonthInfo = dateUtil.getPrevMonthInfo({ year, month })
let lastMonthDatesCount = dateUtil.getDatesCountOfMonth( let lastMonthDatesCount = dateUtil.getDatesCountOfMonth(
prevMonthInfo.year, prevMonthInfo.year,
prevMonthInfo.month, prevMonthInfo.month
) )
const dates = firstWeekDates let dates = firstWeekDates
const firstWeekCount = firstWeekDates.length let firstWeekCount = firstWeekDates.length
for (let i = 0; i < 7 - firstWeekCount; i++) { for (let i = 0; i < 7 - firstWeekCount; i++) {
const week = dateUtil.getDayOfWeek(+year, +month, lastMonthDatesCount) const week = dateUtil.getDayOfWeek(+year, +month, lastMonthDatesCount)
dates.unshift({ dates.unshift({
year: prevMonthInfo.year, year: prevMonthInfo.year,
month: prevMonthInfo.month, month: prevMonthInfo.month,
date: lastMonthDatesCount, date: lastMonthDatesCount,
week, week
}) })
lastMonthDatesCount -= 1 lastMonthDatesCount -= 1
} }
@ -94,15 +93,15 @@ function getDatesWhenTargetInFirstWeek(target, firstWeekDates) {
function getDatesWhenTargetInLastWeek(target, lastWeekDates) { function getDatesWhenTargetInLastWeek(target, lastWeekDates) {
const { year, month } = target const { year, month } = target
const prevMonthInfo = dateUtil.getNextMonthInfo({ year, month }) const prevMonthInfo = dateUtil.getNextMonthInfo({ year, month })
const dates = lastWeekDates let dates = lastWeekDates
const lastWeekCount = lastWeekDates.length let lastWeekCount = lastWeekDates.length
for (let i = 0; i < 7 - lastWeekCount; i++) { for (let i = 0; i < 7 - lastWeekCount; i++) {
const week = dateUtil.getDayOfWeek(+year, +month, i + 1) const week = dateUtil.getDayOfWeek(+year, +month, i + 1)
dates.push({ dates.push({
year: prevMonthInfo.year, year: prevMonthInfo.year,
month: prevMonthInfo.month, month: prevMonthInfo.month,
date: i + 1, date: i + 1,
week, week
}) })
} }
return dates return dates
@ -116,27 +115,23 @@ function getDates(target, calendarDates = [], calendarConfig = {}) {
if (firstDayOfWeekIsMon) { if (firstDayOfWeekIsMon) {
const startIdx = date - (targetDay || 7) const startIdx = date - (targetDay || 7)
return calendarDates.splice(startIdx, 7) return calendarDates.splice(startIdx, 7)
} } else {
else {
const startIdx = date - targetDay - 1 const startIdx = date - targetDay - 1
return calendarDates.splice(startIdx, 7) return calendarDates.splice(startIdx, 7)
} }
} }
function getTargetWeekDates(target, calendarConfig) { function getTargetWeekDates(target, calendarConfig) {
if (!target) if (!target) return
return
const { year, month } = target const { year, month } = target
const calendarDates = dateUtil.calcDates(year, month) const calendarDates = dateUtil.calcDates(year, month)
const firstWeekDates = firstWeekInMonth(target, calendarDates, calendarConfig) const firstWeekDates = firstWeekInMonth(target, calendarDates, calendarConfig)
const lastWeekDates = lastWeekInMonth(target, calendarDates, calendarConfig) const lastWeekDates = lastWeekInMonth(target, calendarDates, calendarConfig)
if (dateIsInDatesRange(target, firstWeekDates)) { if (dateIsInDatesRange(target, firstWeekDates)) {
return getDatesWhenTargetInFirstWeek(target, firstWeekDates) return getDatesWhenTargetInFirstWeek(target, firstWeekDates)
} } else if (dateIsInDatesRange(target, lastWeekDates)) {
else if (dateIsInDatesRange(target, lastWeekDates)) {
return getDatesWhenTargetInLastWeek(target, lastWeekDates) return getDatesWhenTargetInLastWeek(target, lastWeekDates)
} } else {
else {
return getDates(target, calendarDates, calendarConfig) return getDates(target, calendarDates, calendarConfig)
} }
} }
@ -162,44 +157,42 @@ function calculateFirstDateOfCurrentWeek(calendarData = {}) {
function calculateNextWeekDates(calendarData = {}) { function calculateNextWeekDates(calendarData = {}) {
let { curYear, curMonth } = calendarData let { curYear, curMonth } = calendarData
let calendarDates = [] let calendarDates = []
const lastDateInThisWeek = calculateLastDateOfCurrentWeek(calendarData) let lastDateInThisWeek = calculateLastDateOfCurrentWeek(calendarData)
const { year: LYear, month: LMonth } = lastDateInThisWeek const { year: LYear, month: LMonth } = lastDateInThisWeek
if (curYear !== LYear || curMonth !== LMonth) { if (curYear !== LYear || curMonth !== LMonth) {
calendarDates = dateUtil.calcDates(LYear, LMonth) calendarDates = dateUtil.calcDates(LYear, LMonth)
curYear = LYear curYear = LYear
curMonth = LMonth curMonth = LMonth
} } else {
else {
calendarDates = dateUtil.calcDates(curYear, curMonth) calendarDates = dateUtil.calcDates(curYear, curMonth)
} }
const lastDateInThisMonth = dateUtil.getDatesCountOfMonth(curYear, curMonth) const lastDateInThisMonth = dateUtil.getDatesCountOfMonth(curYear, curMonth)
const count = lastDateInThisMonth - lastDateInThisWeek.date const count = lastDateInThisMonth - lastDateInThisWeek.date
const lastDateIdx = calendarDates.findIndex( const lastDateIdx = calendarDates.findIndex(
date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(lastDateInThisWeek), date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(lastDateInThisWeek)
) )
const startIdx = lastDateIdx + 1 const startIdx = lastDateIdx + 1
if (count >= 7) { if (count >= 7) {
return { return {
dates: calendarDates.splice(startIdx, 7), dates: calendarDates.splice(startIdx, 7),
year: curYear, year: curYear,
month: curMonth, month: curMonth
} }
} } else {
else {
const nextMonth = dateUtil.getNextMonthInfo({ const nextMonth = dateUtil.getNextMonthInfo({
year: curYear, year: curYear,
month: curMonth, month: curMonth
}) })
const { year, month } = nextMonth || {} const { year, month } = nextMonth || {}
const calendarDatesOfNextMonth = dateUtil.calcDates(year, month) const calendarDatesOfNextMonth = dateUtil.calcDates(year, month)
const remainDatesOfThisMonth = calendarDates.splice(startIdx) const remainDatesOfThisMonth = calendarDates.splice(startIdx)
const patchDatesOfNextMonth = calendarDatesOfNextMonth.splice( const patchDatesOfNextMonth = calendarDatesOfNextMonth.splice(
0, 0,
7 - remainDatesOfThisMonth.length, 7 - remainDatesOfThisMonth.length
) )
return { return {
dates: [...remainDatesOfThisMonth, ...patchDatesOfNextMonth], dates: [...remainDatesOfThisMonth, ...patchDatesOfNextMonth],
...nextMonth, ...nextMonth
} }
} }
} }
@ -209,45 +202,43 @@ function calculateNextWeekDates(calendarData = {}) {
*/ */
function calculatePrevWeekDates(calendarData = {}) { function calculatePrevWeekDates(calendarData = {}) {
let { curYear, curMonth } = calendarData let { curYear, curMonth } = calendarData
const firstDateInThisWeek = calculateFirstDateOfCurrentWeek(calendarData) let firstDateInThisWeek = calculateFirstDateOfCurrentWeek(calendarData)
let calendarDates = [] let calendarDates = []
const { year: FYear, month: FMonth } = firstDateInThisWeek const { year: FYear, month: FMonth } = firstDateInThisWeek
if (curYear !== FYear || curMonth !== FMonth) { if (curYear !== FYear || curMonth !== FMonth) {
calendarDates = dateUtil.calcDates(FYear, FMonth) calendarDates = dateUtil.calcDates(FYear, FMonth)
curYear = FYear curYear = FYear
curMonth = FMonth curMonth = FMonth
} } else {
else {
calendarDates = dateUtil.calcDates(curYear, curMonth) calendarDates = dateUtil.calcDates(curYear, curMonth)
} }
const firstDateIdx = calendarDates.findIndex( const firstDateIdx = calendarDates.findIndex(
date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(firstDateInThisWeek), date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(firstDateInThisWeek)
) )
if (firstDateIdx - 7 >= 0) { if (firstDateIdx - 7 >= 0) {
const startIdx = firstDateIdx - 7 const startIdx = firstDateIdx - 7
return { return {
dates: calendarDates.splice(startIdx, 7), dates: calendarDates.splice(startIdx, 7),
year: curYear, year: curYear,
month: curMonth, month: curMonth
} }
} } else {
else {
const prevMonth = dateUtil.getPrevMonthInfo({ const prevMonth = dateUtil.getPrevMonthInfo({
year: curYear, year: curYear,
month: curMonth, month: curMonth
}) })
const { year, month } = prevMonth || {} const { year, month } = prevMonth || {}
const calendarDatesOfPrevMonth = dateUtil.calcDates(year, month) const calendarDatesOfPrevMonth = dateUtil.calcDates(year, month)
const remainDatesOfThisMonth = calendarDates.splice( const remainDatesOfThisMonth = calendarDates.splice(
0, 0,
firstDateInThisWeek.date - 1, firstDateInThisWeek.date - 1
) )
const patchDatesOfPrevMonth = calendarDatesOfPrevMonth.splice( const patchDatesOfPrevMonth = calendarDatesOfPrevMonth.splice(
-(7 - remainDatesOfThisMonth.length), -(7 - remainDatesOfThisMonth.length)
) )
return { return {
dates: [...patchDatesOfPrevMonth, ...remainDatesOfThisMonth], dates: [...patchDatesOfPrevMonth, ...remainDatesOfThisMonth],
...prevMonth, ...prevMonth
} }
} }
} }
@ -259,30 +250,30 @@ export default () => {
const { initializedWeekMode, selectedDates } = calendarData const { initializedWeekMode, selectedDates } = calendarData
if (calendarConfig.weekMode && !initializedWeekMode) { if (calendarConfig.weekMode && !initializedWeekMode) {
const { defaultDate } = calendarConfig const { defaultDate } = calendarConfig
const target const target =
= (selectedDates && selectedDates[0]) (selectedDates && selectedDates[0]) ||
|| (defaultDate && dateUtil.transformDateRow2Dict(defaultDate)) (defaultDate && dateUtil.transformDateRow2Dict(defaultDate)) ||
|| dateUtil.todayFMD() dateUtil.todayFMD()
const waitRenderData = this.methods( const waitRenderData = this.methods(
component, component
).__calcDatesWhenSwitchView('week', target) ).__calcDatesWhenSwitchView('week', target)
const { data, config } = waitRenderData || {} const { data, config } = waitRenderData || {}
const setSelectDates = this.methods( const setSelectDates = this.methods(
component, component
).__selectTargetDateWhenJump(target, data.dates, config) ).__selectTargetDateWhenJump(target, data.dates, config)
return { return {
calendarData: { calendarData: {
...data, ...data,
...setSelectDates, ...setSelectDates,
weeksCh: dateUtil.getWeekHeader(calendarConfig.firstDayOfWeek), weeksCh: dateUtil.getWeekHeader(calendarConfig.firstDayOfWeek),
initializedWeekMode: true, initializedWeekMode: true
}, },
calendarConfig, calendarConfig
} }
} }
return { return {
calendarData, calendarData,
calendarConfig, calendarConfig
} }
}, },
onSwitchCalendar(target = {}, calendarData = {}, component) { onSwitchCalendar(target = {}, calendarData = {}, component) {
@ -293,8 +284,7 @@ export default () => {
if (calendarConfig.weekMode) { if (calendarConfig.weekMode) {
if (direction === 'left') { if (direction === 'left') {
waitRenderData = calculateNextWeekDates(calendarData) waitRenderData = calculateNextWeekDates(calendarData)
} } else {
else {
waitRenderData = calculatePrevWeekDates(calendarData) waitRenderData = calculatePrevWeekDates(calendarData)
} }
const { dates, year, month } = waitRenderData const { dates, year, month } = waitRenderData
@ -302,7 +292,7 @@ export default () => {
...calendarData, ...calendarData,
dates, dates,
curYear: year || curYear, curYear: year || curYear,
curMonth: month || curMonth, curMonth: month || curMonth
} }
} }
return calendarData return calendarData
@ -314,8 +304,8 @@ export default () => {
const weekDates = dates.map((date, idx) => { const weekDates = dates.map((date, idx) => {
const tmp = { ...date } const tmp = { ...date }
tmp.id = idx tmp.id = idx
const isTarget const isTarget =
= dateUtil.toTimeStr(target) === dateUtil.toTimeStr(tmp) dateUtil.toTimeStr(target) === dateUtil.toTimeStr(tmp)
if (isTarget && !target.choosed && config.autoChoosedWhenJump) { if (isTarget && !target.choosed && config.autoChoosedWhenJump) {
tmp.choosed = true tmp.choosed = true
selectedDate = tmp selectedDate = tmp
@ -324,7 +314,7 @@ export default () => {
}) })
return { return {
dates: weekDates, dates: weekDates,
selectedDates: [selectedDate], selectedDates: [selectedDate]
} }
}, },
__calcDatesForWeekMode(target, config = {}, calendarData = {}) { __calcDatesForWeekMode(target, config = {}, calendarData = {}) {
@ -338,31 +328,31 @@ export default () => {
nextMonthGrids: null, nextMonthGrids: null,
dates: weekDates, dates: weekDates,
curYear: year, curYear: year,
curMonth: month, curMonth: month
}, },
config: { config: {
...config, ...config,
weekMode: true, weekMode: true
}, }
} }
}, },
__calcDatesForMonthMode(target, config = {}, calendarData = {}) { __calcDatesForMonthMode(target, config = {}, calendarData = {}) {
const { year, month } = target || {} const { year, month } = target || {}
const waitRenderData = calcJumpData({ const waitRenderData = calcJumpData({
dateInfo: target, dateInfo: target,
config, config
}) })
return { return {
data: { data: {
...calendarData, ...calendarData,
...waitRenderData, ...waitRenderData,
curYear: year, curYear: year,
curMonth: month, curMonth: month
}, },
config: { config: {
...config, ...config,
weekMode: false, weekMode: false
}, }
} }
}, },
/** /**
@ -379,20 +369,18 @@ export default () => {
selectedDates = [], selectedDates = [],
dates = [], dates = [],
curYear, curYear,
curMonth, curMonth
} = existCalendarData } = existCalendarData
const currentMonthSelected = selectedDates.filter( const currentMonthSelected = selectedDates.filter(
item => curYear === +item.year || curMonth === +item.month, item => curYear === +item.year || curMonth === +item.month
) )
let jumpTarget = {} let jumpTarget = {}
if (target) { if (target) {
jumpTarget = target jumpTarget = target
} } else {
else {
if (currentMonthSelected.length) { if (currentMonthSelected.length) {
jumpTarget = currentMonthSelected.pop() jumpTarget = currentMonthSelected.pop()
} } else {
else {
jumpTarget = dates[0] jumpTarget = dates[0]
} }
} }
@ -400,47 +388,45 @@ export default () => {
return this.methods(component).__calcDatesForWeekMode( return this.methods(component).__calcDatesForWeekMode(
jumpTarget, jumpTarget,
calendarConfig, calendarConfig,
existCalendarData, existCalendarData
) )
} } else {
else {
return this.methods(component).__calcDatesForMonthMode( return this.methods(component).__calcDatesForMonthMode(
jumpTarget, jumpTarget,
calendarConfig, calendarConfig,
existCalendarData, existCalendarData
) )
} }
}, },
weekModeJump: (dateInfo) => { weekModeJump: dateInfo => {
const target = dateInfo || dateUtil.todayFMD() const target = dateInfo || dateUtil.todayFMD()
const existCalendarData = getCalendarData('calendar', component) || {} const existCalendarData = getCalendarData('calendar', component) || {}
const waitRenderData = this.methods( const waitRenderData = this.methods(
component, component
).__calcDatesWhenSwitchView('week', target) ).__calcDatesWhenSwitchView('week', target)
const { data, config } = waitRenderData || {} const { data, config } = waitRenderData || {}
const setSelectDates = this.methods( const setSelectDates = this.methods(
component, component
).__selectTargetDateWhenJump(target, data.dates, config) ).__selectTargetDateWhenJump(target, data.dates, config)
return renderCalendar.call( return renderCalendar.call(
component, component,
{ {
...existCalendarData, ...existCalendarData,
...data, ...data,
...setSelectDates, ...setSelectDates
}, },
config, config
) )
}, },
switchView: (view, target) => { switchView: (view, target) => {
const waitRenderData = this.methods( const waitRenderData = this.methods(
component, component
).__calcDatesWhenSwitchView(view, target) ).__calcDatesWhenSwitchView(view, target)
const { data, config } = waitRenderData || {} const { data, config } = waitRenderData || {}
if (!data) if (!data) return logger.warn('当前状态不能切换为周视图')
return logger.warn('当前状态不能切换为周视图')
return renderCalendar.call(component, data, config) return renderCalendar.call(component, data, config)
}, }
} }
}, }
} }
} }

47
src/components/calendar/render.js

@ -1,30 +1,29 @@
import plugins from './plugins/index' import plugins from "./plugins/index";
import { getCalendarConfig } from './utils/index' import { getCalendarConfig } from "./utils/index";
/** /**
* 渲染日历 * 渲染日历
*/ */
export function renderCalendar(calendarData, calendarConfig) { export function renderCalendar(calendarData, calendarConfig) {
return new Promise((resolve) => { return new Promise((resolve) => {
const Component = this const Component = this;
if (Component.firstRender === void 0) { if (Component.firstRender === void 0) {
Component.firstRender = true Component.firstRender = true;
} } else {
else { Component.firstRender = false;
Component.firstRender = false
} }
const exitData = Component.data.calendar || {} const exitData = Component.data.calendar || {};
for (const plugin of plugins.installed) { for (let plugin of plugins.installed) {
const [, p] = plugin const [, p] = plugin;
if (typeof p.beforeRender === 'function') { if (typeof p.beforeRender === "function") {
const { calendarData: newData, calendarConfig: newConfig } const { calendarData: newData, calendarConfig: newConfig } =
= p.beforeRender( p.beforeRender(
{ ...exitData, ...calendarData }, { ...exitData, ...calendarData },
calendarConfig || getCalendarConfig(Component), calendarConfig || getCalendarConfig(Component),
Component, Component
) );
calendarData = newData calendarData = newData;
calendarConfig = newConfig calendarConfig = newConfig;
} }
} }
@ -38,13 +37,13 @@ export function renderCalendar(calendarData, calendarConfig) {
calendar: calendarData, calendar: calendarData,
config: calendarConfig, config: calendarConfig,
firstRender: Component.firstRender, firstRender: Component.firstRender,
} };
resolve(rst) resolve(rst);
if (Component.firstRender) { if (Component.firstRender) {
Component.triggerEvent('afterCalendarRender', rst) Component.triggerEvent("afterCalendarRender", rst);
Component.firstRender = false Component.firstRender = false;
} }
}, }
) );
}) });
} }

290
src/components/calendar/utils/index.js

@ -1,17 +1,16 @@
import Logger from './logger' import Logger from "./logger";
import WxData from './wxData' import WxData from "./wxData";
let systemInfo let systemInfo;
export function getSystemInfo() { export function getSystemInfo() {
if (systemInfo) if (systemInfo) return systemInfo;
return systemInfo systemInfo = wx.getSystemInfoSync();
systemInfo = wx.getSystemInfoSync() return systemInfo;
return systemInfo
} }
export function isIos() { export function isIos() {
const sys = getSystemInfo() const sys = getSystemInfo();
return /iphone|ios/i.test(sys.platform) return /iphone|ios/i.test(sys.platform);
} }
class Gesture { class Gesture {
@ -21,77 +20,69 @@ class Gesture {
* @returns {boolean} 布尔值 * @returns {boolean} 布尔值
*/ */
isLeft(gesture = {}, touche = {}) { isLeft(gesture = {}, touche = {}) {
const { startX, startY } = gesture const { startX, startY } = gesture;
const deltaX = touche.clientX - startX const deltaX = touche.clientX - startX;
const deltaY = touche.clientY - startY const deltaY = touche.clientY - startY;
if (deltaX < -60 && deltaY < 20 && deltaY > -20) { if (deltaX < -60 && deltaY < 20 && deltaY > -20) {
return true return true;
} } else {
else { return false;
return false
} }
} }
/** /**
* 右滑 * 右滑
* @param {object} e 事件对象 * @param {object} e 事件对象
* @returns {boolean} 布尔值 * @returns {boolean} 布尔值
*/ */
isRight(gesture = {}, touche = {}) { isRight(gesture = {}, touche = {}) {
const { startX, startY } = gesture const { startX, startY } = gesture;
const deltaX = touche.clientX - startX const deltaX = touche.clientX - startX;
const deltaY = touche.clientY - startY const deltaY = touche.clientY - startY;
if (deltaX > 60 && deltaY < 20 && deltaY > -20) { if (deltaX > 60 && deltaY < 20 && deltaY > -20) {
return true return true;
} } else {
else { return false;
return false
} }
} }
} }
class DateUtil { class DateUtil {
newDate(year, month, date) { newDate(year, month, date) {
let cur = `${+year}-${+month}-${+date}` let cur = `${+year}-${+month}-${+date}`;
if (isIos()) { if (isIos()) {
cur = `${+year}/${+month}/${+date}` cur = `${+year}/${+month}/${+date}`;
} }
return new Date(cur) return new Date(cur);
} }
/** /**
* 计算指定日期时间戳 * 计算指定日期时间戳
* @param {object} date * @param {object} date
*/ */
getTimeStamp(dateInfo) { getTimeStamp(dateInfo) {
if (typeof dateInfo === 'string') { if (typeof dateInfo === "string") {
dateInfo = this.transformDateRow2Dict(dateInfo) dateInfo = this.transformDateRow2Dict(dateInfo);
} }
if (Object.prototype.toString.call(dateInfo) !== '[object Object]') if (Object.prototype.toString.call(dateInfo) !== "[object Object]") return;
return const dateUtil = new DateUtil();
const dateUtil = new DateUtil() return dateUtil.newDate(dateInfo.year, dateInfo.month, dateInfo.date).getTime();
return dateUtil.newDate(dateInfo.year, dateInfo.month, dateInfo.date).getTime() }
}
/** /**
* 计算指定月份共多少天 * 计算指定月份共多少天
* @param {number} year 年份 * @param {number} year 年份
* @param {number} month 月份 * @param {number} month 月份
*/ */
getDatesCountOfMonth(year, month) { getDatesCountOfMonth(year, month) {
return new Date(Date.UTC(year, month, 0)).getUTCDate() return new Date(Date.UTC(year, month, 0)).getUTCDate();
} }
/** /**
* 计算指定月份第一天星期几 * 计算指定月份第一天星期几
* @param {number} year 年份 * @param {number} year 年份
* @param {number} month 月份 * @param {number} month 月份
*/ */
firstDayOfWeek(year, month) { firstDayOfWeek(year, month) {
return new Date(Date.UTC(year, month - 1, 1)).getUTCDay() return new Date(Date.UTC(year, month - 1, 1)).getUTCDay();
} }
/** /**
* 计算指定日期星期几 * 计算指定日期星期几
* @param {number} year 年份 * @param {number} year 年份
@ -99,68 +90,60 @@ class DateUtil {
* @param {number} date 日期 * @param {number} date 日期
*/ */
getDayOfWeek(year, month, date) { getDayOfWeek(year, month, date) {
return new Date(Date.UTC(year, month - 1, date)).getUTCDay() return new Date(Date.UTC(year, month - 1, date)).getUTCDay();
} }
todayFMD() { todayFMD() {
const _date = new Date() const _date = new Date();
const year = _date.getFullYear() const year = _date.getFullYear();
const month = _date.getMonth() + 1 const month = _date.getMonth() + 1;
const date = _date.getDate() const date = _date.getDate();
return { return {
year: +year, year: +year,
month: +month, month: +month,
date: +date, date: +date,
} };
} }
todayTimestamp() { todayTimestamp() {
const { year, month, date } = this.todayFMD() const { year, month, date } = this.todayFMD();
const timestamp = this.newDate(year, month, date).getTime() const timestamp = this.newDate(year, month, date).getTime();
return timestamp return timestamp;
} }
toTimeStr(dateInfo = {}) { toTimeStr(dateInfo = {}) {
return `${+dateInfo.year}-${+dateInfo.month}-${+dateInfo.date}` return `${+dateInfo.year}-${+dateInfo.month}-${+dateInfo.date}`;
} }
transformDateRow2Dict(dateStr) { transformDateRow2Dict(dateStr) {
if (typeof dateStr === 'string' && dateStr.includes('-')) { if (typeof dateStr === "string" && dateStr.includes("-")) {
const [year, month, date] = dateStr.split('-') const [year, month, date] = dateStr.split("-");
return this.tranformStr2NumOfDate({ return this.tranformStr2NumOfDate({
year, year,
month, month,
date, date,
}) });
} }
return {} return {};
} }
tranformStr2NumOfDate(date = {}) { tranformStr2NumOfDate(date = {}) {
const target = { ...date } const target = { ...date };
// 可能传入字符串 // 可能传入字符串
target.year = +target.year target.year = +target.year;
target.month = +target.month target.month = +target.month;
target.date = +target.date target.date = +target.date;
return target return target;
} }
sortDatesByTime(dates = [], sortType) { sortDatesByTime(dates = [], sortType) {
return dates.sort((a, b) => { return dates.sort((a, b) => {
const at = this.getTimeStamp(a) const at = this.getTimeStamp(a);
const bt = this.getTimeStamp(b) const bt = this.getTimeStamp(b);
if (at < bt && sortType !== 'desc') { if (at < bt && sortType !== "desc") {
return -1 return -1;
} } else {
else { return 1;
return 1
} }
}) });
} }
getPrevMonthInfo(date = {}) { getPrevMonthInfo(date = {}) {
const prevMonthInfo const prevMonthInfo =
= Number(date.month) > 1 Number(date.month) > 1
? { ? {
year: +date.year, year: +date.year,
month: Number(date.month) - 1, month: Number(date.month) - 1,
@ -168,13 +151,12 @@ class DateUtil {
: { : {
year: Number(date.year) - 1, year: Number(date.year) - 1,
month: 12, month: 12,
} };
return prevMonthInfo return prevMonthInfo;
} }
getNextMonthInfo(date = {}) { getNextMonthInfo(date = {}) {
const nextMonthInfo const nextMonthInfo =
= Number(date.month) < 12 Number(date.month) < 12
? { ? {
year: +date.year, year: +date.year,
month: Number(date.month) + 1, month: Number(date.month) + 1,
@ -182,34 +164,30 @@ class DateUtil {
: { : {
year: Number(date.year) + 1, year: Number(date.year) + 1,
month: 1, month: 1,
} };
return nextMonthInfo return nextMonthInfo;
} }
getPrevYearInfo(date = {}) { getPrevYearInfo(date = {}) {
return { return {
year: Number(date.year) - 1, year: Number(date.year) - 1,
month: +date.month, month: +date.month,
} };
} }
getNextYearInfo(date = {}) { getNextYearInfo(date = {}) {
return { return {
year: Number(date.year) + 1, year: Number(date.year) + 1,
month: +date.month, month: +date.month,
} };
} }
findDateIndexInArray(target, dates) { findDateIndexInArray(target, dates) {
return dates.findIndex(item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(target)) return dates.findIndex((item) => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(target));
} }
calcDates(year, month) { calcDates(year, month) {
const datesCount = this.getDatesCountOfMonth(year, month) const datesCount = this.getDatesCountOfMonth(year, month);
const dates = [] const dates = [];
const today = dateUtil.todayFMD() const today = dateUtil.todayFMD();
for (let i = 1; i <= datesCount; i++) { for (let i = 1; i <= datesCount; i++) {
const week = dateUtil.getDayOfWeek(+year, +month, i) const week = dateUtil.getDayOfWeek(+year, +month, i);
const date = { const date = {
year: +year, year: +year,
id: i - 1, id: i - 1,
@ -217,48 +195,45 @@ class DateUtil {
date: i, date: i,
week, week,
isToday: +today.year === +year && +today.month === +month && i === +today.date, isToday: +today.year === +year && +today.month === +month && i === +today.date,
} };
dates.push(date) dates.push(date);
} }
return dates return dates;
} }
/** /**
* 日期数组根据日期去重 * 日期数组根据日期去重
* @param {Array} array 数组 * @param {array} array 数组
*/ */
uniqueArrayByDate(array = []) { uniqueArrayByDate(array = []) {
const uniqueObject = {} let uniqueObject = {};
const uniqueArray = [] let uniqueArray = [];
array.forEach((item) => { array.forEach((item) => {
uniqueObject[dateUtil.toTimeStr(item)] = item uniqueObject[dateUtil.toTimeStr(item)] = item;
}) });
for (const i in uniqueObject) { for (let i in uniqueObject) {
uniqueArray.push(uniqueObject[i]) uniqueArray.push(uniqueObject[i]);
} }
return uniqueArray return uniqueArray;
} }
/** /**
* 筛选指定年月日期 * 筛选指定年月日期
* @param {object} target 指定年月 * @param {object} target 指定年月
* @param {Array} dates 待筛选日期 * @param {array} dates 待筛选日期
*/ */
filterDatesByYM(target, dates) { filterDatesByYM(target, dates) {
if (target) { if (target) {
const { year, month } = target const { year, month } = target;
const _dates = dates.filter(item => +item.year === +year && +item.month === +month) const _dates = dates.filter((item) => +item.year === +year && +item.month === +month);
return _dates return _dates;
} }
return dates return dates;
} }
getWeekHeader(firstDayOfWeek) { getWeekHeader(firstDayOfWeek) {
let weeksCh = ['日', '一', '二', '三', '四', '五', '六'] let weeksCh = ["日", "一", "二", "三", "四", "五", "六"];
if (firstDayOfWeek === 'Mon') { if (firstDayOfWeek === "Mon") {
weeksCh = ['一', '二', '三', '四', '五', '六', '日'] weeksCh = ["一", "二", "三", "四", "五", "六", "日"];
} }
return weeksCh return weeksCh;
} }
} }
@ -266,38 +241,35 @@ class DateUtil {
* 获取当前页面实例 * 获取当前页面实例
*/ */
export function getCurrentPage() { export function getCurrentPage() {
const pages = getCurrentPages() || [] const pages = getCurrentPages() || [];
const last = pages.length - 1 const last = pages.length - 1;
return pages[last] || {} return pages[last] || {};
} }
export function getComponentById(componentId) { export function getComponentById(componentId) {
const logger = new Logger() const logger = new Logger();
const page = getCurrentPage() || {} let page = getCurrentPage() || {};
if (page.selectComponent && typeof page.selectComponent === 'function') { if (page.selectComponent && typeof page.selectComponent === "function") {
if (componentId) { if (componentId) {
return page.selectComponent(componentId) return page.selectComponent(componentId);
} } else {
else { logger.warn("请传入组件ID");
logger.warn('请传入组件ID')
} }
} } else {
else { logger.warn("该基础库暂不支持多个小程序日历组件");
logger.warn('该基础库暂不支持多个小程序日历组件')
} }
} }
export const logger = new Logger() export const logger = new Logger();
export const calendarGesture = new Gesture() export const calendarGesture = new Gesture();
export const dateUtil = new DateUtil() export const dateUtil = new DateUtil();
export const getCalendarData = (key, component) => new WxData(component).getData(key) export const getCalendarData = (key, component) => new WxData(component).getData(key);
export const setCalendarData = (data, component) => new WxData(component).setData(data) export const setCalendarData = (data, component) => new WxData(component).setData(data);
export const getCalendarConfig = component => getCalendarData('config', component) export const getCalendarConfig = (component) => getCalendarData("config", component);
export function setCalendarConfig(config, component) { export const setCalendarConfig = (config, component) =>
return setCalendarData( setCalendarData(
{ {
config, config,
}, },
component, component,
) );
}

18
src/components/calendar/utils/logger.js

@ -1,25 +1,23 @@
export default class Logger { export default class Logger {
info(msg) { info(msg) {
console.log( console.log(
`%cInfo: %c${msg}`, '%cInfo: %c' + msg,
'color:#FF0080;font-weight:bold', 'color:#FF0080;font-weight:bold',
'color: #FF509B', 'color: #FF509B'
) )
} }
warn(msg) { warn(msg) {
console.log( console.log(
`%cWarn: %c${msg}`, '%cWarn: %c' + msg,
'color:#FF6600;font-weight:bold', 'color:#FF6600;font-weight:bold',
'color: #FF9933', 'color: #FF9933'
) )
} }
tips(msg) { tips(msg) {
console.log( console.log(
`%cTips: %c${msg}`, '%cTips: %c' + msg,
'color:#00B200;font-weight:bold', 'color:#00B200;font-weight:bold',
'color: #00CC33', 'color: #00CC33'
) )
} }
} }

17
src/components/calendar/utils/wxData.js

@ -1,28 +1,23 @@
class WxData { class WxData {
constructor(component) { constructor(component) {
this.Component = component this.Component = component
} }
getData(key) { getData(key) {
const data = this.Component.data const data = this.Component.data
if (!key) if (!key) return data
return data
if (key.includes('.')) { if (key.includes('.')) {
const keys = key.split('.') let keys = key.split('.')
const tmp = keys.reduce((prev, next) => { const tmp = keys.reduce((prev, next) => {
return prev[next] return prev[next]
}, data) }, data)
return tmp return tmp
} } else {
else {
return this.Component.data[key] return this.Component.data[key]
} }
} }
setData(data) { setData(data) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!data) if (!data) return reject('no data to set')
return reject('no data to set')
if (typeof data === 'object') { if (typeof data === 'object') {
this.Component.setData(data, () => { this.Component.setData(data, () => {
resolve(data) resolve(data)

148
src/components/customPoster/README.md

@ -28,28 +28,28 @@ const data = {
}, },
elements: [ elements: [
{ {
'id': 'circle-name', id: 'circle-name',
'desc': '圈名称', desc: '圈名称',
'type': 1, type: 1,
'text': '治疗讨论', text: '治疗讨论',
'font': '宋体', font: '宋体',
'font-size': '42', 'font-size': '42',
'color': '#FFFFFF', color: '#FFFFFF',
'single-line': true, 'single-line': true,
'halign': 'center', halign: 'center',
'top': '106', top: '106',
}, },
{ {
'id': 'master-name', id: 'master-name',
'desc': '专家名称', desc: '专家名称',
'type': 1, type: 1,
'text': '健康小贴士', text: '健康小贴士',
'font': '宋体', font: '宋体',
'font-size': '38', 'font-size': '38',
'color': '#FFFFFF', color: '#FFFFFF',
'single-line': true, 'single-line': true,
'halign': 'center', halign: 'center',
'top': '237', top: '237',
}, },
{ {
id: 'master-avatar', id: 'master-avatar',
@ -64,72 +64,72 @@ const data = {
top: '328', top: '328',
}, },
{ {
'id': 'note-content', id: 'note-content',
'desc': '动态内容', desc: '动态内容',
'type': 1, type: 1,
'text': '11月5日上海组织进口博览会CIIE大会,邀请大家来我们的展馆现场交流。', text: '11月5日上海组织进口博览会CIIE大会,邀请大家来我们的展馆现场交流。',
'font': '宋体', font: '宋体',
'font-size': '45', 'font-size': '45',
'color': '#18191A', color: '#18191A',
'width': '630', width: '630',
'height': '348', height: '348',
'left': '60', left: '60',
'top': '495', top: '495',
}, },
{ {
'id': 'note-title', id: 'note-title',
'desc': '长文标题', desc: '长文标题',
'type': 1, type: 1,
'text': '', text: '',
'font': '宋体', font: '宋体',
'font-size': '42', 'font-size': '42',
'color': '#18191A', color: '#18191A',
'width': '659', width: '659',
'height': '116', height: '116',
'left': '46', left: '46',
'top': '495', top: '495',
'font-weight': 'bold', 'font-weight': 'bold',
}, },
{ {
'id': 'note-summary', id: 'note-summary',
'desc': '长文摘要 ', desc: '长文摘要 ',
'type': 1, type: 1,
'text': '', text: '',
'font': '宋体', font: '宋体',
'font-size': '42', 'font-size': '42',
'color': '#18191A', color: '#18191A',
'width': '672', width: '672',
'height': '232', height: '232',
'left': '39', left: '39',
'top': '646', top: '646',
}, },
{ {
'id': 'note-more', id: 'note-more',
'desc': '还有', desc: '还有',
'type': 1, type: 1,
'text': '还有3条精彩附件>', text: '还有3条精彩附件>',
'font': '宋体', font: '宋体',
'font-size': '31', 'font-size': '31',
'color': '#666666', color: '#666666',
'single-line': true, 'single-line': true,
'width': '292', width: '292',
'height': '46', height: '46',
'left': '60', left: '60',
'top': '1024', top: '1024',
}, },
{ {
'id': 'scanText', id: 'scanText',
'desc': '扫描二维码查看详情', desc: '扫描二维码查看详情',
'type': 1, type: 1,
'text': '扫描二维码查看详情', text: '扫描二维码查看详情',
'font': '宋体', font: '宋体',
'font-size': '31', 'font-size': '31',
'color': '#666666', color: '#666666',
'single-line': true, 'single-line': true,
'width': '279', width: '279',
'height': '43', height: '43',
'left': '60', left: '60',
'top': '1087', top: '1087',
}, },
{ {
id: 'note-qrcode', id: 'note-qrcode',
@ -143,16 +143,16 @@ const data = {
top: '1012', top: '1012',
}, },
{ {
'id': 'brand', id: 'brand',
'desc': 'brand×华秉科技', desc: 'brand×华秉科技',
'type': 1, type: 1,
'text': '做企业数字化转型的亲密伙伴×华秉科技', text: '做企业数字化转型的亲密伙伴×华秉科技',
'font': '宋体', font: '宋体',
'font-size': '24', 'font-size': '24',
'color': '#B2B3B4', color: '#B2B3B4',
'single-line': true, 'single-line': true,
'halign': 'center', halign: 'center',
'top': '1192', top: '1192',
}, },
], ],
}, },

204
src/components/customPoster/index.js

@ -1,103 +1,101 @@
import Wxml2Canvas from './wxml2canvas/index.js' // 根据具体路径修改,node_modules会被忽略 import Wxml2Canvas from "./wxml2canvas/index.js"; // 根据具体路径修改,node_modules会被忽略
Component({ Component({
properties: { properties: {
params: { params: {
type: Object, type: Object,
observer(newVal, _olVal) { observer(newVal, _olVal) {
if (Object.keys(newVal).length > 0) { if (Object.keys(newVal).length > 0) {
this.paramsFormat(newVal) this.paramsFormat(newVal);
this.setData({ this.setData({
width: newVal.body.width, width: newVal.body.width,
height: newVal.body.height, height: newVal.body.height,
bgImg: newVal.body.bgImg, bgImg: newVal.body.bgImg,
elementsMp: newVal.elements, elementsMp: newVal.elements,
}) });
this.drawImage() this.drawImage1();
} }
}, },
}, },
}, },
data: { data: {
imgUrl: '', imgUrl: "",
width: '', width: "",
height: '', height: "",
imgheight: '', imgheight: "",
bgImg: '', bgImg: "",
elementsMp: [], elementsMp: [],
}, },
lifetimes: { lifetimes: {
attached() {}, attached() {},
}, },
methods: { methods: {
paramsFormat(params) { paramsFormat(params) {
params.elements.forEach((item) => { params.elements.forEach((item) => {
if (item.type === 0) { if (item.type === 0) {
// 图片居中 // 图片居中
if (item.halign === 'center') { if (item.halign === "center") {
item.left = (params.body.width - item.width) / 2 item.left = (params.body.width - item.width) / 2;
} }
} } else {
else { item.text = item.text.replace(/[\r\n]/g, "");
item.text = item.text.replace(/[\r\n]/g, '') // 文字居中(使文字标签宽度等于画布宽度,文字加上居中的className)
// 文字居中(使文字标签宽度等于画布宽度,文字加上居中的className) if (item.halign === "center") {
if (item.halign === 'center') { item.width = item.width || params.body.width;
item.width = item.width || params.body.width item.left = (params.body.width - item.width) / 2;
item.left = (params.body.width - item.width) / 2 }
} if (item.halign === "right") {
if (item.halign === 'right') { item.width = params.body.width;
item.width = params.body.width }
} if (item.id === "shareText" && item.text.length > 30) {
if (item.id === 'shareText' && item.text.length > 30) { item.text = item.text.slice(0, 30) + "...";
item.text = `${item.text.slice(0, 30)}...` }
} if (item.id === "note-title" && item.text.length > 28) {
if (item.id === 'note-title' && item.text.length > 28) { item.text = item.text.slice(0, 28) + "...";
item.text = `${item.text.slice(0, 28)}...` }
} if (item.id === "note-content" && item.text.length > 90) {
if (item.id === 'note-content' && item.text.length > 90) { item.text = item.text.slice(0, 90) + "...";
item.text = `${item.text.slice(0, 90)}...` }
} let len = params.elements.some((x) => x.id === "note-title" && x.text.length);
const len = params.elements.some(x => x.id === 'note-title' && x.text.length) if (len && item.id === "note-summary" && item.text.length > 62) {
if (len && item.id === 'note-summary' && item.text.length > 62) { item.text = item.text.slice(0, 62) + "...";
item.text = `${item.text.slice(0, 62)}...` } else if (item.id === "note-summary" && item.text.length > 76) {
} item.text = item.text.slice(0, 76) + "...";
else if (item.id === 'note-summary' && item.text.length > 76) { }
item.text = `${item.text.slice(0, 76)}...` }
} });
} },
}) drawImage1() {
}, let self = this;
drawImage() { this.drawImage1 = new Wxml2Canvas({
const self = this obj: self,
this.drawImage1 = new Wxml2Canvas({ width: this.data.width, // 宽, 以iphone6为基准,传具体数值,其它机型自动适配
obj: self, height: this.data.height, // 高
width: this.data.width, // 宽, 以iphone6为基准,传具体数值,其它机型自动适配 element: "canvas1",
height: this.data.height, // 高 background: "transparent",
element: 'canvas1', progress(percent) {},
background: 'transparent', finish(url) {
progress(percent) {}, self.setData({
finish(url) { imgUrl: url,
self.setData({ });
imgUrl: url, self.triggerEvent("finish", url);
}) },
self.triggerEvent('finish', url) error(res) {},
}, });
error(res) {},
}) let data = {
list: [
const data = { {
list: [ type: "wxml",
{ class: "#canvas-bill-body-mp .draw_canvas",
type: 'wxml', limit: "#canvas-bill-body-mp",
class: '#canvas-bill-body-mp .draw_canvas', x: 0,
limit: '#canvas-bill-body-mp', y: 0,
x: 0, },
y: 0, ],
}, };
],
} this.drawImage1.draw(data);
},
this.drawImage1.draw(data) },
}, });
},
})

1968
src/components/customPoster/wxml2canvas/index.js

File diff suppressed because it is too large Load Diff

148
src/components/customTable/README.md

@ -28,28 +28,28 @@ const data = {
}, },
elements: [ elements: [
{ {
'id': 'circle-name', id: 'circle-name',
'desc': '圈名称', desc: '圈名称',
'type': 1, type: 1,
'text': '治疗讨论', text: '治疗讨论',
'font': '宋体', font: '宋体',
'font-size': '42', 'font-size': '42',
'color': '#FFFFFF', color: '#FFFFFF',
'single-line': true, 'single-line': true,
'halign': 'center', halign: 'center',
'top': '106', top: '106',
}, },
{ {
'id': 'master-name', id: 'master-name',
'desc': '专家名称', desc: '专家名称',
'type': 1, type: 1,
'text': '健康小贴士', text: '健康小贴士',
'font': '宋体', font: '宋体',
'font-size': '38', 'font-size': '38',
'color': '#FFFFFF', color: '#FFFFFF',
'single-line': true, 'single-line': true,
'halign': 'center', halign: 'center',
'top': '237', top: '237',
}, },
{ {
id: 'master-avatar', id: 'master-avatar',
@ -64,72 +64,72 @@ const data = {
top: '328', top: '328',
}, },
{ {
'id': 'note-content', id: 'note-content',
'desc': '动态内容', desc: '动态内容',
'type': 1, type: 1,
'text': '11月5日上海组织进口博览会CIIE大会,邀请大家来我们的展馆现场交流。', text: '11月5日上海组织进口博览会CIIE大会,邀请大家来我们的展馆现场交流。',
'font': '宋体', font: '宋体',
'font-size': '45', 'font-size': '45',
'color': '#18191A', color: '#18191A',
'width': '630', width: '630',
'height': '348', height: '348',
'left': '60', left: '60',
'top': '495', top: '495',
}, },
{ {
'id': 'note-title', id: 'note-title',
'desc': '长文标题', desc: '长文标题',
'type': 1, type: 1,
'text': '', text: '',
'font': '宋体', font: '宋体',
'font-size': '42', 'font-size': '42',
'color': '#18191A', color: '#18191A',
'width': '659', width: '659',
'height': '116', height: '116',
'left': '46', left: '46',
'top': '495', top: '495',
'font-weight': 'bold', 'font-weight': 'bold',
}, },
{ {
'id': 'note-summary', id: 'note-summary',
'desc': '长文摘要 ', desc: '长文摘要 ',
'type': 1, type: 1,
'text': '', text: '',
'font': '宋体', font: '宋体',
'font-size': '42', 'font-size': '42',
'color': '#18191A', color: '#18191A',
'width': '672', width: '672',
'height': '232', height: '232',
'left': '39', left: '39',
'top': '646', top: '646',
}, },
{ {
'id': 'note-more', id: 'note-more',
'desc': '还有', desc: '还有',
'type': 1, type: 1,
'text': '还有3条精彩附件>', text: '还有3条精彩附件>',
'font': '宋体', font: '宋体',
'font-size': '31', 'font-size': '31',
'color': '#666666', color: '#666666',
'single-line': true, 'single-line': true,
'width': '292', width: '292',
'height': '46', height: '46',
'left': '60', left: '60',
'top': '1024', top: '1024',
}, },
{ {
'id': 'scanText', id: 'scanText',
'desc': '扫描二维码查看详情', desc: '扫描二维码查看详情',
'type': 1, type: 1,
'text': '扫描二维码查看详情', text: '扫描二维码查看详情',
'font': '宋体', font: '宋体',
'font-size': '31', 'font-size': '31',
'color': '#666666', color: '#666666',
'single-line': true, 'single-line': true,
'width': '279', width: '279',
'height': '43', height: '43',
'left': '60', left: '60',
'top': '1087', top: '1087',
}, },
{ {
id: 'note-qrcode', id: 'note-qrcode',
@ -143,16 +143,16 @@ const data = {
top: '1012', top: '1012',
}, },
{ {
'id': 'brand', id: 'brand',
'desc': 'brand×华秉科技', desc: 'brand×华秉科技',
'type': 1, type: 1,
'text': '做企业数字化转型的亲密伙伴×华秉科技', text: '做企业数字化转型的亲密伙伴×华秉科技',
'font': '宋体', font: '宋体',
'font-size': '24', 'font-size': '24',
'color': '#B2B3B4', color: '#B2B3B4',
'single-line': true, 'single-line': true,
'halign': 'center', halign: 'center',
'top': '1192', top: '1192',
}, },
], ],
}, },

203
src/components/customTable/index.js

@ -1,6 +1,5 @@
import Wxml2Canvas from './wxml2canvas/index.js' const app = getApp();
import Wxml2Canvas from "./wxml2canvas/index.js"; // 根据具体路径修改,node_modules会被忽略
const app = getApp() // 根据具体路径修改,node_modules会被忽略
Component({ Component({
properties: { properties: {
@ -8,193 +7,193 @@ Component({
type: Object, type: Object,
observer(newVal, _olVal) { observer(newVal, _olVal) {
if (Object.keys(newVal).length > 0) { if (Object.keys(newVal).length > 0) {
this.drawImage1() this.drawImage1();
} }
}, },
}, },
}, },
data: { data: {
imageUrl: app.globalData.imageUrl, imageUrl: app.globalData.imageUrl,
imgUrl: '', imgUrl: "",
width: '626', width: "626",
height: '980', height: "980",
imgheight: '', imgheight: "",
bgImg: '', bgImg: "",
elementsMp: [], elementsMp: [],
tableData: [ tableData: [
{ {
title: '说话', title: "说话",
key: 'TalkingScore', key: "TalkingScore",
list: [ list: [
{ {
id: '1', id: "1",
title: '正常', title: "正常",
}, },
{ {
id: '2', id: "2",
title: '间或有点含糊或有鼻音', title: "间或有点含糊或有鼻音",
}, },
{ {
id: '3', id: "3",
title: '经常含糊不清或者有鼻音,但是别人还能听懂', title: "经常含糊不清或者有鼻音,但是别人还能听懂",
}, },
{ {
id: '4', id: "4",
title: '别人听不太懂', title: "别人听不太懂",
}, },
], ],
}, },
{ {
title: '咀嚼', title: "咀嚼",
key: 'ChewScore', key: "ChewScore",
list: [ list: [
{ {
id: '1', id: "1",
title: '正常', title: "正常",
}, },
{ {
id: '2', id: "2",
title: '咀嚼固体食物会感到疲劳', title: "咀嚼固体食物会感到疲劳",
}, },
{ {
id: '3', id: "3",
title: '咀嚼松软食物会感到疲劳', title: "咀嚼松软食物会感到疲劳",
}, },
{ {
id: '4', id: "4",
title: '使用喂食管进食,如鼻胃管胃肠管等', title: "使用喂食管进食,如鼻胃管胃肠管等",
}, },
], ],
}, },
{ {
title: '吞咽', title: "吞咽",
key: 'SwallowScore', key: "SwallowScore",
list: [ list: [
{ {
id: '1', id: "1",
title: '正常', title: "正常",
}, },
{ {
id: '2', id: "2",
title: '偶尔会噎到', title: "偶尔会噎到",
}, },
{ {
id: '3', id: "3",
title: '经常会噎到,因而需要改变饮食习惯', title: "经常会噎到,因而需要改变饮食习惯",
}, },
{ {
id: '4', id: "4",
title: '使用喂食管进食,如鼻胃管胃肠管等', title: "使用喂食管进食,如鼻胃管胃肠管等",
}, },
], ],
}, },
{ {
title: '呼吸', title: "呼吸",
key: 'BreathScore', key: "BreathScore",
list: [ list: [
{ {
id: '1', id: "1",
title: '正常', title: "正常",
}, },
{ {
id: '2', id: "2",
title: '劳累后感到气促或呼吸不畅', title: "劳累后感到气促或呼吸不畅",
}, },
{ {
id: '3', id: "3",
title: '静止时感到气促或呼吸不畅', title: "静止时感到气促或呼吸不畅",
}, },
{ {
id: '4', id: "4",
title: '依赖呼吸机', title: "依赖呼吸机",
}, },
], ],
}, },
{ {
title: '刷牙梳头能力受损', title: "刷牙梳头能力受损",
key: 'BrushTeethAndCombHairScore', key: "BrushTeethAndCombHairScore",
list: [ list: [
{ {
id: '1', id: "1",
title: '正常', title: "正常",
}, },
{ {
id: '2', id: "2",
title: '需要多费些力气但是不需要停下来', title: "需要多费些力气但是不需要停下来",
}, },
{ {
id: '3', id: "3",
title: '需要停下来休息才能完成', title: "需要停下来休息才能完成",
}, },
{ {
id: '4', id: "4",
title: '无法自己完成', title: "无法自己完成",
}, },
], ],
}, },
{ {
title: '从椅子上起身能力受损', title: "从椅子上起身能力受损",
key: 'GetUpFromChairScore', key: "GetUpFromChairScore",
list: [ list: [
{ {
id: '1', id: "1",
title: '正常', title: "正常",
}, },
{ {
id: '2', id: "2",
title: '轻度受损,有时需要用手帮忙', title: "轻度受损,有时需要用手帮忙",
}, },
{ {
id: '3', id: "3",
title: '中度受损,总是需要用手帮忙', title: "中度受损,总是需要用手帮忙",
}, },
{ {
id: '4', id: "4",
title: '严重受损,需要他人帮助', title: "严重受损,需要他人帮助",
}, },
], ],
}, },
{ {
title: '复视/重影', title: "复视/重影",
key: 'DoubleVisionScore', key: "DoubleVisionScore",
list: [ list: [
{ {
id: '1', id: "1",
title: '正常', title: "正常",
}, },
{ {
id: '2', id: "2",
title: '有,但不是每天', title: "有,但不是每天",
}, },
{ {
id: '3', id: "3",
title: '每天,但不是持续一整天', title: "每天,但不是持续一整天",
}, },
{ {
id: '4', id: "4",
title: '持续有', title: "持续有",
}, },
], ],
}, },
{ {
title: '眼睑下垂', title: "眼睑下垂",
key: 'DroopyEyelidsScore', key: "DroopyEyelidsScore",
list: [ list: [
{ {
id: '1', id: "1",
title: '正常', title: "正常",
}, },
{ {
id: '2', id: "2",
title: '有,但不是每天', title: "有,但不是每天",
}, },
{ {
id: '3', id: "3",
title: '每天,但不是持续一整天', title: "每天,但不是持续一整天",
}, },
{ {
id: '4', id: "4",
title: '持续有', title: "持续有",
}, },
], ],
}, },
@ -205,37 +204,37 @@ Component({
}, },
methods: { methods: {
drawImage1() { drawImage1() {
const self = this let self = this;
// destZoom: 10, // destZoom: 10,
this.drawImage1 = new Wxml2Canvas({ this.drawImage1 = new Wxml2Canvas({
obj: self, obj: self,
width: this.data.width, // 宽, 以iphone6为基准,传具体数值,其它机型自动适配 width: this.data.width, // 宽, 以iphone6为基准,传具体数值,其它机型自动适配
height: this.data.height, // 高 height: this.data.height, // 高
element: 'canvas1', element: "canvas1",
background: '#ffffff', background: "#ffffff",
progress(_percent) {}, progress(_percent) {},
finish(url) { finish(url) {
self.setData({ self.setData({
imgUrl: url, imgUrl: url,
}) });
self.triggerEvent('finish', url) self.triggerEvent("finish", url);
}, },
error(_res) {}, error(_res) {},
}) });
const data = { let data = {
list: [ list: [
{ {
type: 'wxml', type: "wxml",
class: '#canvas-bill-body-mp .draw_canvas', class: "#canvas-bill-body-mp .draw_canvas",
limit: '#canvas-bill-body-mp', limit: "#canvas-bill-body-mp",
x: 0, x: 0,
y: 0, y: 0,
}, },
], ],
} };
this.drawImage1.draw(data) this.drawImage1.draw(data);
}, },
}, },
}) });

1966
src/components/customTable/wxml2canvas/index.js

File diff suppressed because it is too large Load Diff

216
src/components/ec-canvas/ec-canvas.js

@ -1,32 +1,31 @@
import WxCanvas from './wx-canvas' import WxCanvas from './wx-canvas';
let ctx let ctx;
let echarts let echarts;
function compareVersion(v1, v2) { function compareVersion(v1, v2) {
v1 = v1.split('.') v1 = v1.split('.');
v2 = v2.split('.') v2 = v2.split('.');
const len = Math.max(v1.length, v2.length) const len = Math.max(v1.length, v2.length);
while (v1.length < len) { while (v1.length < len) {
v1.push('0') v1.push('0');
} }
while (v2.length < len) { while (v2.length < len) {
v2.push('0') v2.push('0');
} }
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
const num1 = Number.parseInt(v1[i]) const num1 = parseInt(v1[i]);
const num2 = Number.parseInt(v2[i]) const num2 = parseInt(v2[i]);
if (num1 > num2) { if (num1 > num2) {
return 1 return 1;
} } else if (num1 < num2) {
else if (num1 < num2) { return -1;
return -1
} }
} }
return 0 return 0;
} }
Component({ Component({
@ -50,230 +49,223 @@ Component({
isUseNewCanvas: false, isUseNewCanvas: false,
}, },
async ready() { ready: async function () {
echarts = await require.async('../../gift/compontnts/echart/echarts.js') echarts = await require.async('../../gift/compontnts/echart/echarts.js');
// Disable prograssive because drawImage doesn't support DOM as parameter // Disable prograssive because drawImage doesn't support DOM as parameter
// See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html // See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
echarts.registerPreprocessor((option) => { echarts.registerPreprocessor((option) => {
if (option && option.series) { if (option && option.series) {
if (option.series.length > 0) { if (option.series.length > 0) {
option.series.forEach((series) => { option.series.forEach((series) => {
series.progressive = 0 series.progressive = 0;
}) });
} } else if (typeof option.series === 'object') {
else if (typeof option.series === 'object') { option.series.progressive = 0;
option.series.progressive = 0
} }
} }
}) });
if (!this.data.ec) { if (!this.data.ec) {
console.warn( console.warn(
'组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" ' '组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" ' +
+ 'canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>', 'canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>',
) );
return return;
} }
if (!this.data.ec.lazyLoad) { if (!this.data.ec.lazyLoad) {
this.init() this.init();
} }
}, },
methods: { methods: {
async init(callback) { init: async function (callback) {
echarts = await require.async('../../gift/compontnts/echart/echarts.js') echarts = await require.async('../../gift/compontnts/echart/echarts.js');
const version = wx.getSystemInfoSync().SDKVersion const version = wx.getSystemInfoSync().SDKVersion;
const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0 const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0;
const forceUseOldCanvas = this.data.forceUseOldCanvas const forceUseOldCanvas = this.data.forceUseOldCanvas;
const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
this.setData({ isUseNewCanvas }) this.setData({ isUseNewCanvas });
if (forceUseOldCanvas && canUseNewCanvas) { if (forceUseOldCanvas && canUseNewCanvas) {
console.warn('开发者强制使用旧canvas,建议关闭') console.warn('开发者强制使用旧canvas,建议关闭');
} }
if (isUseNewCanvas) { if (isUseNewCanvas) {
// console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>'); // console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>');
// 2.9.0 可以使用 <canvas type="2d"></canvas> // 2.9.0 可以使用 <canvas type="2d"></canvas>
this.initByNewWay(callback) this.initByNewWay(callback);
} } else {
else { const isValid = compareVersion(version, '1.9.91') >= 0;
const isValid = compareVersion(version, '1.9.91') >= 0
if (!isValid) { if (!isValid) {
console.error( console.error(
'微信基础库版本过低,需大于等于 1.9.91。' '微信基础库版本过低,需大于等于 1.9.91。' +
+ '参见:https://github.com/ecomfe/echarts-for-weixin' '参见:https://github.com/ecomfe/echarts-for-weixin' +
+ '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82', '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82',
) );
} return;
else { } else {
console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能') console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能');
this.initByOldWay(callback) this.initByOldWay(callback);
} }
} }
}, },
initByOldWay(callback) { initByOldWay(callback) {
// 1.9.91 <= version < 2.9.0:原来的方式初始化 // 1.9.91 <= version < 2.9.0:原来的方式初始化
ctx = wx.createCanvasContext(this.data.canvasId, this) ctx = wx.createCanvasContext(this.data.canvasId, this);
const canvas = new WxCanvas(ctx, this.data.canvasId, false) const canvas = new WxCanvas(ctx, this.data.canvasId, false);
echarts.setCanvasCreator(() => { echarts.setCanvasCreator(() => {
return canvas return canvas;
}) });
// const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr // const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
const canvasDpr = 1 const canvasDpr = 1;
const query = wx.createSelectorQuery().in(this) var query = wx.createSelectorQuery().in(this);
query query
.select('.ec-canvas') .select('.ec-canvas')
.boundingClientRect((res) => { .boundingClientRect((res) => {
if (typeof callback === 'function') { if (typeof callback === 'function') {
this.chart = callback(canvas, res.width, res.height, canvasDpr) this.chart = callback(canvas, res.width, res.height, canvasDpr);
} } else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
else if (this.data.ec && typeof this.data.ec.onInit === 'function') { this.chart = this.data.ec.onInit(canvas, res.width, res.height, canvasDpr);
this.chart = this.data.ec.onInit(canvas, res.width, res.height, canvasDpr) } else {
}
else {
this.triggerEvent('init', { this.triggerEvent('init', {
canvas, canvas: canvas,
width: res.width, width: res.width,
height: res.height, height: res.height,
canvasDpr, // 增加了dpr,可方便外面echarts.init canvasDpr: canvasDpr, // 增加了dpr,可方便外面echarts.init
}) });
} }
}) })
.exec() .exec();
}, },
initByNewWay(callback) { initByNewWay(callback) {
// version >= 2.9.0:使用新的方式初始化 // version >= 2.9.0:使用新的方式初始化
const query = wx.createSelectorQuery().in(this) const query = wx.createSelectorQuery().in(this);
query query
.select('.ec-canvas') .select('.ec-canvas')
.fields({ node: true, size: true }) .fields({ node: true, size: true })
.exec((res) => { .exec((res) => {
const canvasNode = res[0].node const canvasNode = res[0].node;
this.canvasNode = canvasNode this.canvasNode = canvasNode;
const canvasDpr = wx.getSystemInfoSync().pixelRatio const canvasDpr = wx.getSystemInfoSync().pixelRatio;
const canvasWidth = res[0].width const canvasWidth = res[0].width;
const canvasHeight = res[0].height const canvasHeight = res[0].height;
const ctx = canvasNode.getContext('2d') const ctx = canvasNode.getContext('2d');
const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode) const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode);
echarts.setCanvasCreator(() => { echarts.setCanvasCreator(() => {
return canvas return canvas;
}) });
if (typeof callback === 'function') { if (typeof callback === 'function') {
this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr) this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr);
} } else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
else if (this.data.ec && typeof this.data.ec.onInit === 'function') { this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr);
this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr) } else {
}
else {
this.triggerEvent('init', { this.triggerEvent('init', {
canvas, canvas: canvas,
width: canvasWidth, width: canvasWidth,
height: canvasHeight, height: canvasHeight,
dpr: canvasDpr, dpr: canvasDpr,
}) });
} }
}) });
}, },
canvasToTempFilePath(opt) { canvasToTempFilePath(opt) {
if (this.data.isUseNewCanvas) { if (this.data.isUseNewCanvas) {
// 新版 // 新版
const query = wx.createSelectorQuery().in(this) const query = wx.createSelectorQuery().in(this);
query query
.select('.ec-canvas') .select('.ec-canvas')
.fields({ node: true, size: true }) .fields({ node: true, size: true })
.exec((res) => { .exec((res) => {
const canvasNode = res[0].node const canvasNode = res[0].node;
opt.canvas = canvasNode opt.canvas = canvasNode;
wx.canvasToTempFilePath(opt) wx.canvasToTempFilePath(opt);
}) });
} } else {
else {
// 旧的 // 旧的
if (!opt.canvasId) { if (!opt.canvasId) {
opt.canvasId = this.data.canvasId opt.canvasId = this.data.canvasId;
} }
ctx.draw(true, () => { ctx.draw(true, () => {
wx.canvasToTempFilePath(opt, this) wx.canvasToTempFilePath(opt, this);
}) });
} }
}, },
touchStart(e) { touchStart(e) {
if (this.chart && e.touches.length > 0) { if (this.chart && e.touches.length > 0) {
const touch = e.touches[0] var touch = e.touches[0];
const handler = this.chart.getZr().handler var handler = this.chart.getZr().handler;
handler.dispatch('mousedown', { handler.dispatch('mousedown', {
zrX: touch.x, zrX: touch.x,
zrY: touch.y, zrY: touch.y,
preventDefault: () => {}, preventDefault: () => {},
stopImmediatePropagation: () => {}, stopImmediatePropagation: () => {},
stopPropagation: () => {}, stopPropagation: () => {},
}) });
handler.dispatch('mousemove', { handler.dispatch('mousemove', {
zrX: touch.x, zrX: touch.x,
zrY: touch.y, zrY: touch.y,
preventDefault: () => {}, preventDefault: () => {},
stopImmediatePropagation: () => {}, stopImmediatePropagation: () => {},
stopPropagation: () => {}, stopPropagation: () => {},
}) });
handler.processGesture(wrapTouch(e), 'start') handler.processGesture(wrapTouch(e), 'start');
} }
}, },
touchMove(e) { touchMove(e) {
if (this.chart && e.touches.length > 0) { if (this.chart && e.touches.length > 0) {
const touch = e.touches[0] var touch = e.touches[0];
const handler = this.chart.getZr().handler var handler = this.chart.getZr().handler;
handler.dispatch('mousemove', { handler.dispatch('mousemove', {
zrX: touch.x, zrX: touch.x,
zrY: touch.y, zrY: touch.y,
preventDefault: () => {}, preventDefault: () => {},
stopImmediatePropagation: () => {}, stopImmediatePropagation: () => {},
stopPropagation: () => {}, stopPropagation: () => {},
}) });
handler.processGesture(wrapTouch(e), 'change') handler.processGesture(wrapTouch(e), 'change');
} }
}, },
touchEnd(e) { touchEnd(e) {
if (this.chart) { if (this.chart) {
const touch = e.changedTouches ? e.changedTouches[0] : {} const touch = e.changedTouches ? e.changedTouches[0] : {};
const handler = this.chart.getZr().handler var handler = this.chart.getZr().handler;
handler.dispatch('mouseup', { handler.dispatch('mouseup', {
zrX: touch.x, zrX: touch.x,
zrY: touch.y, zrY: touch.y,
preventDefault: () => {}, preventDefault: () => {},
stopImmediatePropagation: () => {}, stopImmediatePropagation: () => {},
stopPropagation: () => {}, stopPropagation: () => {},
}) });
handler.dispatch('click', { handler.dispatch('click', {
zrX: touch.x, zrX: touch.x,
zrY: touch.y, zrY: touch.y,
preventDefault: () => {}, preventDefault: () => {},
stopImmediatePropagation: () => {}, stopImmediatePropagation: () => {},
stopPropagation: () => {}, stopPropagation: () => {},
}) });
handler.processGesture(wrapTouch(e), 'end') handler.processGesture(wrapTouch(e), 'end');
} }
}, },
}, },
}) });
function wrapTouch(event) { function wrapTouch(event) {
for (let i = 0; i < event.touches.length; ++i) { for (let i = 0; i < event.touches.length; ++i) {
const touch = event.touches[i] const touch = event.touches[i];
touch.offsetX = touch.x touch.offsetX = touch.x;
touch.offsetY = touch.y touch.offsetY = touch.y;
} }
return event return event;
} }

2
src/components/ec-canvas/ec-canvas.json

@ -1,4 +1,4 @@
{ {
"component": true, "component": true,
"usingComponents": {} "usingComponents": {}
} }

66
src/components/ec-canvas/wx-canvas.js

@ -1,24 +1,24 @@
export default class WxCanvas { export default class WxCanvas {
constructor(ctx, canvasId, isNew, canvasNode) { constructor(ctx, canvasId, isNew, canvasNode) {
this.ctx = ctx this.ctx = ctx;
this.canvasId = canvasId this.canvasId = canvasId;
this.chart = null this.chart = null;
this.isNew = isNew this.isNew = isNew
if (isNew) { if (isNew) {
this.canvasNode = canvasNode this.canvasNode = canvasNode;
} }
else { else {
this._initStyle(ctx) this._initStyle(ctx);
} }
// this._initCanvas(zrender, ctx); // this._initCanvas(zrender, ctx);
this._initEvent() this._initEvent();
} }
getContext(contextType) { getContext(contextType) {
if (contextType === '2d') { if (contextType === '2d') {
return this.ctx return this.ctx;
} }
} }
@ -30,7 +30,7 @@ export default class WxCanvas {
// } // }
setChart(chart) { setChart(chart) {
this.chart = chart this.chart = chart;
} }
addEventListener() { addEventListener() {
@ -47,58 +47,55 @@ export default class WxCanvas {
_initCanvas(zrender, ctx) { _initCanvas(zrender, ctx) {
zrender.util.getContext = function () { zrender.util.getContext = function () {
return ctx return ctx;
} };
zrender.util.$override('measureText', (text, font) => { zrender.util.$override('measureText', function (text, font) {
ctx.font = font || '12px sans-serif' ctx.font = font || '12px sans-serif';
return ctx.measureText(text) return ctx.measureText(text);
}) });
} }
_initStyle(ctx) { _initStyle(ctx) {
ctx.createRadialGradient = () => { ctx.createRadialGradient = () => {
return ctx.createCircularGradient(arguments) return ctx.createCircularGradient(arguments);
} };
} }
_initEvent() { _initEvent() {
this.event = {} this.event = {};
const eventNames = [{ const eventNames = [{
wxName: 'touchStart', wxName: 'touchStart',
ecName: 'mousedown', ecName: 'mousedown'
}, { }, {
wxName: 'touchMove', wxName: 'touchMove',
ecName: 'mousemove', ecName: 'mousemove'
}, { }, {
wxName: 'touchEnd', wxName: 'touchEnd',
ecName: 'mouseup', ecName: 'mouseup'
}, { }, {
wxName: 'touchEnd', wxName: 'touchEnd',
ecName: 'click', ecName: 'click'
}] }];
eventNames.forEach((name) => { eventNames.forEach(name => {
this.event[name.wxName] = (e) => { this.event[name.wxName] = e => {
const touch = e.touches[0] const touch = e.touches[0];
this.chart.getZr().handler.dispatch(name.ecName, { this.chart.getZr().handler.dispatch(name.ecName, {
zrX: name.wxName === 'tap' ? touch.clientX : touch.x, zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
zrY: name.wxName === 'tap' ? touch.clientY : touch.y, zrY: name.wxName === 'tap' ? touch.clientY : touch.y,
preventDefault: () => {}, preventDefault: () => {},
stopImmediatePropagation: () => {}, stopImmediatePropagation: () => {},
stopPropagation: () => {}, stopPropagation: () => {}
}) });
} };
}) });
} }
set width(w) { set width(w) {
if (this.canvasNode) if (this.canvasNode) this.canvasNode.width = w
this.canvasNode.width = w
} }
set height(h) { set height(h) {
if (this.canvasNode) if (this.canvasNode) this.canvasNode.height = h
this.canvasNode.height = h
} }
get width() { get width() {
@ -106,7 +103,6 @@ export default class WxCanvas {
return this.canvasNode.width return this.canvasNode.width
return 0 return 0
} }
get height() { get height() {
if (this.canvasNode) if (this.canvasNode)
return this.canvasNode.height return this.canvasNode.height

149
src/components/freeAudio/index.js

@ -1,4 +1,5 @@
const app = getApp() const app = getApp();
import dayjs from "dayjs";
Component({ Component({
behaviors: [], behaviors: [],
properties: { properties: {
@ -6,19 +7,19 @@ Component({
type: Object, type: Object,
observer(val) { observer(val) {
if (this.audioContext) { if (this.audioContext) {
const { play } = this.data const { play } = this.data;
if (play) { if (play) {
this.audioContext.pause() this.audioContext.pause();
this.setData({ this.setData({
play: false, play: false,
progress: 0, progress: 0,
time: '00', time: "00",
}) });
} }
this.audioContext.destroy() this.audioContext.destroy();
} }
if (val) { if (val) {
this.audioAddEventListener(val) this.audioAddEventListener(val);
} }
}, },
}, },
@ -26,8 +27,8 @@ Component({
data: { data: {
Timestamp: app.globalData.Timestamp, Timestamp: app.globalData.Timestamp,
progress: 0, progress: 0,
time: '00', time: "00",
duration: '00', duration: "00",
play: false, play: false,
loading: true, loading: true,
@ -40,138 +41,136 @@ Component({
moved() {}, moved() {},
detached() { detached() {
if (this.audioContext) { if (this.audioContext) {
const { play } = this.data const { play } = this.data;
if (play) { if (play) {
this.audioContext.pause() this.audioContext.pause();
} }
this.audioContext.destroy() this.audioContext.destroy();
} }
this.audioAddEventListener = null this.audioAddEventListener = null;
this.setData({ this.setData({
play: false, play: false,
progress: 0, progress: 0,
time: '00', time: "00",
}) });
}, },
}, },
pageLifetimes: { pageLifetimes: {
// 组件所在页面的生命周期函数 // 组件所在页面的生命周期函数
show() {}, show: function () {},
hide() { hide: function () {
const { play } = this.data const { play } = this.data;
if (play) { if (play) {
this.audioContext.pause() this.audioContext.pause();
} }
}, },
resize() {}, resize: function () {},
}, },
methods: { methods: {
togglePlay() { togglePlay() {
const { play, loading } = this.data const { play, loading } = this.data;
if (loading) { if (loading) {
wx.showToast({ wx.showToast({
title: '音频加载中', title: "音频加载中",
icon: 'none', icon: "none",
}) });
return return;
} }
if (play) { if (play) {
this.audioContext.pause() this.audioContext.pause();
} } else {
else { this.audioContext.play();
this.audioContext.play()
} }
}, },
formatTime(time) { formatTime(time) {
const m = Number.parseInt(time / 60) let m = parseInt(time / 60);
const s = Number.parseInt(time % 60) let s = parseInt(time % 60);
return `${this.towNum(m)}:${this.towNum(s)}` return this.towNum(m) + ":" + this.towNum(s);
}, },
towNum(num) { towNum(num) {
if (num >= 10) { if (num >= 10) {
return num return num;
} } else {
else { return "0" + num;
return `0${num}`
} }
}, },
audioAddEventListener(val) { audioAddEventListener(val) {
const that = this const that = this;
this.setData({ this.setData({
duration: this.formatTime(val.size), duration: this.formatTime(val.size),
}) });
that.audioContext = wx.createInnerAudioContext() that.audioContext = wx.createInnerAudioContext();
that.audioContext.src = val.url that.audioContext.src = val.url;
that.setData({ that.setData({
loading: false, loading: false,
}) });
that.audioContext.onError(({ errCode, ...reset }) => { that.audioContext.onError(({ errCode, ...reset }) => {
console.log('reset: ', reset) console.log("reset: ", reset);
console.log('errCode: ', errCode) console.log("errCode: ", errCode);
if (errCode === 10004 || errCode == 10001 || errCode == -1) { if (errCode === 10004 || errCode == 10001 || errCode == -1) {
that.audioContext.destroy() that.audioContext.destroy();
that.setData({ that.setData({
loading: true, loading: true,
}) });
setTimeout(() => { setTimeout(() => {
that.audioAddEventListener(val) that.audioAddEventListener(val);
}, 300) }, 300);
} }
}) });
that.audioContext.onPlay(() => { that.audioContext.onPlay(() => {
that.setData({ that.setData({
play: true, play: true,
}) });
}) });
that.audioContext.onPause(() => { that.audioContext.onPause(() => {
console.log(1111111) console.log(1111111);
that.setData({ that.setData({
play: false, play: false,
}) });
}) });
that.audioContext.onEnded(() => { that.audioContext.onEnded(() => {
that.audioContext.seek(0) that.audioContext.seek(0);
that.setData({ that.setData({
play: false, play: false,
progress: 0, progress: 0,
time: '00', time: "00",
}) });
}) });
that.audioContext.onTimeUpdate(() => { that.audioContext.onTimeUpdate(() => {
const duration = that.audioContext.duration || 0 const duration = that.audioContext.duration || 0;
const currentTime = that.audioContext.currentTime || 0 const currentTime = that.audioContext.currentTime || 0;
const progress = (currentTime / duration) * 100 const progress = (currentTime / duration) * 100;
if (duration == Infinity) { if (duration == Infinity) {
return return;
} }
that.setData({ that.setData({
play: true, play: true,
duration: that.formatTime(duration), duration: that.formatTime(duration),
time: that.formatTime(currentTime), time: that.formatTime(currentTime),
}) });
if (that.data.progressimg) { if (that.data.progressimg) {
this.setData({ this.setData({
progress, progress: progress,
}) });
} }
}) });
}, },
handleAuthChangeimg() { handleAuthChangeimg() {
console.log(11111) console.log(11111);
this.setData({ this.setData({
progressimg: false, progressimg: false,
}) });
}, },
handleAuthChange(e) { handleAuthChange(e) {
console.log(22222222222) console.log(22222222222);
const { duration } = this.data let { duration } = this.data;
const secods = this.audioContext.duration || duration.split(':')[0] * 60 + duration.split(':')[1] * 1 const secods = this.audioContext.duration || duration.split(":")[0] * 60 + duration.split(":")[1] * 1;
const progress = e.detail.value const progress = e.detail.value;
const seek = ((secods / 100) * progress).toFixed(3) * 1 let seek = ((secods / 100) * progress).toFixed(3) * 1;
this.audioContext.seek(seek) this.audioContext.seek(seek);
this.setData({ this.setData({
progressimg: true, progressimg: true,
}) });
}, },
}, },
}) });

8
src/components/image-merge/index.json

@ -1,8 +0,0 @@
{
"component": true,
"usingComponents": {
"van-button": "@vant/weapp/button/index",
"van-icon": "@vant/weapp/icon/index",
"van-toast": "@vant/weapp/toast/index"
}
}

7
src/components/image-merge/index.scss

@ -1,7 +0,0 @@
.merge-canvas {
position: fixed;
left: -9999px;
top: -9999px;
width: 1px;
height: 1px;
}

200
src/components/image-merge/index.ts

@ -1,200 +0,0 @@
interface ImageItem {
src: string
time?: string
}
Component({
properties: {
id: {
type: String,
value: 'default',
},
},
data: {
imageList: [] as ImageItem[],
mergedImage: '',
isLoading: false,
},
methods: {
mergeImages(imageList: ImageItem[]) {
if (this.data.isLoading) {
return
}
if (!imageList || imageList.length < 2) {
wx.showToast({ title: '至少需要2张图片才能拼接', icon: 'none' })
return
}
wx.showLoading({ title: '拼接中...', mask: true })
this.setData({ isLoading: true, imageList })
this.validateImages(imageList)
.then(() => this.drawImagesOnCanvas())
.then((mergedImage) => {
wx.hideLoading()
this.setData({
mergedImage,
isLoading: false,
})
this.triggerEvent('save', { tempFilePath: mergedImage })
wx.previewImage({
urls: [mergedImage],
current: mergedImage,
showmenu: true,
})
})
.catch((error) => {
wx.hideLoading()
console.error('拼接失败:', error)
this.setData({ isLoading: false })
wx.showToast({ title: error.message || '拼接失败,请重试', icon: 'none' })
this.triggerEvent('error', { reason: error.message })
})
},
validateImages(imageList: ImageItem[]): Promise<void> {
return Promise.all(
imageList.map(
(item, index) =>
new Promise<void>((resolve, reject) => {
wx.getImageInfo({
src: item.src,
success: () => resolve(),
fail: () => reject(new Error(`${index + 1}张图片加载失败`)),
})
}),
),
)
},
formatTime(date: Date): string {
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
const hours = String(date.getHours()).padStart(2, '0')
const minutes = String(date.getMinutes()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}`
},
drawImagesOnCanvas(): Promise<string> {
return new Promise((resolve, reject) => {
const { imageList, id } = this.data
const query = this.createSelectorQuery()
query
.in(this)
.select(`#mergeCanvas-${id}`)
.fields({ node: true, size: true })
.exec((res) => {
if (!res[0]) {
reject(new Error('Canvas not found'))
return
}
const canvas = res[0].node
const ctx = canvas.getContext('2d')
Promise.all(imageList.map(item => this.getImageInfo(item.src)))
.then((imageInfos) => {
const targetWidth = 750
const pixelRatio = wx.getWindowInfo().pixelRatio
const canvasWidth = Math.floor((targetWidth * pixelRatio) / 2)
const fontScale = pixelRatio / 2
let totalHeight = 0
const scaledHeights: number[] = []
imageInfos.forEach((info) => {
const scale = canvasWidth / info.width
const scaledHeight = Math.floor(info.height * scale)
scaledHeights.push(scaledHeight)
totalHeight += scaledHeight
})
canvas.width = canvasWidth
canvas.height = totalHeight
let currentY = 0
let loadedCount = 0
// 预计算每张图片的 Y 偏移,确保顺序正确
const yPositions: number[] = []
scaledHeights.forEach((h, i) => {
yPositions.push(currentY)
currentY += h
})
loadedCount = 0
currentY = 0
imageInfos.forEach((info, index) => {
const img = canvas.createImage()
img.src = info.path
img.onload = () => {
ctx.drawImage(img, 0, yPositions[index], canvasWidth, scaledHeights[index])
const timeText = imageList[index].time || this.formatTime(new Date())
const padding = 20 * fontScale
const fontSize = Math.round(28 * fontScale)
const textY = yPositions[index] + 40 * fontScale
ctx.font = `bold ${fontSize}px sans-serif`
ctx.textBaseline = 'middle'
const textMetrics = ctx.measureText(timeText)
const bgPaddingH = 16 * fontScale
const bgPaddingV = 10 * fontScale
const bgH = fontSize + bgPaddingV * 2
const bgX = padding - bgPaddingH
const bgY = textY - bgH / 2
const bgW = textMetrics.width + bgPaddingH * 2
ctx.fillStyle = 'rgba(0, 0, 0, 0.45)'
ctx.fillRect(bgX, bgY, bgW, bgH)
ctx.fillStyle = '#ffffff'
ctx.textAlign = 'left'
ctx.fillText(timeText, padding, textY)
if (index === imageInfos.length - 1) {
const lastImageBottom = yPositions[index] + scaledHeights[index]
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'
ctx.font = `${Math.round(24 * fontScale)}px sans-serif`
ctx.textAlign = 'right'
ctx.fillText('由-TED关爱小助手-小程序生成', canvasWidth - 20 * fontScale, lastImageBottom - 20 * fontScale)
}
loadedCount++
if (loadedCount === imageInfos.length) {
wx.canvasToTempFilePath({
canvas,
success: (result) => {
resolve(result.tempFilePath)
},
fail: reject,
})
}
}
img.onerror = () => {
reject(new Error(`Failed to load image: ${info.path}`))
}
})
})
.catch(reject)
})
})
},
getImageInfo(src: string): Promise<WechatMiniprogram.GetImageInfoSuccessCallbackResult> {
return new Promise((resolve, reject) => {
wx.getImageInfo({
src,
success: resolve,
fail: reject,
})
})
},
},
})

1
src/components/image-merge/index.wxml

@ -1 +0,0 @@
<canvas type="2d" id="mergeCanvas-{{id}}" class="merge-canvas"></canvas>

6
src/components/loginNavbar/index.ts

@ -1,4 +1,4 @@
const app = getApp<IAppOption>() const app = getApp<IAppOption>();
Component({ Component({
properties: { properties: {
@ -17,7 +17,7 @@ Component({
}, },
methods: { methods: {
handleBack() { handleBack() {
this.triggerEvent('back') this.triggerEvent("back");
}, },
}, },
}) });

6
src/components/navbar/index.ts

@ -32,7 +32,7 @@ Component({
*/ */
data: { data: {
imageUrl: app.globalData.imageUrl, imageUrl: app.globalData.imageUrl,
Timestamp: app.globalData.Timestamp, Timestamp:app.globalData.Timestamp
}, },
/** /**
@ -40,8 +40,8 @@ Component({
*/ */
methods: { methods: {
onClickLeft() { onClickLeft() {
if (this.data.back) if(this.data.back)
this.triggerEvent('clickLeft', {}, {}) this.triggerEvent('clickLeft', {}, {})
}, },
onClickRight() { onClickRight() {
this.triggerEvent('clickRight', {}, {}) this.triggerEvent('clickRight', {}, {})

7
src/components/noteImagePreview/index.json

@ -1,7 +0,0 @@
{
"component": true,
"usingComponents": {
"van-icon": "@vant/weapp/icon/index",
"navbar": "/components/navbar/index"
}
}

157
src/components/noteImagePreview/index.scss

@ -1,157 +0,0 @@
.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;
position: relative;
.order {
position: absolute;
left: 50%;
transform: translate(-50%, 0 );
padding: 18rpx 32rpx;
font-size: 40rpx;
font-weight: bold;
text-align: center;
color: #211d2e;
border-radius: 94rpx;
display: inline-flex;
align-items: baseline;
background-color: #fff;
z-index: 10;
white-space: nowrap;
.num {
margin-left: 20rpx;
}
.m-num {
font-size: 28rpx;
}
}
.preview-image {
display: block;
width: 100%;
height: 100%;
}
// 左右切换按钮
.nav-btn {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 72rpx;
height: 72rpx;
border-radius: 50%;
background: rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
&:active:not(.disabled) {
background: rgba(0, 0, 0, 0.6);
}
&.disabled {
opacity: 0.3;
}
&.nav-prev {
left: 24rpx;
}
&.nav-next {
right: 24rpx;
}
}
}
// 页码指示器
.indicator {
position: absolute;
left: 0;
right: 0;
text-align: center;
color: #fff;
font-size: 28rpx;
z-index: 10;
bottom: calc(168rpx + env(safe-area-inset-bottom));
.current {
font-weight: 600;
}
.separator {
margin: 0 8rpx;
opacity: 0.6;
}
.total {
opacity: 0.6;
}
}
// 底部操作栏
.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;
}
}
}

157
src/components/noteImagePreview/index.ts

@ -1,157 +0,0 @@
Component({
properties: {
visible: {
type: Boolean,
value: false,
observer(newVal) {
this.setData({ visible: newVal })
},
},
src: {
type: String,
value: '',
},
images: {
type: Array,
value: [],
},
currentIndex: {
type: Number,
value: 0,
},
photoLabels: {
type: Array,
value: [] as { name: string; index: number; total: number }[],
},
showActions: {
type: Boolean,
value: true,
},
},
data: {
visible: false,
src: '',
images: [] as string[],
currentIndex: 0,
navHeight: wx.getSystemInfoSync().statusBarHeight + 44,
startX: 0,
startY: 0,
},
observers: {
'currentIndex, images': function (currentIndex: number, images: string[]) {
if (images && images.length > 0 && images[currentIndex]) {
this.setData({
src: images[currentIndex],
})
}
},
},
methods: {
// 返回/关闭
handleBack() {
this.triggerEvent('close')
},
// 更多操作
handleMore() {
this.triggerEvent('more')
},
// 预览/查看
handlePreview(src) {
if (src) {
this.setData({
visible: true,
src,
})
}
},
handleHidePreview() {
this.setData({
visible: false,
src: '',
})
},
// 上一张
handlePrev() {
const { currentIndex, images } = this.data
if (currentIndex > 0) {
const newIndex = currentIndex - 1
this.setData({
currentIndex: newIndex,
})
this.triggerEvent('change', { index: newIndex })
}
},
// 下一张
handleNext() {
const { currentIndex, images } = this.data
if (currentIndex < images.length - 1) {
const newIndex = currentIndex + 1
this.setData({
currentIndex: newIndex,
})
this.triggerEvent('change', { index: newIndex })
}
},
// 滑动手势 - 开始
handleTouchStart(e: any) {
this.setData({
startX: e.touches[0].clientX,
startY: e.touches[0].clientY,
})
},
// 滑动手势 - 结束
handleTouchEnd(e: any) {
const { startX, startY, currentIndex, images } = this.data
const endX = e.changedTouches[0].clientX
const endY = e.changedTouches[0].clientY
const diffX = endX - startX
const diffY = endY - startY
// 水平滑动距离大于50且大于垂直滑动距离时才触发切换
if (Math.abs(diffX) > 50 && Math.abs(diffX) > Math.abs(diffY)) {
if (diffX > 0) {
// 右滑 - 上一张
if (currentIndex > 0) {
this.handlePrev()
}
} else {
// 左滑 - 下一张
if (currentIndex < images.length - 1) {
this.handleNext()
}
}
}
},
// 删除
handleDelete() {
wx.showModal({
title: '提示',
content: '确定要删除这张照片吗?',
confirmColor: '#8c75d0',
cancelColor: '#141515',
success: (res) => {
if (res.confirm) {
this.handleHidePreview()
this.triggerEvent('delete')
}
},
})
},
// 重拍
handleRetake() {
this.handleHidePreview()
this.triggerEvent('retake')
},
},
})

31
src/components/noteImagePreview/index.wxml

@ -1,31 +0,0 @@
<view class="preview-container {{visible ? 'show' : ''}}">
<navbar fixed title="" custom-style="background:transparent" bind:click-left="handleBack">
<van-icon name="arrow-left" slot="left" size="18px" color="#fff" bind:tap="handleBack" />
</navbar>
<view class="image-wrapper" style="padding-top:{{navHeight}}px;" bindtouchstart="handleTouchStart" bindtouchend="handleTouchEnd">
<view class="order" wx:if="{{photoLabels[currentIndex]}}" style="top:{{navHeight * 0.5}}px;">
{{photoLabels[currentIndex].name}}
<!-- <view class="num">{{photoLabels[currentIndex].index}}</view> -->
<!-- <view class="m-num">/{{photoLabels[currentIndex].total}}</view> -->
</view>
<view class="nav-btn nav-prev {{currentIndex <= 0 ? 'disabled' : ''}}" wx:if="{{images.length > 1}}" bindtap="handlePrev">
<van-icon name="arrow-left" size="20px" color="{{currentIndex <= 0 ? '#666' : '#fff'}}" />
</view>
<image class="preview-image" src="{{src}}" mode="aspectFit" />
<view class="nav-btn nav-next {{currentIndex >= images.length - 1 ? 'disabled' : ''}}" wx:if="{{images.length > 1}}" bindtap="handleNext">
<van-icon name="arrow" size="20px" color="{{currentIndex >= images.length - 1 ? '#666' : '#fff'}}" />
</view>
</view>
<view class="indicator" wx:if="{{images.length > 1}}">
<text class="current">{{currentIndex + 1}}</text>
<text class="separator">/</text>
<text class="total">{{images.length}}</text>
</view>
<view class="action-bar" wx:if="{{showActions}}">
<view class="btn btn-delete" bindtap="handleDelete">删除</view>
<view class="btn btn-retake" bindtap="handleRetake">重拍</view>
</view>
</view>

6
src/components/pageNavbar/index.ts

@ -1,4 +1,4 @@
const app = getApp<IAppOption>() const app = getApp<IAppOption>();
Component({ Component({
properties: { properties: {
@ -17,7 +17,7 @@ Component({
}, },
methods: { methods: {
handleBack() { handleBack() {
wx.navigateBack() wx.navigateBack();
}, },
}, },
}) });

40
src/components/patient-tab-bar/index.scss

@ -1,46 +1,6 @@
/* custom-tab-bar/index.wxss */ /* custom-tab-bar/index.wxss */
.tab-custom-item {
position: relative;
flex: 1;
z-index: 1;
.circle {
display: block;
margin: 0 auto;
margin-top: -53rpx;
width: 100rpx;
height: 100rpx;
border-radius: 50%;
border: 3px solid #fff;
background: linear-gradient(0deg, #e98ff8 0%, #b073ff 100%);
display: flex;
align-items: center;
justify-content: center;
.icon {
width: 60rpx;
height: 60rpx;
}
}
.name {
font-size: 26rpx;
color: rgba(105, 104, 110, 1);
text-align: center;
&.active {
color: rgba(33, 29, 46, 1);
}
}
.tip-card {
position: absolute;
top: -30rpx;
left: 50%;
width: 390rpx;
height: 230rpx;
transform: translate(-50%, -100%);
}
}
.tab-item { .tab-item {
flex: 1;
.icon { .icon {
width: 48rpx; width: 48rpx;
height: 48rpx; height: 48rpx;

16
src/components/patient-tab-bar/index.ts

@ -1,5 +1,4 @@
import { getCurrentPageUrl } from '@/utils/util' import { getCurrentPageUrl } from '@/utils/util'
const app = getApp() const app = getApp()
Component({ Component({
@ -22,11 +21,6 @@ Component({
iconActive: 'tab-active2', iconActive: 'tab-active2',
}, },
{ {
pagePath: '/patient/pages/note/index',
text: '突眼日记',
custom: true,
},
{
pagePath: '/patient/pages/live/index', pagePath: '/patient/pages/live/index',
text: '大咖说', text: '大咖说',
icon: 'tab5', icon: 'tab5',
@ -54,7 +48,7 @@ Component({
}) })
const pagePath = getCurrentPageUrl() const pagePath = getCurrentPageUrl()
const active = this.data.list.findIndex(item => item.pagePath === pagePath) const active = this.data.list.findIndex((item) => item.pagePath === pagePath)
this.setData({ this.setData({
active, active,
}) })
@ -78,14 +72,8 @@ Component({
handleNav(e) { handleNav(e) {
const { index } = e.currentTarget.dataset const { index } = e.currentTarget.dataset
const { list } = this.data const { list } = this.data
const { pagePath, custom } = list[index] const pagePath = list[index].pagePath
app.globalData.BeginnerCardId = '' app.globalData.BeginnerCardId = ''
if (custom) {
wx.navigateTo({
url: pagePath,
})
return
}
wx.reLaunch({ wx.reLaunch({
url: pagePath, url: pagePath,
}) })

7
src/components/patient-tab-bar/index.wxml

@ -1,13 +1,6 @@
<van-tabbar active="{{ active }}" active-color="#CF5375" bind:change="onChange" inactive-color="#CCCCCC"> <van-tabbar active="{{ active }}" active-color="#CF5375" bind:change="onChange" inactive-color="#CCCCCC">
<block wx:for="{{list}}" wx:key="*this"> <block wx:for="{{list}}" wx:key="*this">
<view class="tab-custom-item" wx:if="{{item.custom}}" bind:tap="handleNav" data-index="{{index}}">
<view class="circle">
<image class="icon" src="{{imageUrl}}icon142.png?t={{Timestamp}}"></image>
</view>
<view class="name">突眼日记</view>
</view>
<van-tabbar-item <van-tabbar-item
wx:else
class="tab-item" class="tab-item"
bind:tap="handleNav" bind:tap="handleNav"
data-index="{{index}}" data-index="{{index}}"

10
src/components/pickerArea/index.scss

@ -41,7 +41,7 @@
padding: 18rpx 30rpx; padding: 18rpx 30rpx;
box-shadow: 0rpx 4rpx 12rpx 0rpx rgba(0, 0, 0, 0.11); box-shadow: 0rpx 4rpx 12rpx 0rpx rgba(0, 0, 0, 0.11);
border-radius: 12rpx 12rpx 12rpx 12rpx; border-radius: 12rpx 12rpx 12rpx 12rpx;
border: 2rpx solid #b982ff; border: 2rpx solid #e04775;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@ -69,7 +69,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: linear-gradient(197deg, #ffbcf9 0%, #b982ff 100%); background: #e04775;
border-radius: 12rpx 12rpx 12rpx 12rpx; border-radius: 12rpx 12rpx 12rpx 12rpx;
} }
} }
@ -91,7 +91,7 @@
background: #f7f8f9; background: #f7f8f9;
&.active { &.active {
color: #fff; color: #fff;
background-color: #b982ff; background-color: rgba(224, 71, 117, 1);
} }
} }
} }
@ -118,9 +118,9 @@
height: 36rpx; height: 36rpx;
} }
&.active { &.active {
color: #b982ff; color: rgba(224, 71, 117, 1);
.word { .word {
color: #b982ff; color: rgba(224, 71, 117, 1);
} }
} }
} }

76
src/components/pickerArea/index.ts

@ -1,4 +1,4 @@
const app = getApp<IAppOption>() const app = getApp<IAppOption>();
Component({ Component({
properties: { properties: {
@ -22,14 +22,10 @@ Component({
type: String, type: String,
value: '', value: '',
}, },
required: {
type: Boolean,
value: false,
},
}, },
observers: { observers: {
show(newVal: boolean) { show(newVal: boolean) {
this.triggerEvent('show', newVal) this.triggerEvent('show', newVal);
}, },
}, },
data: { data: {
@ -221,7 +217,6 @@ Component({
handleShow() { handleShow() {
this.setData({ this.setData({
show: true, show: true,
active: 0,
ProvinceName: this.data.pname || '', ProvinceName: this.data.pname || '',
ProvinceId: this.data.pid || '', ProvinceId: this.data.pid || '',
CityName: this.data.cname || '', CityName: this.data.cname || '',
@ -229,8 +224,8 @@ Component({
scrollIntoView0: this.data.pid || '', scrollIntoView0: this.data.pid || '',
scrollIntoView1: this.data.cid || '', scrollIntoView1: this.data.cid || '',
}) });
this.getArea() this.getArea();
}, },
getArea() { getArea() {
wx.ajax({ wx.ajax({
@ -240,95 +235,78 @@ Component({
}).then((res) => { }).then((res) => {
this.setData({ this.setData({
area: res, area: res,
}) });
this.getRangeList() this.getRangeList();
}) });
}, },
handleItem(e: any) { handleItem(e: any) {
const { code, name } = e.currentTarget.dataset const { code, name } = e.currentTarget.dataset;
this.setData({ this.setData({
ProvinceId: code, ProvinceId: code,
ProvinceName: name, ProvinceName: name,
CityId: '', CityId: '',
CityName: '', CityName: '',
}) });
this.getRangeList() this.getRangeList();
}, },
handleChangeCity(e: any) { handleChangeCity(e: any) {
const { code, name } = e.currentTarget.dataset const { code, name } = e.currentTarget.dataset;
this.setData({ this.setData({
CityId: code, CityId: code,
CityName: name, CityName: name,
}) });
}, },
handleShare() { handleShare() {
if (this.data.required) {
if (!this.data.ProvinceId) {
wx.showToast({
icon: 'none',
title: '请选择省份',
})
return
}
if (!this.data.CityId) {
wx.showToast({
icon: 'none',
title: '请选择城市',
})
return
}
}
this.setData({ this.setData({
show: false, show: false,
}) });
this.triggerEvent('ok', { this.triggerEvent('ok', {
ProvinceName: this.data.ProvinceName, ProvinceName: this.data.ProvinceName,
ProvinceId: this.data.ProvinceId, ProvinceId: this.data.ProvinceId,
CityName: this.data.CityName, CityName: this.data.CityName,
CityId: this.data.CityId, CityId: this.data.CityId,
}) });
}, },
handleSelect(e) { handleSelect(e) {
const { id } = e.currentTarget.dataset const { id } = e.currentTarget.dataset;
this.setData({ this.setData({
word: id, word: id,
scrollIntoView0: id, scrollIntoView0: id,
}) });
}, },
getRangeList() { getRangeList() {
const { area, ProvinceId } = this.data const { area, ProvinceId } = this.data;
if (!ProvinceId) if (!ProvinceId) return;
return const range = area.filter((item: any) => item.value == ProvinceId)[0].children;
const range = area.filter((item: any) => item.value == ProvinceId)[0].children
this.setData({ this.setData({
range, range,
active: 1, active: 1,
scrollIntoView0: '', scrollIntoView0: '',
scrollIntoView1: `id${this.data.CityId}`, scrollIntoView1: `id${this.data.CityId}`,
}) });
}, },
handleProvince() { handleProvince() {
this.setData({ this.setData({
active: 0, active: 0,
scrollIntoView0: this.data.word || `id${this.data.ProvinceId}`, scrollIntoView0: this.data.word || `id${this.data.ProvinceId}`,
scrollIntoView1: '', scrollIntoView1: '',
}) });
}, },
handleCity() { handleCity() {
const { ProvinceId } = this.data const { ProvinceId } = this.data;
if (!ProvinceId) { if (!ProvinceId) {
wx.showToast({ wx.showToast({
title: '请先选择省份', title: '请先选择省份',
icon: 'none', icon: 'none',
}) });
return return;
} }
this.getRangeList() this.getRangeList();
}, },
handleClose() { handleClose() {
this.setData({ this.setData({
show: false, show: false,
}) });
}, },
}, },
}) });

7
src/components/pickerArea/index.wxml

@ -4,8 +4,7 @@
<view class="popup"> <view class="popup">
<van-icon catch:tap="handleClose" class="close" name="cross" /> <van-icon catch:tap="handleClose" class="close" name="cross" />
<view class="p-header"> <view class="p-header">
<view class="title" wx:if="{{active===1}}">选择您的地区</view> <view class="title">选择省份和地区</view>
<view class="title" wx:else>选择您的省份</view>
<!-- <view class="tip">对方打开后自动定位此地区</view> --> <!-- <view class="tip">对方打开后自动定位此地区</view> -->
<view class="area"> <view class="area">
<view class="item" bind:tap="handleProvince"> <view class="item" bind:tap="handleProvince">
@ -37,7 +36,7 @@
data-name="{{item.label}}" data-name="{{item.label}}"
> >
<view class="left">{{item.label}}</view> <view class="left">{{item.label}}</view>
<image wx:if="{{item.value === CityId}}" class="icon" src="{{imageUrl}}icon102.png?t={{Timestamp}}"></image> <image wx:if="{{item.value === CityId}}" class="icon" src="{{imageUrl}}icon7.png?t={{Timestamp}}"></image>
</view> </view>
</scroll-view> </scroll-view>
</block> </block>
@ -77,7 +76,7 @@
<image <image
wx:if="{{item.code=== ProvinceId}}" wx:if="{{item.code=== ProvinceId}}"
class="icon" class="icon"
src="{{imageUrl}}icon102.png?t={{Timestamp}}" src="{{imageUrl}}icon7.png?t={{Timestamp}}"
></image> ></image>
</view> </view>
</block> </block>

511
src/components/popup/index.scss

@ -129,19 +129,10 @@
.popup6 { .popup6 {
width: 590rpx; width: 590rpx;
height: 880rpx; height: 880rpx;
position: relative;
.p-img { .p-img {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.code {
position: absolute;
top: 350rpx;
left: 50%;
transform: translateX(-50%);
width: 290rpx;
height: 290rpx;
}
} }
.popup7 { .popup7 {
@ -155,19 +146,19 @@
} }
.contaienr { .contaienr {
margin-top: -80rpx; margin-top: -80rpx;
padding: 122rpx 0 0; padding: 96rpx 0 0;
width: 540rpx; width: 540rpx;
border-radius: 24rpx; border-radius: 24rpx;
box-sizing: border-box; box-sizing: border-box;
background: linear-gradient(353deg, #ffffff 0%, #f5eeff 100%); background: linear-gradient(353deg, #ffffff 0%, #f5eeff 100%);
box-shadow: inset 0rpx -1rpx 0rpx 0rpx #e5e6eb; box-shadow: inset 0rpx -1rpx 0rpx 0rpx #e5e6eb;
.content { .content {
font-size: 36rpx; font-size: 28rpx;
color: #adacb2; color: #adacb2;
text-align: center; text-align: center;
} }
.footer { .footer {
margin-top: 66rpx; margin-top: 40rpx;
border-top: 1px solid #e5e6eb; border-top: 1px solid #e5e6eb;
display: flex; display: flex;
.sure, .sure,
@ -196,7 +187,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.code { .code{
position: absolute; position: absolute;
top: 372rpx; top: 372rpx;
left: 50%; left: 50%;
@ -207,500 +198,6 @@
} }
} }
.popup9 {
padding: 32rpx;
width: 530rpx;
height: 452rpx;
box-sizing: border-box;
background-color: #fff;
text-align: center;
.icon {
width: 128rpx;
height: 128rpx;
}
.title {
margin-top: 24rpx;
font-size: 38rpx;
color: #211d2e;
font-weight: bold;
line-height: 56rpx;
}
.btn {
margin: 36rpx auto 0;
width: 418rpx;
height: 88rpx;
line-height: 88rpx;
font-size: 32rpx;
color: #ffffff;
background: linear-gradient(197deg, #ffbcf9 0%, #b982ff 100%);
border-radius: 100rpx 100rpx 100rpx 100rpx;
}
}
.popup10,
.popup11 {
padding: 48rpx 50rpx 48rpx;
width: 650rpx;
box-sizing: border-box;
background-color: #fff;
border-radius: 24rpx;
.title {
margin-top: 24rpx;
font-size: 40rpx;
color: #211d2e;
font-weight: bold;
line-height: 56rpx;
text-align: center;
}
.content {
margin-top: 24rpx;
text-align: center;
.link {
font-size: 32rpx;
color: #b982ff;
}
}
.footer {
margin-top: 40rpx;
display: flex;
gap: 30rpx;
.sure,
.cancel {
flex: 1;
padding: 20rpx;
text-align: center;
font-size: 36rpx;
border-radius: 100rpx;
}
.cancel {
padding: 18rpx 0;
color: #b982ff;
border: 1px solid #b982ff;
}
.sure {
padding: 0;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%);
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
}
}
.popup12 {
.popup-container {
padding: 0 40rpx 40rpx;
width: 630rpx;
height: 860rpx;
box-sizing: border-box;
.container {
padding: 236rpx 0 0;
.c-header {
display: flex;
align-items: center;
justify-content: center;
.avatar {
width: 76rpx;
height: 76rpx;
border-radius: 50%;
}
.name {
margin-left: 20rpx;
font-size: 32rpx;
color: #211d2e;
font-weight: bold;
line-height: 44rpx;
}
}
.code {
margin: 60rpx auto 0;
display: block;
width: 260rpx;
height: 260rpx;
border-radius: 24rpx;
}
.tip {
margin-top: 60rpx;
text-align: center;
font-size: 32rpx;
color: #211d2e;
line-height: 44rpx;
}
}
}
}
.popup13 {
.popup-container {
padding: 48rpx 32rpx 32rpx;
width: 670rpx;
height: 1124rpx;
background: linear-gradient(180deg, #f1e6ff 0%, #ffffff 12.03%, #ffffff 100%);
border-radius: 32rpx 32rpx 32rpx 32rpx;
border: 2rpx solid #ffffff;
box-sizing: border-box;
.title {
font-size: 44rpx;
color: #b982ff;
text-align: center;
font-weight: bold;
}
.scroll {
margin-top: 32rpx;
padding: 32rpx 32rpx 32rpx 0;
background: #f6f8f9;
border-radius: 32rpx 32rpx 32rpx 32rpx;
height: 824rpx;
overflow-y: auto;
box-sizing: border-box;
.s-title {
font-size: 36rpx;
line-height: 60rpx;
font-weight: bold;
margin-left: 32rpx;
color: #332c49;
border-radius: 0 32rpx 32rpx 0;
display: inline-block;
margin-top: 28rpx;
position: relative;
&::after {
position: absolute;
left: 0;
bottom: 6rpx;
content: '';
width: 100%;
height: 16rpx;
background: linear-gradient(90deg, #b982ff 0%, rgba(185, 130, 255, 0) 100%);
opacity: 0.4;
}
&:first-of-type {
margin-top: 0;
}
}
.content {
margin-top: 32rpx;
padding: 0 32rpx;
font-size: 32rpx;
color: #69686e;
line-height: 48rpx;
.high {
color: #b982ff;
font-weight: bold;
}
}
.s-name {
margin-top: 32rpx;
padding: 0 32rpx;
font-size: 32rpx;
color: #211d2e;
line-height: 48rpx;
display: flex;
align-items: center;
gap: 8rpx;
&::before {
content: '';
width: 8rpx;
height: 30rpx;
background: #b982ff;
border-radius: 2rpx 2rpx 2rpx 2rpx;
}
}
.row {
padding: 0 32rpx;
.col {
margin-top: 24rpx;
display: flex;
gap: 12rpx;
.order {
margin-top: 10rpx;
flex-shrink: 0;
width: 36rpx;
height: 36rpx;
text-align: center;
line-height: 36rpx;
font-size: 28rpx;
color: #ffffff;
border-radius: 50%;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%);
}
.c-content {
font-size: 32rpx;
color: #69686e;
line-height: 48rpx;
.high {
color: #b982ff;
font-weight: bold;
}
}
}
}
}
.btn {
margin-top: 32rpx;
width: 606rpx;
height: 88rpx;
font-size: 36rpx;
color: #ffffff;
line-height: 88rpx;
text-align: center;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%);
border-radius: 100rpx 100rpx 100rpx 100rpx;
}
}
}
.popup14 {
.badge {
position: relative;
z-index: 1;
display: block;
width: 198rpx;
height: 198rpx;
margin: 0 auto -110rpx;
text-align: center;
}
.popup-container {
width: 670rpx;
box-sizing: border-box;
padding: 130rpx 58rpx 56rpx;
border-radius: 32rpx;
background: linear-gradient(180deg, #f1e6ff 0%, #ffffff 29.75%, #ffffff 100%);
.title {
font-size: 36rpx;
color: #211d2e;
font-weight: bold;
}
.content {
margin-top: 28rpx;
font-size: 36rpx;
color: #69686e;
line-height: 48rpx;
text-align: center;
}
.btn {
margin-top: 56rpx;
height: 88rpx;
line-height: 88rpx;
text-align: center;
font-size: 36rpx;
color: #ffffff;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%);
border-radius: 100rpx;
}
}
}
.popup15 {
.badge {
position: relative;
z-index: 1;
display: block;
width: 144rpx;
height: 144rpx;
margin: 0 auto -72rpx;
text-align: center;
}
.popup-container {
width: 670rpx;
box-sizing: border-box;
padding: 118rpx 48rpx 16rpx;
border-radius: 32rpx;
background: #fff;
.title {
font-size: 40rpx;
color: #211d2e;
font-weight: bold;
text-align: center;
}
.content {
margin-top: 20rpx;
font-size: 32rpx;
color: #69686e;
line-height: 48rpx;
text-align: center;
.date {
color: #b982ff;
}
}
.btn {
margin-top: 44rpx;
height: 88rpx;
line-height: 88rpx;
text-align: center;
font-size: 36rpx;
color: #ffffff;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%);
border-radius: 100rpx;
}
.cancel {
padding: 32rpx;
font-size: 32rpx;
color: #b982ff;
text-align: center;
}
}
}
.popup16 {
.badge {
position: relative;
z-index: 1;
display: block;
width: 144rpx;
height: 144rpx;
margin: 0 auto -72rpx;
text-align: center;
}
.popup-container {
width: 670rpx;
box-sizing: border-box;
padding: 118rpx 48rpx 44rpx;
border-radius: 32rpx;
background: #fff;
.title {
font-size: 40rpx;
color: #211d2e;
font-weight: bold;
text-align: center;
}
.p-footer {
margin-top: 52rpx;
display: flex;
gap: 30rpx;
.sure,
.cancel {
flex: 1;
font-size: 36rpx;
border-radius: 100rpx;
height: 88rpx;
box-sizing: border-box;
}
.cancel {
color: #b982ff;
border: 1px solid #b982ff;
display: flex;
align-items: center;
justify-content: center;
}
.sure {
padding: 0;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%);
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
.popup17 {
.badge {
position: relative;
z-index: 1;
display: block;
width: 144rpx;
height: 144rpx;
margin: 0 auto -72rpx;
text-align: center;
}
.popup-container {
width: 670rpx;
box-sizing: border-box;
padding: 118rpx 48rpx 44rpx;
border-radius: 32rpx;
background: #fff;
.title {
font-size: 40rpx;
color: #211d2e;
font-weight: bold;
text-align: center;
}
.p-footer {
margin-top: 52rpx;
display: flex;
gap: 30rpx;
.sure,
.cancel {
flex: 1;
font-size: 36rpx;
border-radius: 100rpx;
height: 88rpx;
box-sizing: border-box;
}
.cancel {
color: #b982ff;
border: 1px solid #b982ff;
display: flex;
align-items: center;
justify-content: center;
}
.sure {
padding: 0;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%);
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
.popup18 {
.badge {
position: relative;
z-index: 1;
display: block;
width: 144rpx;
height: 144rpx;
margin: 0 auto -72rpx;
text-align: center;
}
.popup-container {
width: 670rpx;
box-sizing: border-box;
padding: 118rpx 48rpx 44rpx;
border-radius: 32rpx;
background: #fff;
.title {
font-size: 40rpx;
color: #211d2e;
font-weight: bold;
text-align: center;
}
.p-footer {
margin-top: 52rpx;
display: flex;
gap: 30rpx;
.sure,
.cancel {
flex: 1;
font-size: 36rpx;
border-radius: 100rpx;
height: 88rpx;
box-sizing: border-box;
}
.cancel {
color: #b982ff;
border: 1px solid #b982ff;
display: flex;
align-items: center;
justify-content: center;
}
.sure {
padding: 0;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%);
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
.close { .close {
margin: 48rpx auto 0; margin: 48rpx auto 0;
display: block; display: block;

3
src/components/popup/index.ts

@ -36,9 +36,6 @@ Component({
handleCancel() { handleCancel() {
this.triggerEvent('cancel') this.triggerEvent('cancel')
}, },
handlePhone(e) {
this.triggerEvent('phone', e.detail)
},
routerTo(e: any) { routerTo(e: any) {
const { url } = e.currentTarget.dataset const { url } = e.currentTarget.dataset
wx.navigateTo({ wx.navigateTo({

184
src/components/popup/index.wxml

@ -55,8 +55,7 @@
</view> </view>
</view> </view>
<view class="popup6" wx:if="{{type==='popup6'}}"> <view class="popup6" wx:if="{{type==='popup6'}}">
<image class="p-img" src="{{imageUrl}}bg32.png?t={{Timestamp}}"></image> <image class="p-img" src="{{imageUrl}}bg20.png?t={{Timestamp}}" show-menu-by-longpress></image>
<image class="code" src="{{params.qrCode}}" show-menu-by-longpress></image>
</view> </view>
<view class="popup7" wx:if="{{type==='popup7'}}"> <view class="popup7" wx:if="{{type==='popup7'}}">
<image class="badge" src="{{imageUrl}}icon78.png?t={{Timestamp}}"></image> <image class="badge" src="{{imageUrl}}icon78.png?t={{Timestamp}}"></image>
@ -72,187 +71,6 @@
<image class="p-img" src="{{imageUrl}}bg23.png?t={{Timestamp}}"></image> <image class="p-img" src="{{imageUrl}}bg23.png?t={{Timestamp}}"></image>
<image class="code" src="{{params.subscribe_img}}" show-menu-by-longpress></image> <image class="code" src="{{params.subscribe_img}}" show-menu-by-longpress></image>
</view> </view>
<view class="popup9" wx:if="{{type==='popup9'}}">
<image class="icon" src="{{imageUrl}}icon100.png?t={{Timestamp}}"></image>
<view class="title">
文字包含不合规内容
<view></view>
请修改后重新提交
</view>
<view class="btn" bind:tap="handleOk">知道了</view>
</view>
<view class="popup10" wx:if="{{type==='popup10'}}">
<view class="title">我已阅读并同意</view>
<view class="content">
<text class="link" bind:tap="routerTo" data-url="/doc/pages/doc2/index?active=1">《用户协议》</text>
<text class="link" bind:tap="routerTo" data-url="/doc/pages/doc2/index">《隐私政策》</text>
<view></view>
<text class="link" bind:tap="routerTo" data-url="/doc/pages/doc2/index?active=2">《个人信息共享知情同意书》</text>
</view>
<view class="footer">
<view class="cancel" bind:tap="handleCancel">取消</view>
<button class="sure" open-type="getPhoneNumber" bindgetphonenumber="handlePhone">确定</button>
</view>
</view>
<view class="popup11" wx:if="{{type==='popup11'}}">
<view class="title">我已阅读并同意</view>
<view class="content">
<text class="link" bind:tap="routerTo" data-url="/doc/pages/doc1/index">《隐私协议保护政策》</text>
</view>
<view class="footer">
<view class="cancel" bind:tap="handleCancel">取消</view>
<view wx:if="{{params.customPhone}}" class="sure" bind:tap="handleOk">确定</view>
<button wx:else class="sure" open-type="getPhoneNumber" bindgetphonenumber="handlePhone">确定</button>
</view>
</view>
<view class="popup12" wx:if="{{type==='popup12'}}">
<view
class="popup-container"
style="background: url('{{imageUrl}}bg29.png?t={{Timestamp}}') no-repeat top center/100%"
>
<view class="container">
<view class="c-header">
<image class="avatar" src="{{params.ConsultQwAvatar}}"></image>
<view class="name">{{params.ConsultQwName}}</view>
</view>
<image class="code" mode="aspectFill" src="{{params.ConsultQwImg}}" show-menu-by-longpress></image>
<view class="tip">
长按识别二维码
<view></view>
添加客服人员
</view>
</view>
</view>
</view>
<view class="popup13" wx:if="{{type==='popup13'}}">
<view class="popup-container">
<view class="title">了解双通道/临采/院内用药</view>
<view class="scroll">
<view class="s-title">什么是“双通道”?</view>
<view class="content">
“双通道”是指除了医院,患者还能去
<text class="high">指定药店</text>
买药,而且
<text class="high">报销比例和医院一样。</text>
</view>
<view class="s-name">“双通道”报销需要注意以下两点</view>
<view class="row">
<view class="col">
<view class="order">1</view>
<view class="c-content">
外配处方通常存在
<text class="high">有效期</text>
,我们要在有效期内去药店购药;
</view>
</view>
<view class="col">
<view class="order">2</view>
<view class="c-content">
药店必须是纳入“双通道”管理的
<text class="high">定点药店</text>
,才能享受同等报销待遇。
</view>
</view>
</view>
<view class="s-title">什么是“临采”?</view>
<view class="content">
“临采”全称是临时采购,适用场景主要是:医院暂时缺货、有突发的治疗需求、或者有特种病例需要紧急用药的情况。
</view>
<view class="content">
整个流程有
<text class="high">明确的时间限制</text>
,是短期解决“缺药”问题的办法,
<text class="high">不适合长期</text>
常规用药。
</view>
<view class="s-title">什么是“院内用药”?</view>
<view class="content">
院内用药就是“在医院看诊-拿药-直接报销”的一站式全流程,也是最传统、最省心的方式,全程
<text class="high">自动报销</text>
</view>
<view class="s-name">“院内用药”报销需满足两个条件</view>
<view class="row">
<view class="col">
<view class="order">1</view>
<view class="c-content">
医院必须是
<text class="high">医保定点机构</text>
</view>
</view>
<view class="col">
<view class="order">2</view>
<view class="c-content">
医生开具的处方要符合药品说明书适应症和医保限定支付范围(即:
<text class="high">中重度甲状腺眼病</text>
)。
</view>
</view>
</view>
</view>
<view class="btn" bind:tap="handleOk">了解更多详情</view>
</view>
</view>
<view class="popup14" wx:if="{{type==='popup14'}}">
<image class="badge" src="{{imageUrl}}icon131.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="title">访问直播活动页需切换至患者端</view>
<view class="content">请问是否继续</view>
<view class="btn" bind:tap="handleOk">继续</view>
</view>
</view>
<view class="popup15" wx:if="{{type==='popup15'}}">
<image class="badge" src="{{imageUrl}}icon155.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="title">确认删除记录?</view>
<view class="content">
删除
<text class="date">{{params.recordDate}}</text>
记录
<view>此操作不可逆,相关照片将永久删除</view>
</view>
<view class="btn" bind:tap="handleOk">确认删除</view>
<view class="cancel" bind:tap="handleCancel">取消</view>
</view>
</view>
<view class="popup16" wx:if="{{type==='popup16'}}">
<image class="badge" src="{{imageUrl}}icon156.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="title">您的记录还未保存</view>
<view class="p-footer">
<view class="cancel" bind:tap="handleCancel">退出</view>
<view class="sure" bind:tap="handleOk">保存记录</view>
</view>
</view>
</view>
<view class="popup17" wx:if="{{type==='popup17'}}">
<image class="badge" src="{{imageUrl}}icon156.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="title">
您有裁剪的照片
<view></view>
现在退出会被清空
</view>
<view class="p-footer">
<view class="cancel" bind:tap="handleCancel">取消</view>
<view class="sure" bind:tap="handleOk">继续退出</view>
</view>
</view>
</view>
<view class="popup18" wx:if="{{type==='popup18'}}">
<image class="badge" src="{{imageUrl}}icon156.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="title">
是否替换已有基准照
</view>
<view class="p-footer">
<view class="cancel" bind:tap="handleCancel">取消</view>
<view class="sure" bind:tap="handleOk">确认替换</view>
</view>
</view>
</view>
<image <image
wx:if="{{params.close}}" wx:if="{{params.close}}"

2
src/patient/pages/hormones/index.json → src/components/referralFrom/index.json

@ -1,6 +1,6 @@
{ {
"component": true,
"usingComponents": { "usingComponents": {
"navbar": "/components/navbar/index",
"van-popup": "@vant/weapp/popup/index" "van-popup": "@vant/weapp/popup/index"
} }
} }

95
src/components/referralFrom/index.scss

@ -0,0 +1,95 @@
.from {
padding: 48rpx 40rpx;
width: 650rpx;
box-sizing: border-box;
background: linear-gradient(349deg, #ffffff 0%, #e2f1f4 100%);
border-radius: 24rpx 24rpx 24rpx 24rpx;
border: 2rpx solid #ffffff;
.title {
font-size: 32rpx;
color: #283031;
font-weight: bold;
}
.date {
margin-top: 24rpx;
padding: 14rpx 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #f2f4f5;
border-radius: 16rpx;
.conetent {
font-size: 32rpx;
color: #283031;
}
.tril {
width: 0;
height: 0;
border-style: solid;
border-width: 10rpx 10rpx 0 10rpx;
border-color: #aeb3b4 transparent transparent transparent;
}
}
.select-title {
margin-top: 48rpx;
font-size: 32rpx;
color: #283031;
font-weight: bold;
.sub {
font-weight: normal;
}
}
.list {
margin-top: 26rpx;
max-height: 55vh;
overflow-y: auto;
&::-webkit-scrollbar{
display: none;
}
.item {
margin-bottom: 16rpx;
padding: 14rpx 32rpx;
font-size: 32rpx;
color: #283031;
line-height: 48rpx;
background-color: #f2f4f5;
border: 1px solid #f2f4f5;
border-radius: 16rpx;
&.active {
border-color: #67baca;
background-color: #e7f5f8;
color: #67baca;
}
}
}
.footer {
margin-top: 32rpx;
display: flex;
justify-content: space-between;
align-items: center;
gap: 26rpx;
text-align: center;
.cancel {
flex: 1;
height: 80rpx;
font-size: 36rpx;
color: #67BACA;
line-height: 80rpx;
background: #ffffff;
border-radius: 98rpx 98rpx 98rpx 98rpx;
border: 2rpx solid #67baca;
}
.submit {
flex: 1;
height: 80rpx;
font-size: 36rpx;
color: #FFFFFF;
line-height: 80rpx;
background: #67baca;
border-radius: 98rpx 98rpx 98rpx 98rpx;
border: 2rpx solid #67baca;
}
}
}

139
src/components/referralFrom/index.ts

@ -0,0 +1,139 @@
import dayjs from 'dayjs'
const _app = getApp<IAppOption>()
// pages/story/a.ts
Component({
/**
*
*/
properties: {
show: {
type: Boolean,
value: false,
},
params: {
type: Object,
value: undefined,
},
},
observers: {
show() {
if (this.data.params) {
this.setData({
...this.data.params,
})
this.handleDateChange()
} else {
this.setData({
visitDateName: '',
visitDate: '',
hormone: 2,
traditionalInhibitor: 2,
gammaGlobulin: 2,
plasmaExchange: 2,
bCellInhibitor: 2,
fcRnAntagonists: 2,
c5ComplementInhibitor: 2,
chineseMedicine: 2,
other: 2,
recordId: '',
})
}
},
},
data: {
currentDate: dayjs().format('YYYY-MM-DD'),
visitDateName: '',
visitDate: '',
hormone: 2,
traditionalInhibitor: 2,
gammaGlobulin: 2,
plasmaExchange: 2,
bCellInhibitor: 2,
fcRnAntagonists: 2,
c5ComplementInhibitor: 2,
chineseMedicine: 2,
other: 2,
recordId: '',
},
methods: {
handleDateChange() {
this.setData({
visitDateName: dayjs(this.data.visitDate).format('YYYY年MM月DD日'),
})
},
handleSelect(e) {
const { name } = e.currentTarget.dataset
const value = this.data[name]
this.setData({
[name]: value === 2 ? 1 : 2,
})
},
submit() {
const { visitDate, recordId } = this.data
const params = {
visitDate,
recordId,
}
if(!visitDate){
wx.showToast({
title: '请选择复诊日期',
icon: 'none',
})
return
}
const selectKeys = [
'hormone',
'traditionalInhibitor',
'gammaGlobulin',
'plasmaExchange',
'bCellInhibitor',
'fcRnAntagonists',
'c5ComplementInhibitor',
'chineseMedicine',
'other',
]
selectKeys.forEach((item) => {
params[item] = this.data[item]
})
const onlySelect = selectKeys.some((item) => {
return this.data[item] === 1
})
if (!onlySelect) {
wx.showToast({
title: '请至少选择一种复诊后的方案',
icon: 'none',
})
return
}
wx.ajax({
method: 'POST',
url: '?r=xd/re-visit/save-record',
data: params,
}).then(() => {
if (recordId) {
wx.showToast({
icon: 'none',
title: '编辑成功',
})
} else {
wx.showToast({
icon: 'none',
title: '添加成功',
})
}
this.handleCancel()
this.triggerEvent('refresh', params)
})
},
handleCancel() {
this.setData({
show: false,
})
},
},
})

52
src/components/referralFrom/index.wxml

@ -0,0 +1,52 @@
<van-popup custom-style="background: transparent;" round z-index="{{100000}}" show="{{ show }}">
<view class="from">
<view class="title">您上一次复诊时间?</view>
<picker mode="date" model:value="{{visitDate}}" end="{{currentDate}}" bind:change="handleDateChange">
<view class="date">
<view class="content">{{visitDateName||'请选择'}}</view>
<view class="tril"></view>
</view>
</picker>
<view class="select-title">
您复诊后的方案是?
<text class="sub">(多选)</text>
</view>
<view class="list">
<view bind:tap="handleSelect" data-name="hormone" class="item {{hormone===1 && 'active'}}">1.激素</view>
<view
bind:tap="handleSelect"
data-name="traditionalInhibitor"
class="item {{traditionalInhibitor===1 && 'active'}}"
>
2.传统免疫抑制剂(如他克莫司、吗 替麦考酚酯等)
</view>
<view bind:tap="handleSelect" data-name="gammaGlobulin" class="item {{gammaGlobulin===1 && 'active'}}">
3.静脉输注丙种球蛋白
</view>
<view bind:tap="handleSelect" data-name="plasmaExchange" class="item {{plasmaExchange===1 && 'active'}}">
4.血浆置换
</view>
<view bind:tap="handleSelect" data-name="bCellInhibitor" class="item {{bCellInhibitor===1 && 'active'}}">
5.B细胞抑制剂(如:利妥昔单抗、泰 它西普、伊奈利珠单抗)
</view>
<view bind:tap="handleSelect" data-name="fcRnAntagonists" class="item {{fcRnAntagonists===1 && 'active'}}">
6.FcRn拮抗剂(如:艾加莫德)
</view>
<view
bind:tap="handleSelect"
data-name="c5ComplementInhibitor"
class="item {{c5ComplementInhibitor===1 && 'active'}}"
>
7.C5补体抑制剂(如:依库珠单抗)
</view>
<view bind:tap="handleSelect" data-name="chineseMedicine" class="item {{chineseMedicine===1 && 'active'}}">
8.中药或中成药
</view>
<view bind:tap="handleSelect" data-name="other" class="item {{other===1 && 'active'}}">9.其他</view>
</view>
<view class="footer">
<view class="cancel" bind:tap="handleCancel">取消</view>
<view class="submit" bind:tap="submit">确定</view>
</view>
</view>
</van-popup>

209
src/components/star/index.ts

@ -1,70 +1,70 @@
const app = getApp() const app = getApp();
/** /**
* >=min && <=max * >=min && <=max
* @param min * @param min
* @param max * @param max
*/ */
function getRandom(min, max) { function getRandom(min, max) {
return min + Math.floor(Math.random() * (max - min + 1)) return min + Math.floor(Math.random() * (max - min + 1));
} }
Component({ Component({
options: {}, options: {},
lifetimes: { lifetimes: {
attached() { attached() {
const query = wx.createSelectorQuery().in(this) const query = wx.createSelectorQuery().in(this);
query query
.select('#thumsCanvas') .select("#thumsCanvas")
.fields({ node: true, size: true }) .fields({ node: true, size: true })
.exec((res) => { .exec((res) => {
const canvas = res[0].node const canvas = res[0].node;
const context = canvas.getContext('2d') const context = canvas.getContext("2d");
this.setData({ this.setData({
context, context: context,
}) });
const dpr = wx.getSystemInfoSync().pixelRatio const dpr = wx.getSystemInfoSync().pixelRatio;
canvas.width = res[0].width * dpr canvas.width = res[0].width * dpr;
canvas.height = res[0].height * dpr canvas.height = res[0].height * dpr;
this.data.width = res[0].width * dpr this.data.width = res[0].width * dpr;
this.data.height = res[0].height * dpr this.data.height = res[0].height * dpr;
// context.fillStyle = "rgba(255, 255, 255, 0)"; // context.fillStyle = "rgba(255, 255, 255, 0)";
const images = [ const images = [
'za-images/star/icon1.png', "za-images/star/icon1.png",
'za-images/star/icon2.png', "za-images/star/icon2.png",
'za-images/star/icon3.png', "za-images/star/icon3.png",
'za-images/star/icon4.png', "za-images/star/icon4.png",
'za-images/star/icon5.png', "za-images/star/icon5.png",
'za-images/star/icon6.png', "za-images/star/icon6.png",
'za-images/star/icon7.png', "za-images/star/icon7.png",
'za-images/star/icon8.png', "za-images/star/icon8.png",
] ];
const promiseAll = [] as Array<Promise<any>> const promiseAll = [] as Array<Promise<any>>;
images.forEach((src) => { images.forEach((src) => {
const p = new Promise((resolve) => { const p = new Promise(function (resolve) {
const img = canvas.createImage() const img = canvas.createImage();
img.onerror = img.onload = resolve.bind(null, img) img.onerror = img.onload = resolve.bind(null, img);
img.src = app.globalData.imageUrl + src img.src = app.globalData.imageUrl + src;
}) });
promiseAll.push(p) promiseAll.push(p);
}) });
Promise.all(promiseAll).then((imgsList) => { Promise.all(promiseAll).then((imgsList) => {
const imgsLists = imgsList.filter((d) => { const imgsLists = imgsList.filter((d) => {
if (d && d.width > 0) if (d && d.width > 0) return true;
return true return false;
return false });
})
this.setData({ this.setData({
imgsList: imgsLists, imgsList: imgsLists,
}) });
if (this.data.imgsList.length == 0) { if (this.data.imgsList.length == 0) {
// logger.error("imgsList load all error"); // logger.error("imgsList load all error");
wx.showToast({ wx.showToast({
icon: 'none', icon: "none",
title: 'imgsList load all error', title: "imgsList load all error",
}) });
return;
} }
}) });
}) });
}, },
}, },
properties: {}, properties: {},
@ -79,105 +79,98 @@ Component({
}, },
methods: { methods: {
handleTap() { handleTap() {
this.start() this.start();
}, },
createRender() { createRender() {
if (this.data.imgsList.length == 0) if (this.data.imgsList.length == 0) return null;
return null const basicScale = [0.6, 0.9, 1.2][getRandom(0, 2)];
const basicScale = [0.6, 0.9, 1.2][getRandom(0, 2)]
const getScale = (diffTime) => { const getScale = (diffTime) => {
if (diffTime < this.data.scaleTime) { if (diffTime < this.data.scaleTime) {
return +(diffTime / this.data.scaleTime).toFixed(2) * basicScale return +(diffTime / this.data.scaleTime).toFixed(2) * basicScale;
} else {
return basicScale;
} }
else { };
return basicScale const context = this.data.context;
}
}
const context = this.data.context
// 随机读取一个图片来渲染 // 随机读取一个图片来渲染
const image: any = this.data.imgsList[getRandom(0, this.data.imgsList.length - 1)] const image: any = this.data.imgsList[getRandom(0, this.data.imgsList.length - 1)];
const offset = 20 const offset = 20;
const basicX = this.data.width / 2 + getRandom(-offset, offset) const basicX = this.data.width / 2 + getRandom(-offset, offset);
const angle = getRandom(2, 10) const angle = getRandom(2, 10);
const ratio = getRandom(10, 30) * (getRandom(0, 1) ? 1 : -1) let ratio = getRandom(10, 30) * (getRandom(0, 1) ? 1 : -1);
const getTranslateX = (diffTime) => { const getTranslateX = (diffTime) => {
if (diffTime < this.data.scaleTime) { if (diffTime < this.data.scaleTime) {
// 放大期间,不进行摇摆位移 // 放大期间,不进行摇摆位移
return basicX return basicX;
} } else {
else { return basicX + ratio * Math.sin(angle * (diffTime - this.data.scaleTime));
return basicX + ratio * Math.sin(angle * (diffTime - this.data.scaleTime))
} }
} };
const getTranslateY = (diffTime) => { const getTranslateY = (diffTime) => {
return image.height / 2 + (this.data.height - image.height / 2) * (1 - diffTime) return image.height / 2 + (this.data.height - image.height / 2) * (1 - diffTime);
} };
const fadeOutStage = getRandom(14, 18) / 100 const fadeOutStage = getRandom(14, 18) / 100;
const getAlpha = (diffTime) => { const getAlpha = (diffTime) => {
const left = 1 - +diffTime let left = 1 - +diffTime;
if (left > fadeOutStage) { if (left > fadeOutStage) {
return 1 return 1;
} else {
return 1 - +((fadeOutStage - left) / fadeOutStage).toFixed(2);
} }
else { };
return 1 - +((fadeOutStage - left) / fadeOutStage).toFixed(2)
}
}
return (diffTime) => { return (diffTime) => {
// 差值满了,即结束了 0 ---》 1 // 差值满了,即结束了 0 ---》 1
if (diffTime >= 1) if (diffTime >= 1) return true;
return true context.save();
context.save() const scale = getScale(diffTime);
const scale = getScale(diffTime)
// const rotate = getRotate(); // const rotate = getRotate();
const translateX = getTranslateX(diffTime) const translateX = getTranslateX(diffTime);
const translateY = getTranslateY(diffTime) const translateY = getTranslateY(diffTime);
context.translate(translateX, translateY) context.translate(translateX, translateY);
context.scale(scale, scale) context.scale(scale, scale);
// context.rotate(rotate * Math.PI / 180); // context.rotate(rotate * Math.PI / 180);
context.globalAlpha = getAlpha(diffTime) context.globalAlpha = getAlpha(diffTime);
context.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height) context.drawImage(image, -image.width / 2, -image.height / 2, image.width, image.height);
context.restore() context.restore();
} };
}, },
scan() { scan() {
this.data.context.clearRect(0, 0, this.data.width, this.data.height) this.data.context.clearRect(0, 0, this.data.width, this.data.height);
this.data.context.fillStyle = 'rgba(255, 255, 255, 0)' this.data.context.fillStyle = "rgba(255, 255, 255, 0)";
this.data.context.fillRect(0, 0, 200, 400) this.data.context.fillRect(0, 0, 200, 400);
let index = 0 let index = 0;
let length = this.data.renderList.length let length = this.data.renderList.length;
if (length > 0) { if (length > 0) {
this.requestFrame(this.scan.bind(this)) this.requestFrame(this.scan.bind(this));
this.setData({ this.setData({
scanning: true, scanning: true,
}) });
} } else {
else {
this.setData({ this.setData({
scanning: false, scanning: false,
}) });
} }
while (index < length) { while (index < length) {
const child = this.data.renderList[index] const child = this.data.renderList[index];
if (!child || !child.render || child.render.call(null, (Date.now() - child.timestamp) / child.duration)) { if (!child || !child.render || child.render.call(null, (Date.now() - child.timestamp) / child.duration)) {
// 结束了,删除该动画 // 结束了,删除该动画
this.setData({ this.setData({
renderList: [...this.data.renderList].filter((_item, fIndex) => fIndex != index), renderList: [...this.data.renderList].filter((_item, fIndex) => fIndex != index),
}) });
length-- length--;
} } else {
else {
// continue // continue
index++ index++;
} }
} }
}, },
start() { start() {
const render = this.createRender() const render = this.createRender();
const duration = getRandom(1500, 3000) const duration = getRandom(1500, 3000);
this.setData({ this.setData({
renderList: [ renderList: [
...this.data.renderList, ...this.data.renderList,
@ -187,25 +180,25 @@ Component({
timestamp: Date.now(), timestamp: Date.now(),
}, },
], ],
}) });
if (!this.data.scanning) { if (!this.data.scanning) {
this.setData({ this.setData({
scanning: true, scanning: true,
}) });
this.requestFrame(this.scan.bind(this)) this.requestFrame(this.scan.bind(this));
// this.scan.bind(this)(); // this.scan.bind(this)();
} }
return this return this;
}, },
requestFrame(cb) { requestFrame(cb) {
return ( return (
this.data.context.requestAnimationFrame this.data.context.requestAnimationFrame ||
|| (function (callback) { (function (callback) {
setTimeout(callback, 1000 / 60) setTimeout(callback, 1000 / 60);
})(cb) })(cb)
) );
}, },
}, },
}) });

8
src/components/text-expandsion/index.scss

@ -10,13 +10,13 @@
max-height: 9em; max-height: 9em;
text-align: justify; text-align: justify;
&::before { &::before {
content: ''; content: "";
float: right; float: right;
height: 100%; height: 100%;
margin-bottom: -40rpx; margin-bottom: -40rpx;
} }
&::after { &::after {
content: ''; content: "";
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
position: absolute; position: absolute;
@ -32,11 +32,11 @@
clear: both; clear: both;
line-height: 42rpx; line-height: 42rpx;
&::before { &::before {
content: '...'; content: "...";
margin-right: 8rpx; margin-right: 8rpx;
} }
&::after { &::after {
content: ''; content: "";
display: inline-block; display: inline-block;
margin-bottom: 2rpx; margin-bottom: 2rpx;
margin-left: 4rpx; margin-left: 4rpx;

50
src/components/timeOut/index.ts

@ -1,4 +1,4 @@
const app = getApp<IAppOption>() const app = getApp<IAppOption>();
// pages/story/a.ts // pages/story/a.ts
Component({ Component({
@ -8,7 +8,7 @@ Component({
properties: { properties: {
detailId: { detailId: {
type: String, type: String,
value: '0', value: "0",
}, },
asideOut: { asideOut: {
type: Boolean, type: Boolean,
@ -16,7 +16,7 @@ Component({
}, },
asideType: { asideType: {
type: String, type: String,
value: '', value: "",
}, },
timeToast: { timeToast: {
type: Boolean, type: Boolean,
@ -24,34 +24,33 @@ Component({
}, },
timeToastType: { timeToastType: {
type: String, type: String,
value: '', value: "",
}, },
timeToastParams: { timeToastParams: {
type: Object, type: Object,
value() { value() {
return {} return {};
}, },
}, },
}, },
observers: { observers: {
asideOut(asideOut) { asideOut: function (asideOut) {
if (asideOut) { if (asideOut) {
setTimeout(() => { setTimeout(() => {
this.countDown() this.countDown();
}, 1000) }, 1000);
} }
}, },
}, },
lifetimes: { lifetimes: {
attached() { attached() {
const systemInfo = wx.getSystemInfoSync() let systemInfo = wx.getSystemInfoSync();
this.setData({ this.setData({
sliderTop: systemInfo.screenHeight - 250, sliderTop: systemInfo.screenHeight - 250,
}) });
}, },
detached() { detached() {
if (this.timer) if (this.timer) clearInterval(this.timer);
clearInterval(this.timer)
}, },
}, },
data: { data: {
@ -67,26 +66,25 @@ Component({
methods: { methods: {
timer: null as any, timer: null as any,
countDown() { countDown() {
const that = this const that = this;
if (that.timer) if (that.timer) return;
return let circle = 100;
let circle = 100
that.timer = setInterval(() => { that.timer = setInterval(() => {
circle-- circle--;
that.setData({ that.setData({
circleVal: circle, circleVal: circle,
centerVal: Math.floor(circle / 10), centerVal: Math.floor(circle / 10),
}) });
if (circle <= 0) { if (circle <= 0) {
clearInterval(that.timer) clearInterval(that.timer);
this.handleAsideOut() this.handleAsideOut();
} }
}, 100) }, 100);
}, },
handleAsideOut() { handleAsideOut() {
wx.ajax({ wx.ajax({
method: 'POST', method: "POST",
url: '?r=xd/score/send-score', url: "?r=xd/score/send-score",
data: { data: {
Type: this.data.asideType, Type: this.data.asideType,
Id: this.data.detailId, Id: this.data.detailId,
@ -95,9 +93,9 @@ Component({
if (!Array.isArray(res)) { if (!Array.isArray(res)) {
this.setData({ this.setData({
rewardScore: res.rewardScore, rewardScore: res.rewardScore,
}) });
} }
}) });
}, },
}, },
}) });

143
src/components/toast/index.scss

@ -4,14 +4,6 @@
justify-content: center; justify-content: center;
} }
.popup-close {
margin: 40rpx auto;
display: block;
font-size: 80rpx;
color: #fff;
text-align: center;
}
.popup { .popup {
position: relative; position: relative;
z-index: 9999999999; z-index: 9999999999;
@ -2628,7 +2620,7 @@
width: 364rpx; width: 364rpx;
height: 84rpx; height: 84rpx;
font-size: 36rpx; font-size: 36rpx;
color: #ffffff; color: #FFFFFF;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -2639,136 +2631,3 @@
} }
} }
} }
.popup-medical-guide {
margin-bottom: -120rpx;
.popup-container {
.container {
padding: 424rpx 0 0;
width: 750rpx;
height: 800rpx;
box-sizing: border-box;
.tip {
font-size: 40rpx;
color: #b982ff;
text-align: center;
}
.btn {
margin: 42rpx auto 0;
width: 526rpx;
height: 88rpx;
font-size: 40rpx;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%);
border-radius: 100rpx;
}
}
}
}
.popup-question-toast {
.popup-container {
padding: 48rpx 0 68rpx;
background: linear-gradient(180deg, #f1e6ff 0%, #ffffff 12.03%, #ffffff 100%);
border-radius: 32rpx 32rpx 32rpx 32rpx;
border: 2rpx solid #ffffff;
width: 670rpx;
box-sizing: border-box;
.title {
font-size: 44rpx;
color: #b982ff;
line-height: 48rpx;
text-align: center;
font-weight: bold;
}
.scroll {
margin-top: 32rpx;
padding: 0 50rpx;
font-size: 36rpx;
color: #211d2e;
line-height: 60rpx;
height: 716rpx;
overflow-y: auto;
}
}
}
.popup-enter-info {
.badge {
position: relative;
z-index: 1;
display: block;
width: 200rpx;
height: 224rpx;
margin: 0 auto -140rpx;
text-align: center;
}
.popup-container {
width: 670rpx;
position: relative;
box-sizing: border-box;
padding: 148rpx 24rpx 56rpx;
border-radius: 32rpx;
background: linear-gradient(180deg, #f1e6ff 0%, #ffffff 29.75%, #ffffff 100%);
text-align: center;
.p-close {
position: absolute;
right: 22rpx;
top: 22rpx;
font-size: 38rpx;
color: #adacb2;
}
.title {
font-size: 40rpx;
color: #211d2e;
font-weight: bold;
}
.content {
margin-top: 28rpx;
font-size: 32rpx;
color: #adacb2;
line-height: 48rpx;
.high {
color: #b982ff;
}
}
.btn {
margin: 32rpx 30rpx 0;
height: 88rpx;
line-height: 88rpx;
text-align: center;
font-size: 36rpx;
color: #ffffff;
background: linear-gradient(344deg, #ffbcf9 0%, #b982ff 100%);
border-radius: 100rpx;
}
}
}
.popup-qw {
.popup-container {
width: 630rpx;
height: 802rpx;
overflow: hidden;
.code {
margin: 342rpx auto 0;
display: block;
width: 264rpx;
height: 264rpx;
}
}
}
.popup-note-guide {
.popup-container {
.guide {
margin: 0 auto 62rpx;
display: block;
width: 660rpx;
height: 673rpx;
}
}
}

72
src/components/toast/index.ts

@ -1,4 +1,4 @@
const app = getApp() const app = getApp();
Component({ Component({
properties: { properties: {
show: { show: {
@ -9,7 +9,7 @@ Component({
params: { params: {
type: Object, type: Object,
value() { value() {
return {} return {};
}, },
}, },
}, },
@ -19,37 +19,37 @@ Component({
app.zdGetTheme().then((res) => { app.zdGetTheme().then((res) => {
this.setData({ this.setData({
theme: res, theme: res,
}) });
}) });
if (this.data.params.timeOut) { if (this.data.params.timeOut) {
let time = this.data.params.timeOut let time = this.data.params.timeOut;
const timerFunc = () => { const timerFunc = () => {
if (time <= 0) { if (time <= 0) {
this.setData({ this.setData({
timeOut: '', timeOut: '',
}) });
clearInterval(this.timer) clearInterval(this.timer);
return return;
} }
this.setData({ this.setData({
timeOut: `${time}s`, timeOut: `${time}s`,
}) });
--time --time;
} };
timerFunc() timerFunc();
this.timer = setInterval(timerFunc, 1000) this.timer = setInterval(timerFunc, 1000);
} }
if (['storyLead', 'storyStar', 'storyShare'].includes(this.data.type)) { if (['storyLead', 'storyStar', 'storyShare'].includes(this.data.type)) {
this.getSettingInfo() this.getSettingInfo();
} }
} }
this.setData({ this.setData({
zdUserInfo: app.globalData.zdUserInfo, zdUserInfo: app.globalData.zdUserInfo,
}) });
}, },
type(val) { type(val) {
if (val === 'healthCare') { if (val === 'healthCare') {
this.getOpenPatientList() this.getOpenPatientList();
} }
}, },
}, },
@ -66,42 +66,42 @@ Component({
this.setData({ this.setData({
imageUrl: app.globalData.imageUrl, imageUrl: app.globalData.imageUrl,
Timestamp: app.globalData.Timestamp, Timestamp: app.globalData.Timestamp,
}) });
}, },
}, },
methods: { methods: {
timer: null as any, timer: null as any,
handleOk() { handleOk() {
if (this.data.timeOut) { if (this.data.timeOut) {
return return;
} }
this.triggerEvent('ok', { protocol: this.data.protocol }) this.triggerEvent('ok', { protocol: this.data.protocol });
}, },
handleCancel(e = { currentTarget: { dataset: { key: '' } } }) { handleCancel(e = { currentTarget: { dataset: { key: '' } } }) {
const { key } = e.currentTarget.dataset const { key } = e.currentTarget.dataset;
if (this.timer) { if (this.timer) {
clearInterval(this.timer) clearInterval(this.timer);
this.setData({ this.setData({
timeOut: '', timeOut: '',
}) });
} }
this.triggerEvent('cancel', { key }) this.triggerEvent('cancel', { key });
}, },
handleTaskCancel() { handleTaskCancel() {
this.triggerEvent('taskCancel') this.triggerEvent('taskCancel');
}, },
handleJump() { handleJump() {
this.triggerEvent('jump') this.triggerEvent('jump');
}, },
handleDel() { handleDel() {
this.triggerEvent('del') this.triggerEvent('del');
}, },
routerTo(e) { routerTo(e) {
const { path } = e.currentTarget.dataset const { path } = e.currentTarget.dataset;
wx.navigateTo({ wx.navigateTo({
url: path, url: path,
}) });
this.handleCancel() this.handleCancel();
}, },
getSettingInfo() { getSettingInfo() {
wx.ajax({ wx.ajax({
@ -111,8 +111,8 @@ Component({
}).then((res) => { }).then((res) => {
this.setData({ this.setData({
settingsInfo: res, settingsInfo: res,
}) });
}) });
}, },
getOpenPatientList() { getOpenPatientList() {
wx.ajax({ wx.ajax({
@ -122,18 +122,18 @@ Component({
}).then((res) => { }).then((res) => {
this.setData({ this.setData({
openPatientList: res, openPatientList: res,
}) });
}) });
}, },
handleProtocolChange() { handleProtocolChange() {
this.setData({ this.setData({
protocol: !this.data.protocol, protocol: !this.data.protocol,
}) });
}, },
handleAdlQuestion() { handleAdlQuestion() {
wx.navigateTo({ wx.navigateTo({
url: '/pages/repositoryDetail/index?id=9', url: '/pages/repositoryDetail/index?id=9',
}) });
}, },
}, },
}) });

65
src/components/toast/index.wxml

@ -4,8 +4,6 @@
round round
z-index="{{100000}}" z-index="{{100000}}"
show="{{ show }}" show="{{ show }}"
position="{{params.position || 'center'}}"
safe-area-inset-bottom="{{false}}"
> >
<view class="popup-class" wx:if="{{type=='videoComplate'}}"> <view class="popup-class" wx:if="{{type=='videoComplate'}}">
<image class="bg" src="{{imageUrl}}za-images/popup-class-bg.png?t={{Timestamp}}"></image> <image class="bg" src="{{imageUrl}}za-images/popup-class-bg.png?t={{Timestamp}}"></image>
@ -792,67 +790,4 @@
</view> </view>
</view> </view>
</view> </view>
<view class="popup-medical-guide" wx:if="{{type == 'medical-guide'}}">
<view class="popup-container">
<view class="container" style="background: url('{{imageUrl}}bg43.png?t={{Timestamp}}') no-repeat top center/100%">
<view class="tip">医保政策轻松查询</view>
<view class="btn" bind:tap="handleOk">立即查询</view>
</view>
</view>
</view>
<view class="popup-question-toast" wx:if="{{type == 'question-toast'}}">
<view class="popup-container">
<view class="title">{{params.title}}</view>
<view class="scroll" wx:if="{{params.type==1}}">
GO-QOL生活质量量表,是《中国甲状腺相关眼病诊断和治疗指南(2022年)》中提及的唯一可居家自测的甲状腺眼病评估量表,反映了疾病对患者生活质量的影响。得分越低影响越大,让患者主观感受清晰可见。
</view>
<view class="scroll" wx:elif="{{params.type==2}}">
《中国甲状腺相关眼病诊断和治疗指南(2022年)》指出,剂量越高短期效果可能越好,但不良反应也会更大,并且同一疗程需严格控制累积剂量。
且风险与用药剂量和用药时间相关。
<view></view>
规范记录每次用药时间、剂量与不适反应,可帮助及时发现风险线索,便于医生综合评估疗效与安全性并调整方案;这是用药安全管理的关键一步。
</view>
</view>
</view>
<view class="popup-enter-info" wx:if="{{type==='guideEnterInfo'}}">
<image class="badge" src="{{imageUrl}}icon133.png?t={{Timestamp}}"></image>
<view class="popup-container">
<van-icon class="p-close" name="cross" bind:tap="handleCancel" />
<view class="title">完善个人信息</view>
<view class="content">
完善个人信息,可获得
<text class="high">【医生】</text>
更多关注
</view>
<view class="btn" bind:tap="handleOk">确认</view>
</view>
</view>
<view class="popup-enter-info" wx:if="{{type==='guideEnterInfoJump'}}">
<image class="badge" src="{{imageUrl}}icon133.png?t={{Timestamp}}"></image>
<view class="popup-container">
<van-icon class="p-close" name="cross" bind:tap="handleCancel" />
<view class="title">完善个人信息</view>
<view class="content">
完善个人信息,可获得
<text class="high">【医生】</text>
更多关注
</view>
<view class="btn" bind:tap="handleOk">确认</view>
</view>
</view>
<view class="popup-qw" wx:if="{{type==='guideQw'}}">
<view
class="popup-container"
style="background: url('{{imageUrl}}bg49.png?t={{Timestamp}}') no-repeat top center/100%"
>
<image class="code" src="{{params.ConsultQwImg}}" show-menu-by-longpress></image>
</view>
</view>
<view class="popup-note-guide" wx:if="{{type==='noteGuide'}}">
<view class="popup-container" bind:tap="handleCancel">
<image class="guide" src="{{imageUrl}}bg59.png?t={{Timestamp}}"></image>
</view>
</view>
<van-icon wx:if="{{params.close}}" class="popup-close" bind:tap="handleCancel" name="close" />
</van-popup> </van-popup>

87
src/components/uploadFile/index.ts

@ -1,4 +1,4 @@
const app = getApp<IAppOption>() const app = getApp<IAppOption>();
// pages/story/a.ts // pages/story/a.ts
Component({ Component({
@ -32,17 +32,17 @@ Component({
*/ */
methods: { methods: {
GetExtensionFileName(pathfilename) { GetExtensionFileName(pathfilename) {
const reg = /(\\+)/g const reg = /(\\+)/g;
const pString = pathfilename.replace(reg, '#') // 用正则表达式来将\或\\替换成# const pString = pathfilename.replace(reg, '#'); //用正则表达式来将\或\\替换成#
const arr = pString.split('#') // 以“#”为分隔符,将字符分解为数组 例如 D Program Files bg.png const arr = pString.split('#'); // 以“#”为分隔符,将字符分解为数组 例如 D Program Files bg.png
const lastString = arr[arr.length - 1] // 取最后一个字符 const lastString = arr[arr.length - 1]; //取最后一个字符
const arr2 = lastString.split('.') // 再以"."作为分隔符 const arr2 = lastString.split('.'); // 再以"."作为分隔符
return arr2[arr2.length - 1] // 将后缀名返回出来 return arr2[arr2.length - 1]; //将后缀名返回出来
}, },
handleAfterRead(e) { handleAfterRead(e) {
this.uploadFile(e.detail.file).then((res) => { this.uploadFile(e.detail.file).then((res) => {
this.triggerEvent('file', res as object) this.triggerEvent('file', res as object);
}) });
}, },
handleChooseAvatar(e) { handleChooseAvatar(e) {
this.uploadFile({ this.uploadFile({
@ -50,8 +50,8 @@ Component({
tempFilePath: e.detail.avatarUrl, tempFilePath: e.detail.avatarUrl,
size: 0, size: 0,
}).then((res) => { }).then((res) => {
this.triggerEvent('file', res as object) this.triggerEvent('file', res as object);
}) });
}, },
handleChooseFile() { handleChooseFile() {
wx.chooseMessageFile({ wx.chooseMessageFile({
@ -63,44 +63,41 @@ Component({
fileType: res.tempFiles[0].type, fileType: res.tempFiles[0].type,
tempFilePath: res.tempFiles[0].path, tempFilePath: res.tempFiles[0].path,
}).then((res) => { }).then((res) => {
this.triggerEvent('file', res as object) this.triggerEvent('file', res as object);
}) });
}, },
fail() { fail() {
wx.showToast({ wx.showToast({
icon: 'none', icon: 'none',
title: '取消选择', title: '取消选择',
}) });
}, },
}) });
}, },
uploadFile(item) { uploadFile(item) {
wx.showLoading({ wx.showLoading({
title: '正在上传', title: '正在上传',
}) });
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let url = `${app.globalData.upFileUrl}?r=file-service/upload-` let url = `${app.globalData.upFileUrl}?r=file-service/upload-`;
if (item.fileType === 'image') { if (item.fileType === 'image') {
url += 'img' url += 'img';
} } else if (item.fileType === 'video' || item.type === 'video') {
else if (item.fileType === 'video' || item.type === 'video') { url += 'video';
url += 'video' item.tempFilePath = item.url;
item.tempFilePath = item.url } else if (item.fileType === 'audio') {
} url += 'audio';
else if (item.fileType === 'audio') { } else {
url += 'audio' url += 'doc';
}
else {
url += 'doc'
} }
wx.uploadFile({ wx.uploadFile({
filePath: item.tempFilePath, filePath: item.tempFilePath,
name: 'file', name: 'file',
url, url,
success: (res) => { success: (res) => {
wx.hideLoading() wx.hideLoading();
const data = JSON.parse(res.data) const data = JSON.parse(res.data);
const suffix = this.GetExtensionFileName(data.data.Url) const suffix = this.GetExtensionFileName(data.data.Url);
const expandJson = { const expandJson = {
fileId: '', fileId: '',
name: item.name || `病历相关文件.${suffix}`, name: item.name || `病历相关文件.${suffix}`,
@ -112,26 +109,24 @@ Component({
duration: 0, duration: 0,
videoUrl: '', videoUrl: '',
hash: '', hash: '',
} };
if (item.fileType === 'image') { if (item.fileType === 'image') {
expandJson.imgUrl = data.data.Url expandJson.imgUrl = data.data.Url;
} } else if (item.fileType === 'video' || item.type === 'video') {
else if (item.fileType === 'video' || item.type === 'video') { expandJson.imgUrl = data.data.SnapshotUrl;
expandJson.imgUrl = data.data.SnapshotUrl } else if (item.fileType === 'audio') {
} expandJson.duration = Number.parseInt(String(item.duration / 1000));
else if (item.fileType === 'audio') {
expandJson.duration = Number.parseInt(String(item.duration / 1000))
} }
resolve(expandJson) resolve(expandJson);
}, },
fail() { fail() {
wx.hideLoading() wx.hideLoading();
reject(new Error('上传失败')) reject(new Error('上传失败'));
}, },
}) });
}) });
}, },
}, },
}) });
export {} export {};

28
src/components/viewFile/index.js

@ -1,5 +1,5 @@
// components/viewFile/index.js // components/viewFile/index.js
const app = getApp() const app = getApp();
Component({ Component({
/** /**
* 组件的属性列表 * 组件的属性列表
@ -25,7 +25,7 @@ Component({
* 组件的初始数据 * 组件的初始数据
*/ */
data: { data: {
Timestamp: app.globalData.Timestamp, Timestamp: app.globalData.Timestamp,
imageUrl: app.globalData.imageUrl, imageUrl: app.globalData.imageUrl,
}, },
@ -34,28 +34,28 @@ Component({
*/ */
methods: { methods: {
deleteFile(e) { deleteFile(e) {
const { index, item } = e.currentTarget.dataset const { index, item } = e.currentTarget.dataset;
this.triggerEvent('deleteFile', { this.triggerEvent("deleteFile", {
index, index,
item, item,
}) });
}, },
viewFile(e) { viewFile(e) {
const { index } = e.currentTarget.dataset const { index } = e.currentTarget.dataset;
const { fileList } = this.properties const { fileList } = this.properties;
const sources = [] let sources = [];
fileList.map((e) => { fileList.map((e) => {
const obj = { const obj = {
url: e.fileUrl, url: e.fileUrl,
type: e.type, // image video type: e.type, // image video
poster: e.imgUrl, poster: e.imgUrl,
} };
sources.push(obj) sources.push(obj);
}) });
wx.previewMedia({ wx.previewMedia({
current: index, current: index,
sources, sources: sources,
}) });
}, },
}, },
}) });

2
src/components/viewFile/index.json

@ -3,4 +3,4 @@
"usingComponents": { "usingComponents": {
"van-icon": "@vant/weapp/icon/index" "van-icon": "@vant/weapp/icon/index"
} }
} }

7
src/components/viewVideo/index.scss

@ -27,10 +27,9 @@
align-items: center; align-items: center;
flex-direction: row-reverse; flex-direction: row-reverse;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.02) 0%, #000000 100%); background: linear-gradient(180deg, rgba(0, 0, 0, 0.02) 0%, #000000 100%);
> view, >view,>image{
> image { margin-right: 32rpx;
margin-right: 32rpx; };
}
transition: all 0.8s; transition: all 0.8s;
.time { .time {
font-size: 24rpx; font-size: 24rpx;

228
src/components/zd-navBar/navBar.js

@ -1,35 +1,35 @@
const app = getApp() const app = getApp();
Component({ Component({
options: { options: {
multipleSlots: true, multipleSlots: true,
addGlobalClass: true, addGlobalClass: true,
}, },
properties: { properties: {
slotLeft: { slotLeft:{
type: Boolean, type:Boolean,
value: false, value:false,
}, },
extClass: { extClass: {
type: String, type: String,
value: '', value: "",
}, },
background: { background: {
type: String, type: String,
value: 'transparent', value: "transparent",
observer: '_showChange', observer: "_showChange",
}, },
backgroundColorTop: { backgroundColorTop: {
type: String, type: String,
value: 'transparent', value: "transparent",
observer: '_showChangeBackgroundColorTop', observer: "_showChangeBackgroundColorTop",
}, },
color: { color: {
type: String, type: String,
value: '#000000', value: "#000000",
}, },
title: { title: {
type: String, type: String,
value: '', value: "",
}, },
back: { back: {
type: Boolean, type: Boolean,
@ -41,7 +41,7 @@ Component({
}, },
iconTheme: { iconTheme: {
type: String, type: String,
value: 'nuohe', value: "nuohe",
}, },
/* animated: { /* animated: {
type: Boolean, type: Boolean,
@ -61,11 +61,11 @@ Component({
value: false, value: false,
}, },
}, },
created() { created: function () {
this.getSystemInfo() this.getSystemInfo();
}, },
attached() { attached: function () {
this.setStyle() // 设置样式 this.setStyle(); //设置样式
}, },
data: { data: {
imageUrl: app.globalData.imageUrl, imageUrl: app.globalData.imageUrl,
@ -73,52 +73,50 @@ Component({
isHome: false, isHome: false,
}, },
pageLifetimes: { pageLifetimes: {
show() { show: function () {
if (getApp().globalSystemInfo.ios) { if (getApp().globalSystemInfo.ios) {
this.getSystemInfo() this.getSystemInfo();
this.setStyle() // 设置样式1 this.setStyle(); //设置样式1
} }
const pages = getCurrentPages() let pages = getCurrentPages();
this.setData({ this.setData({
isHome: !pages[pages.length - 2], isHome: !pages[pages.length - 2],
}) });
}, },
hide() {}, hide: function () {},
}, },
methods: { methods: {
setStyle(life) { setStyle: function (life) {
const { statusBarHeight, navBarHeight, capsulePosition, navBarExtendHeight, ios, windowWidth } const { statusBarHeight, navBarHeight, capsulePosition, navBarExtendHeight, ios, windowWidth } =
= getApp().globalSystemInfo getApp().globalSystemInfo;
const { back, home, title } = this.data const { back, home, title } = this.data;
const rightDistance = windowWidth - capsulePosition.right // 胶囊按钮右侧到屏幕右侧的边距 let rightDistance = windowWidth - capsulePosition.right; //胶囊按钮右侧到屏幕右侧的边距
const leftWidth = windowWidth - capsulePosition.left // 胶囊按钮左侧到屏幕右侧的边距 let leftWidth = windowWidth - capsulePosition.left; //胶囊按钮左侧到屏幕右侧的边距
this.setData({ this.setData({
leftWidth, leftWidth: leftWidth,
}) });
const navigationbarinnerStyle = [ let navigationbarinnerStyle = [
`color: ${this.data.color}`, `color: ${this.data.color}`,
`background: ${this.data.background}`, `background: ${this.data.background}`,
`height:${navBarHeight + navBarExtendHeight}px`, `height:${navBarHeight + navBarExtendHeight}px`,
`padding-top:${statusBarHeight}px`, `padding-top:${statusBarHeight}px`,
`padding-right:${leftWidth}px`, `padding-right:${leftWidth}px`,
`padding-bottom:${navBarExtendHeight}px`, `padding-bottom:${navBarExtendHeight}px`,
].join(';') ].join(";");
let navBarLeft = [] let navBarLeft = [];
if ((back && !home) || (!back && home)) { if ((back && !home) || (!back && home)) {
navBarLeft = [`width:${capsulePosition.width}px`, `height:${capsulePosition.height}px`].join(';') navBarLeft = [`width:${capsulePosition.width}px`, `height:${capsulePosition.height}px`].join(";");
} } else if ((back && home) || title) {
else if ((back && home) || title) {
navBarLeft = [ navBarLeft = [
`width:${capsulePosition.width}px`, `width:${capsulePosition.width}px`,
`height:${capsulePosition.height}px`, `height:${capsulePosition.height}px`,
`margin-left:${rightDistance}px`, `margin-left:${rightDistance}px`,
].join(';') ].join(";");
} } else {
else { navBarLeft = [`width:auto`, `margin-left:0px`].join(";");
navBarLeft = [`width:auto`, `margin-left:0px`].join(';')
} }
if (life === 'created') { if (life === "created") {
this.data = { this.data = {
navigationbarinnerStyle, navigationbarinnerStyle,
navBarLeft, navBarLeft,
@ -126,9 +124,8 @@ Component({
capsulePosition, capsulePosition,
navBarExtendHeight, navBarExtendHeight,
ios, ios,
} };
} } else {
else {
this.setData({ this.setData({
navigationbarinnerStyle, navigationbarinnerStyle,
navBarLeft, navBarLeft,
@ -136,125 +133,118 @@ Component({
capsulePosition, capsulePosition,
navBarExtendHeight, navBarExtendHeight,
ios, ios,
}) });
} }
}, },
_showChange(value) { _showChange: function (value) {
this.setStyle() this.setStyle();
}, },
// 返回事件 // 返回事件
back() { back: function () {
const pages = getCurrentPages() let pages = getCurrentPages();
if (app.globalData.backPage) { if (app.globalData.backPage) {
wx.reLaunch({ wx.reLaunch({
url: app.globalData.backPage, url: app.globalData.backPage,
}) });
app.globalData.backPage = null app.globalData.backPage = null;
return return;
} }
if (!pages[pages.length - 2] && !app.globalData.anyWhere) { if (!pages[pages.length - 2] && !app.globalData.anyWhere) {
wx.reLaunch({ wx.reLaunch({
url: '/pages/index/index', url: "/pages/index/index",
}) });
return return;
} }
this.triggerEvent('back', { delta: this.data.delta }) this.triggerEvent("back", { delta: this.data.delta });
}, },
home() { home: function () {
wx.reLaunch({ wx.reLaunch({
url: '/pages/start/index', url: "/pages/start/index",
}) });
}, },
search() { search: function () {
this.triggerEvent('search', {}) this.triggerEvent("search", {});
}, },
getSystemInfo() { getSystemInfo() {
const app = getApp() var app = getApp();
if (app.globalSystemInfo && !app.globalSystemInfo.ios) { if (app.globalSystemInfo && !app.globalSystemInfo.ios) {
return app.globalSystemInfo return app.globalSystemInfo;
} } else {
else { let systemInfo = wx.getSystemInfoSync();
const systemInfo = wx.getSystemInfoSync() let ios = !!(systemInfo.system.toLowerCase().search("ios") + 1);
const ios = !!(systemInfo.system.toLowerCase().search('ios') + 1) let rect;
let rect
try { try {
rect = wx.getMenuButtonBoundingClientRect ? wx.getMenuButtonBoundingClientRect() : null rect = wx.getMenuButtonBoundingClientRect ? wx.getMenuButtonBoundingClientRect() : null;
if (rect === null) { if (rect === null) {
throw 'getMenuButtonBoundingClientRect error' throw "getMenuButtonBoundingClientRect error";
} }
// 取值为0的情况 有可能width不为0 top为0的情况 //取值为0的情况 有可能width不为0 top为0的情况
if (!rect.width || !rect.top || !rect.left || !rect.height) { if (!rect.width || !rect.top || !rect.left || !rect.height) {
throw 'getMenuButtonBoundingClientRect error' throw "getMenuButtonBoundingClientRect error";
} }
} } catch (error) {
catch (error) { let gap = ""; //胶囊按钮上下间距 使导航内容居中
let gap = '' // 胶囊按钮上下间距 使导航内容居中 let width = 96; //胶囊的宽度
let width = 96 // 胶囊的宽度 if (systemInfo.platform === "android") {
if (systemInfo.platform === 'android') { gap = 8;
gap = 8 width = 96;
width = 96 } else if (systemInfo.platform === "devtools") {
}
else if (systemInfo.platform === 'devtools') {
if (ios) { if (ios) {
gap = 5.5 // 开发工具中ios手机 gap = 5.5; //开发工具中ios手机
} else {
gap = 7.5; //开发工具中android和其它手机
} }
else { } else {
gap = 7.5 // 开发工具中android和其它手机 gap = 4;
} width = 88;
}
else {
gap = 4
width = 88
} }
if (!systemInfo.statusBarHeight) { if (!systemInfo.statusBarHeight) {
// 开启wifi的情况下修复statusBarHeight值获取不到 //开启wifi的情况下修复statusBarHeight值获取不到
systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20 systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20;
} }
rect = { rect = {
// 获取不到胶囊信息就自定义重置一个 //获取不到胶囊信息就自定义重置一个
bottom: systemInfo.statusBarHeight + gap + 32, bottom: systemInfo.statusBarHeight + gap + 32,
height: 32, height: 32,
left: systemInfo.windowWidth - width - 10, left: systemInfo.windowWidth - width - 10,
right: systemInfo.windowWidth - 10, right: systemInfo.windowWidth - 10,
top: systemInfo.statusBarHeight + gap, top: systemInfo.statusBarHeight + gap,
width, width: width,
} };
console.log('error', error) console.log("error", error);
console.log('rect', rect) console.log("rect", rect);
} }
let navBarHeight = '' let navBarHeight = "";
if (!systemInfo.statusBarHeight) { if (!systemInfo.statusBarHeight) {
systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20 systemInfo.statusBarHeight = systemInfo.screenHeight - systemInfo.windowHeight - 20;
navBarHeight = (function () { navBarHeight = (function () {
const gap = rect.top - systemInfo.statusBarHeight let gap = rect.top - systemInfo.statusBarHeight;
return 2 * gap + rect.height return 2 * gap + rect.height;
})() })();
systemInfo.statusBarHeight = 0 systemInfo.statusBarHeight = 0;
systemInfo.navBarExtendHeight = 0 // 下方扩展4像素高度 防止下方边距太小 systemInfo.navBarExtendHeight = 0; //下方扩展4像素高度 防止下方边距太小
} } else {
else {
navBarHeight = (function () { navBarHeight = (function () {
const gap = rect.top - systemInfo.statusBarHeight let gap = rect.top - systemInfo.statusBarHeight;
return systemInfo.statusBarHeight + 2 * gap + rect.height return systemInfo.statusBarHeight + 2 * gap + rect.height;
})() })();
if (ios) { if (ios) {
systemInfo.navBarExtendHeight = 4 // 下方扩展4像素高度 防止下方边距太小 systemInfo.navBarExtendHeight = 4; //下方扩展4像素高度 防止下方边距太小
} } else {
else { systemInfo.navBarExtendHeight = 0;
systemInfo.navBarExtendHeight = 0
} }
} }
systemInfo.navBarHeight = navBarHeight // 导航栏高度不包括statusBarHeight systemInfo.navBarHeight = navBarHeight; //导航栏高度不包括statusBarHeight
systemInfo.capsulePosition = rect // 右上角胶囊按钮信息bottom: 58 height: 32 left: 317 right: 404 top: 26 width: 87 目前发现在大多机型都是固定值 为防止不一样所以会使用动态值来计算nav元素大小 systemInfo.capsulePosition = rect; //右上角胶囊按钮信息bottom: 58 height: 32 left: 317 right: 404 top: 26 width: 87 目前发现在大多机型都是固定值 为防止不一样所以会使用动态值来计算nav元素大小
systemInfo.ios = ios // 是否ios systemInfo.ios = ios; //是否ios
app.globalSystemInfo = systemInfo // 将信息保存到全局变量中,后边再用就不用重新异步获取了 app.globalSystemInfo = systemInfo; //将信息保存到全局变量中,后边再用就不用重新异步获取了
// console.log('systemInfo', systemInfo); //console.log('systemInfo', systemInfo);
return systemInfo return systemInfo;
} }
}, },
}, },
}) });

2
src/components/zd-navBar/navBar.scss

@ -75,7 +75,7 @@ page {
} }
.lxy-nav-bar__buttons::after { .lxy-nav-bar__buttons::after {
position: absolute; position: absolute;
content: ''; content: "";
width: 1rpx; width: 1rpx;
height: 18.4px; height: 18.4px;
background: rgba(204, 204, 204, 0.6); background: rgba(204, 204, 204, 0.6);

164
src/components/zdUploadFile/index.js

@ -1,5 +1,5 @@
// components/uploadFile/index.js // components/uploadFile/index.js
const app = getApp() const app = getApp();
Component({ Component({
/** /**
* 组件的属性列表 * 组件的属性列表
@ -17,17 +17,17 @@ Component({
}, },
accept: { accept: {
type: String, type: String,
value: 'media', value: "media",
}, },
fileTypes: { fileTypes: {
// 上传类型 // 上传类型
type: Array, type: Array,
value: ['image', 'video'], value: ["image", "video"],
}, },
// 拍照和相机 // 拍照和相机
sourceType: { sourceType: {
type: Array, type: Array,
value: ['album', 'camera'], value: ["album", "camera"],
}, },
// 是否可以删除 // 是否可以删除
canDelete: { canDelete: {
@ -67,64 +67,62 @@ Component({
*/ */
methods: { methods: {
viewFile(e) { viewFile(e) {
const { index } = e.currentTarget.dataset const { index } = e.currentTarget.dataset;
const { fileList } = this.properties const { fileList } = this.properties;
const sources = [] let sources = [];
fileList.map((e) => { fileList.map((e) => {
const obj = { const obj = {
url: e.fileUrl, url: e.fileUrl,
type: e.type, // image video type: e.type, // image video
poster: e.imgUrl, poster: e.imgUrl,
} };
sources.push(obj) sources.push(obj);
}) });
wx.previewMedia({ wx.previewMedia({
current: index, current: index,
sources, sources: sources,
}) });
}, },
deleteFile(e) { deleteFile(e) {
const { index, item } = e.currentTarget.dataset const { index, item } = e.currentTarget.dataset;
this.triggerEvent('deleteFile', { this.triggerEvent("deleteFile", {
index, index,
item, item,
}) });
}, },
downFile(e) { downFile(e) {
const { item } = e.currentTarget.dataset const { item } = e.currentTarget.dataset;
wx.showToast({ wx.showToast({
title: '正在下载,请稍后...', title: "正在下载,请稍后...",
icon: 'none', icon: "none",
}) });
wx.downloadFile({ wx.downloadFile({
url: item.fileUrl, url: item.fileUrl,
success(res) { success(res) {
if (item.type === 'image') { if (item.type === "image") {
wx.saveImageToPhotosAlbum({ wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath, filePath: res.tempFilePath,
success: () => { success: () => {
wx.showToast({ wx.showToast({
title: '下载成功', title: "下载成功",
}) });
}, },
}) });
} } else if (item.type === "video") {
else if (item.type === 'video') {
wx.saveVideoToPhotosAlbum({ wx.saveVideoToPhotosAlbum({
filePath: res.tempFilePath, filePath: res.tempFilePath,
success: () => { success: () => {
wx.showToast({ wx.showToast({
title: '下载成功', title: "下载成功",
}) });
}, },
}) });
} } else {
else {
wx.showToast({ wx.showToast({
title: '附件请到pc端下载!', title: "附件请到pc端下载!",
icon: 'none', icon: "none",
}) });
// wx.saveFile({ // wx.saveFile({
// tempFilePath: res.tempFilePath, // tempFilePath: res.tempFilePath,
// success: () => { // success: () => {
@ -138,96 +136,96 @@ Component({
// }) // })
} }
}, },
}) });
}, },
uploadFile(item) { uploadFile(item) {
return new Promise((resolve, resject) => { return new Promise((resolve, resject) => {
let url = `${app.globalData.upFileUrl}?r=file-service/upload-` let url = `${app.globalData.upFileUrl}?r=file-service/upload-`;
if (item.fileType === 'image') { if (item.fileType === "image") {
url += 'img' url += "img";
} }
if (item.fileType === 'video') { if (item.fileType === "video") {
url += 'video' url += "video";
} }
const that = this let that = this;
wx.uploadFile({ wx.uploadFile({
filePath: item.tempFilePath, filePath: item.tempFilePath,
name: 'file', name: "file",
url, url: url,
success(res) { success(res) {
const data = JSON.parse(res.data) let data = JSON.parse(res.data);
const expandJson = { let expandJson = {
fileId: '', fileId: "",
name: data.data.Url, name: data.data.Url,
size: (item.size / 1024).toFixed(2), size: (item.size / 1024).toFixed(2),
fileUrl: data.data.Url, fileUrl: data.data.Url,
suffix: that.GetExtensionFileName(data.data.Url), suffix: that.GetExtensionFileName(data.data.Url),
type: item.fileType, type: item.fileType,
};
if (item.fileType === "image") {
expandJson.imgUrl = data.data.Url;
} }
if (item.fileType === 'image') { if (item.fileType === "video") {
expandJson.imgUrl = data.data.Url expandJson.imgUrl = data.data.SnapshotUrl;
}
if (item.fileType === 'video') {
expandJson.imgUrl = data.data.SnapshotUrl
} }
resolve(expandJson) resolve(expandJson);
}, },
fail() { fail() {
resject() resject();
}, },
}) });
}) });
}, },
GetExtensionFileName(pathfilename) { GetExtensionFileName(pathfilename) {
const reg = /(\\+)/g var reg = /(\\+)/g;
const pString = pathfilename.replace(reg, '#') // 用正则表达式来将\或\\替换成# var pString = pathfilename.replace(reg, "#"); //用正则表达式来将\或\\替换成#
const arr = pString.split('#') // 以“#”为分隔符,将字符分解为数组 例如 D Program Files bg.png var arr = pString.split("#"); // 以“#”为分隔符,将字符分解为数组 例如 D Program Files bg.png
const lastString = arr[arr.length - 1] // 取最后一个字符 var lastString = arr[arr.length - 1]; //取最后一个字符
const arr2 = lastString.split('.') // 再以"."作为分隔符 var arr2 = lastString.split("."); // 再以"."作为分隔符
return arr2[arr2.length - 1] // 将后缀名返回出来 return arr2[arr2.length - 1]; //将后缀名返回出来
}, },
upFile(data) { upFile(data) {
wx.showLoading({ wx.showLoading({
title: '正在上传', title: "正在上传",
}) });
const apiArr = [] let apiArr = [];
data.map((e) => { data.map((e) => {
apiArr.push(this.uploadFile(e)) apiArr.push(this.uploadFile(e));
}) });
Promise.all(apiArr) Promise.all(apiArr)
.then((res) => { .then((res) => {
wx.hideLoading({ wx.hideLoading({
success: () => { success: () => {
this.triggerEvent('setData', res) this.triggerEvent("setData", res);
}, },
}) });
}) })
.catch(() => { .catch(() => {
wx.showToast({ wx.showToast({
title: '上传失败', title: "上传失败",
icon: 'error', icon: "error",
}) });
}) });
}, },
selectFile() { selectFile() {
let { fileList, maxNum, sourceType, fileTypes, count = 0 } = this.properties let { fileList, maxNum, sourceType, fileTypes, count = 0 } = this.properties;
const that = this var that = this;
if (maxNum >= 0 && count == 0) { if (maxNum >= 0 && count == 0) {
count = maxNum - fileList.length count = maxNum - fileList.length;
} }
this.triggerEvent('choose') this.triggerEvent("choose");
wx.chooseMedia({ wx.chooseMedia({
mediaType: fileTypes, mediaType: fileTypes,
count, count: count,
sourceType, sourceType: sourceType,
sizeType: ['original'], sizeType: ["original"],
success(res) { success(res) {
res.tempFiles.map((e) => { res.tempFiles.map((e) => {
e.fileType = e.fileType || res.type e.fileType = e.fileType || res.type;
}) });
that.upFile(res.tempFiles) that.upFile(res.tempFiles);
}, },
}) });
}, },
}, },
}) });

12
src/config.ts

@ -1,12 +0,0 @@
export default {
wxf9ce8010f1ad24aa: {
url: 'https://m.xd.hbraas.com',
upFileUrl: 'https://m.xd.hbraas.com/',
imageUrl: 'https://m.xd.hbraas.com/xd/',
},
wx71ac9c27c3c3e3f4: {
url: 'https://m.xd.hbsaas.com',
upFileUrl: 'https://m.xd.hbsaas.com/',
imageUrl: 'https://m.xd.hbsaas.com/api/xd/',
},
}

74
src/custom-tab-bar/index.scss

@ -4,6 +4,76 @@
justify-content: space-between; justify-content: space-between;
background-color: #fff; background-color: #fff;
box-shadow: 0rpx 3rpx 27rpx 0rpx rgba(40, 48, 49, 0.1); box-shadow: 0rpx 3rpx 27rpx 0rpx rgba(40, 48, 49, 0.1);
.custom {
flex-shrink: 0;
position: relative;
width: 94rpx;
height: 64rpx;
.add {
position: absolute;
top: -42rpx;
width: 94rpx;
height: 94rpx;
}
.popup-tip {
padding: 20rpx 34rpx 28rpx;
position: absolute;
top: -60rpx;
left: 50%;
transform: translate(-50%, -100%);
border-radius: 16rpx;
background: linear-gradient(90deg, #00b4c5 0%, #54e2b4 100%);
box-shadow: 0 4rpx 11rpx rgba(0, 0, 0, 0.08);
.close {
position: absolute;
top: -10rpx;
right: -10rpx;
width: 40rpx;
height: 40rpx;
}
.content {
text-align: center;
font-size: 32rpx;
color: #fff;
white-space: nowrap;
line-height: 48rpx;
.plus {
color: #fff;
font-size: 48rpx;
font-weight: bold;
}
}
.pt-footer {
margin-top: 16rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 24rpx;
white-space: nowrap;
.ok {
padding: 16rpx 42rpx;
font-size: 24rpx;
color: #00b4c5;
font-size: 32rpx;
line-height: 32rpx;
border-radius: 120rpx;
background: #fff;
}
}
&::after {
position: absolute;
content: "";
bottom: -10rpx;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-style: solid;
border-width: 12rpx 12rpx 0 12rpx;
border-color: #56cabb transparent transparent transparent;
}
}
}
.tab-item { .tab-item {
position: relative; position: relative;
padding-top: 10rpx; padding-top: 10rpx;
@ -40,7 +110,7 @@
.name { .name {
margin-top: 8rpx; margin-top: 8rpx;
font-size: 22rpx; font-size: 22rpx;
color: #69686e; color: rgba(20, 21, 21, 1);
line-height: 21rpx; line-height: 21rpx;
} }
&.active { &.active {
@ -53,7 +123,7 @@
} }
} }
.name { .name {
color: #211d2e; color: rgba(0, 180, 197, 1);
} }
} }
} }

68
src/custom-tab-bar/index.ts

@ -1,4 +1,4 @@
const _app = getApp<IAppOption>() const _app = getApp<IAppOption>();
// pages/story/a.ts // pages/story/a.ts
Component({ Component({
@ -16,33 +16,37 @@ Component({
notice: false, notice: false,
tabbar: [ tabbar: [
{ {
path: '/pages/home/index', path: "/pages/home/index",
name: '首页', name: "首页",
icon: 'tab1.png', icon: "tab1.png",
iconActive: 'tab-active1.png', iconActive: "tab-active1.png",
activeIndex: 0,
},
{
path: '/pages/information/index',
name: '资料库',
icon: 'tab2.png',
iconActive: 'tab-active2.png',
activeIndex: 1, activeIndex: 1,
}, },
{ {
path: '/pages/d_interactive/index', path: "/pages/cases/index",
name: '互动', name: "病历",
icon: 'tab3.png', icon: "tab2.png",
iconActive: 'tab-active3.png', iconActive: "tab-active2.png",
activeIndex: 2, activeIndex: 2,
}, },
{ {
path: '/pages/my/index', custom: true,
name: '我的', path: "/module1/pages/entryCases/index",
icon: 'tab4.png', },
iconActive: 'tab-active4.png', {
path: "/pages/chatRoomList/index",
name: "学习窗",
icon: "tab3.png",
iconActive: "tab-active3.png",
activeIndex: 3, activeIndex: 3,
}, },
{
path: "/pages/my/index",
name: "我的",
icon: "tab4.png",
iconActive: "tab-active4.png",
activeIndex: 4,
},
], ],
userInfo: {}, userInfo: {},
}, },
@ -51,16 +55,20 @@ Component({
*/ */
methods: { methods: {
handleTab(e: any) { handleTab(e: any) {
const { index } = e.currentTarget.dataset const { index } = e.currentTarget.dataset;
const tab = this.data.tabbar[index] const tab = this.data.tabbar[index];
this.setData({ if (tab.custom) {
active: tab.activeIndex, this.handleClsoeCaseTip();
}) wx.navigateTo({
wx.switchTab({ url: tab.path,
url: tab.path, });
}) } else {
wx.switchTab({
url: tab.path,
});
}
}, },
}, },
}) });
export {} export {};

23
src/custom-tab-bar/index.wxml

@ -1,6 +1,27 @@
<view class="tabbar"> <view class="tabbar">
<block wx:for="{{tabbar}}" wx:key="index"> <block wx:for="{{tabbar}}" wx:key="index">
<view class="tab-item {{active==item.activeIndex && 'active'}}" bind:tap="handleTab" data-index="{{index}}"> <view class="custom" wx:if="{{item.custom && userInfo.DoctorLevel<3}}" bind:tap="handleTab" data-index="{{index}}">
<image class="add" src="{{imageUrl}}tabbar/add.png?t={{Timestamp}}"></image>
<view class="popup-tip" wx:if="{{showEntryCase}}">
<image class="close" catch:tap="handleClsoeCaseTip" src="{{imageUrl}}icon-close-white.png?t={{Timestamp}}"></image>
<view class="content">
点击
<text class="plus">+</text>
,可录入病历
<view></view>
邀约合作医生一起讨论哦
</view>
<view class="pt-footer">
<view class="ok">去录入</view>
</view>
</view>
</view>
<view
class="tab-item {{active===item.activeIndex && 'active'}}"
wx:elif="{{!item.custom}}"
bind:tap="handleTab"
data-index="{{index}}"
>
<view class="icon-wrap"> <view class="icon-wrap">
<view class="dot" wx:if="{{notice && index===3}}"></view> <view class="dot" wx:if="{{notice && index===3}}"></view>
<image class="icon" src="{{imageUrl}}tabbar/{{item.icon}}?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}tabbar/{{item.icon}}?t={{Timestamp}}"></image>

2
src/doc/pages/doc1/index.scss

@ -1,3 +1,3 @@
.page { .page{
padding: 0 40rpx; padding: 0 40rpx;
} }

6
src/doc/pages/doc1/index.ts

File diff suppressed because one or more lines are too long

2
src/doc/pages/doc2/index.scss

@ -1,3 +1,3 @@
.mp-html { .mp-html{
padding: 20rpx 40rpx; padding: 20rpx 40rpx;
} }

5184
src/gift/compontnts/echart/echarts.js

File diff suppressed because one or more lines are too long

6
src/gift/pages/conformOrder/index.json

@ -0,0 +1,6 @@
{
"navigationBarTitleText": "确认订单",
"usingComponents": {
"van-icon": "@vant/weapp/icon/index"
}
}

184
src/gift/pages/conformOrder/index.scss

@ -0,0 +1,184 @@
.page {
padding: 34rpx 40rpx;
.site {
padding: 40rpx 32rpx;
background: #ffffff;
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05);
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
.wrap {
.title {
.label {
width: 72rpx;
height: 36rpx;
border: 1rpx solid #e04775;
font-size: 24rpx;
color: #e04775;
text-align: center;
border-radius: 10rpx;
box-sizing: border-box;
}
.name {
margin-top: -42rpx;
text-indent: 80rpx;
font-size: 36rpx;
line-height: 46rpx;
color: #3f3f3f;
font-weight: bold;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
&.no-indent {
margin-top: 0;
text-indent: 0;
}
}
}
.content {
margin-top: 0;
margin-top: 12rpx;
font-size: 28rpx;
color: #b6b7ba;
}
}
.more {
flex-shrink: 0;
}
}
.shop {
margin-top: 16px;
padding: 40rpx 32rpx;
background: #ffffff;
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05);
border-radius: 24rpx;
.shop-header {
padding-bottom: 10px;
display: flex;
.shop-img {
flex-shrink: 0;
width: 204rpx;
height: 204rpx;
border-radius: 24rpx;
}
.wrap {
padding-top: 8rpx;
flex: 1;
padding-left: 24rpx;
.name {
font-size: 32rpx;
font-weight: bold;
color: #3f3f3f;
line-height: 44rpx;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.specification {
margin-top: 8rpx;
font-size: 28rpx;
color: #b6b7ba;
}
.price {
margin-top: 14rpx;
display: flex;
align-items: center;
justify-content: space-between;
.num {
font-size: 32rpx;
color: #3f3f3f;
}
.sub {
font-size: 22rpx;
}
.val {
font-size: 28rpx;
color: #b6b7ba;
}
}
}
}
.row {
margin-top: 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
.label {
font-size: 32rpx;
color: #3f3f3f;
}
.content {
font-size: 32rpx;
color: #3f3f3f;
&.yellow {
color: #e04775;
}
.sub {
font-size: 22rpx;
}
}
}
}
.remark {
margin-top: 16px;
padding: 40rpx 32rpx;
background: #ffffff;
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05);
border-radius: 24rpx;
.title {
font-size: 32rpx;
color: #3f3f3f;
font-weight: bold;
}
.textarea {
margin-top: 10rpx;
padding: 24rpx 32rpx;
background-color: #fafafa;
min-height: 196rpx;
border-radius: 16rpx;
box-sizing: border-box;
}
}
.footer {
padding: 24rpx 48rpx 48rpx;
position: fixed;
bottom: 0;
left: 0;
width: 100vw;
box-sizing: border-box;
display: flex;
justify-content: space-between;
align-items: center;
height: 168rpx;
background: #ffffff;
box-shadow: 0rpx 8rpx 20rpx 0rpx rgba(0, 0, 0, 0.26);
.price {
font-size: 28rpx;
color: #b6b7ba;
.num {
font-size: 40rpx;
color: #e04775;
}
.sub {
font-size: 24rpx;
}
}
.submit {
width: 260rpx;
height: 96rpx;
background: #e04775;
border-radius: 48rpx;
text-align: center;
line-height: 96rpx;
color: #fff;
font-weight: bold;
}
}
}

86
src/gift/pages/conformOrder/index.ts

@ -0,0 +1,86 @@
const app = getApp<IAppOption>();
Page({
data: {
id: "",
detail: {},
select: false,
addressDetail: {} as any,
remark: "",
},
onLoad(options) {
this.setData({
id: options.id,
});
},
onShow() {
app.waitLogin().then(() => {
this.getDetail();
if (!this.data.select) {
this.getDefaultAddress();
} else {
this.setData({
select: false,
});
}
});
},
getDefaultAddress() {
wx.ajax({
method: "GET",
url: "?r=zd/patient-address/get-default-address",
data: {},
}).then((res) => {
this.setData({
addressDetail: res,
});
});
},
getDetail() {
wx.ajax({
method: "GET",
url: "?r=zd/gift-order/get-order-detail",
data: {
orderId: this.data.id,
},
}).then((res) => {
this.setData({
detail: res,
});
});
},
handleSite() {
if (this.data.addressDetail) {
wx.navigateTo({
url: "/gift/pages/siteList/index",
});
} else {
wx.navigateTo({
url: "/gift/pages/siteEdit/index",
});
}
},
handleSubmit() {
if (!this.data.addressDetail?.addressId) {
wx.showToast({
icon: "none",
title: "请选择地址",
});
return;
}
wx.ajax({
method: "POST",
url: "?r=zd/gift-order/confirm-order",
data: {
orderId: this.data.id,
addressId: this.data.addressDetail.addressId,
remark: this.data.remark,
},
loading: true,
}).then(() => {
wx.reLaunch({
url: `/gift/pages/orderEnd/index?id=${this.data.id}`,
});
});
},
});

56
src/gift/pages/conformOrder/index.wxml

@ -0,0 +1,56 @@
<view class="page">
<view class="site" bind:tap="handleSite">
<view class="wrap">
<block wx:if="{{addressDetail}}">
<view class="title">
<view class="label" wx:if="{{addressDetail.isDefault==1}}">默认</view>
<view class="name {{addressDetail.isDefault!=1 && 'no-indent'}}">
{{addressDetail.provinceName}}{{addressDetail.cityName}}{{addressDetail.countyName}}{{addressDetail.address}}
</view>
</view>
<view class="content">{{addressDetail.receiveUserName}} {{addressDetail.receiveTelephone}}</view>
</block>
<view class="title" wx:else>请添加收货地址</view>
</view>
<van-icon class="more" name="arrow" />
</view>
<view class="shop">
<view class="shop-header">
<image class="shop-img" src="{{detail.giftBigImg}}"></image>
<view class="wrap">
<view class="name">{{detail.giftName}}</view>
<view class="specification" wx:if="{{detail.specName}}">规格:{{detail.specName}}</view>
<view class="price">
<view class="num">{{detail.giftScore}}<text class="sub">能量</text></view>
<view class="val">x{{detail.orderCount}}</view>
</view>
</view>
</view>
<view class="row">
<view class="label">礼品总价</view>
<view class="content yellow">{{detail.orderScore}}<text class="sub">能量</text></view>
</view>
<view class="row" >
<view class="label">配送方式</view>
<view class="content" style="font-weight:normal">快递配送</view>
</view>
<view class="row" >
<view class="label">商家电话</view>
<view class="content" style="font-weight:normal">{{detail.serviceTel}}</view>
</view>
</view>
<view class="remark">
<view class="title">留言</view>
<textarea class="textarea" model:value="{{remark}}" placeholder="请输入留言" auto-height></textarea>
</view>
<view class="footer">
<view class="price">
共{{detail.orderCount}}件
<view>
合计消耗
<text class="num">{{detail.orderScore}}<text class="sub">能量</text></text>
</view>
</view>
<view class="submit" bind:tap="handleSubmit">提交订单</view>
</view>
</view>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save