Browse Source

接口调整

dev
kola-web 4 weeks ago
parent
commit
1ad4a0ccca
  1. 2
      project.config.json
  2. 25
      src/app.json
  3. 110
      src/app.ts
  4. 144
      src/components/calendar/core.js
  5. 12
      src/components/calendar/helper.js
  6. 1
      src/components/calendar/index.d.ts
  7. 258
      src/components/calendar/index.js
  8. 3
      src/components/calendar/index.json
  9. 116
      src/components/calendar/index.wxml
  10. 247
      src/components/calendar/index.wxss
  11. 212
      src/components/calendar/plugins/holidays/holidays-map.js
  12. 1
      src/components/calendar/plugins/holidays/index.d.ts
  13. 201
      src/components/calendar/plugins/holidays/index.js
  14. 1
      src/components/calendar/plugins/index.d.ts
  15. 18
      src/components/calendar/plugins/index.js
  16. 277
      src/components/calendar/plugins/preset/base.js
  17. 69
      src/components/calendar/plugins/preset/get-calendar-data.js
  18. 1
      src/components/calendar/plugins/preset/index.d.ts
  19. 9
      src/components/calendar/plugins/preset/index.js
  20. 1
      src/components/calendar/plugins/selectable.d.ts
  21. 221
      src/components/calendar/plugins/selectable.js
  22. 1036
      src/components/calendar/plugins/solarLunar/convertSolarLunar.js
  23. 1
      src/components/calendar/plugins/solarLunar/index.d.ts
  24. 59
      src/components/calendar/plugins/solarLunar/index.js
  25. 305
      src/components/calendar/plugins/time-range.js
  26. 1
      src/components/calendar/plugins/todo.d.ts
  27. 135
      src/components/calendar/plugins/todo.js
  28. 432
      src/components/calendar/plugins/week.js
  29. 49
      src/components/calendar/render.js
  30. 29
      src/components/calendar/theme/iconfont.wxss
  31. 61
      src/components/calendar/theme/theme-default.wxss
  32. 58
      src/components/calendar/theme/theme-elegant.wxss
  33. 90
      src/components/calendar/theme/theme-nuohe.wxss
  34. 275
      src/components/calendar/utils/index.js
  35. 23
      src/components/calendar/utils/logger.js
  36. 30
      src/components/calendar/utils/wxData.js
  37. 271
      src/components/ec-canvas/ec-canvas.js
  38. 4
      src/components/ec-canvas/ec-canvas.json
  39. 4
      src/components/ec-canvas/ec-canvas.wxml
  40. 5
      src/components/ec-canvas/ec-canvas.wxss
  41. 111
      src/components/ec-canvas/wx-canvas.js
  42. 352
      src/components/freeAudio/index.js
  43. 54
      src/components/freeAudio/index.wxml
  44. 14
      src/components/pageNavbar/index.wxml
  45. 7
      src/components/patient-tab-bar/index.json
  46. 19
      src/components/patient-tab-bar/index.scss
  47. 113
      src/components/patient-tab-bar/index.ts
  48. 16
      src/components/patient-tab-bar/index.wxml
  49. 408
      src/components/star/index.ts
  50. 278
      src/components/toast/index.ts
  51. 147
      src/components/toast/index.wxml
  52. 61
      src/components/viewFile/index.js
  53. 6
      src/components/viewFile/index.json
  54. 12
      src/components/viewFile/index.wxml
  55. 48
      src/components/viewFile/index.wxss
  56. 66
      src/components/viewVideo/index.js
  57. 4
      src/components/viewVideo/index.json
  58. 46
      src/components/viewVideo/index.scss
  59. 21
      src/components/viewVideo/index.wxml
  60. 46
      src/components/viewVideo/index.wxss
  61. 231
      src/components/zdUploadFile/index.js
  62. 8
      src/components/zdUploadFile/index.json
  63. 20
      src/components/zdUploadFile/index.wxml
  64. 77
      src/components/zdUploadFile/index.wxss
  65. 25
      src/gift/compontnts/echart/echarts.js
  66. 6
      src/gift/pages/conformOrder/index.json
  67. 184
      src/gift/pages/conformOrder/index.scss
  68. 86
      src/gift/pages/conformOrder/index.ts
  69. 56
      src/gift/pages/conformOrder/index.wxml
  70. 4
      src/gift/pages/cutaneous/index.json
  71. 63
      src/gift/pages/cutaneous/index.scss
  72. 65
      src/gift/pages/cutaneous/index.ts
  73. 82
      src/gift/pages/cutaneous/index.wxml
  74. 4
      src/gift/pages/cutaneousDetail/index.json
  75. 11
      src/gift/pages/cutaneousDetail/index.scss
  76. 26
      src/gift/pages/cutaneousDetail/index.ts
  77. 9
      src/gift/pages/cutaneousDetail/index.wxml
  78. 4
      src/gift/pages/cutaneousVideo/index.json
  79. 36
      src/gift/pages/cutaneousVideo/index.scss
  80. 29
      src/gift/pages/cutaneousVideo/index.ts
  81. 16
      src/gift/pages/cutaneousVideo/index.wxml
  82. 4
      src/gift/pages/dtpDurg/index.json
  83. 128
      src/gift/pages/dtpDurg/index.scss
  84. 52
      src/gift/pages/dtpDurg/index.ts
  85. 61
      src/gift/pages/dtpDurg/index.wxml
  86. 7
      src/gift/pages/giftDetail/index.json
  87. 185
      src/gift/pages/giftDetail/index.scss
  88. 150
      src/gift/pages/giftDetail/index.ts
  89. 80
      src/gift/pages/giftDetail/index.wxml
  90. 8
      src/gift/pages/giftList/index.json
  91. 185
      src/gift/pages/giftList/index.scss
  92. 114
      src/gift/pages/giftList/index.ts
  93. 51
      src/gift/pages/giftList/index.wxml
  94. 4
      src/gift/pages/myGift/index.json
  95. 110
      src/gift/pages/myGift/index.scss
  96. 48
      src/gift/pages/myGift/index.ts
  97. 28
      src/gift/pages/myGift/index.wxml
  98. 11
      src/gift/pages/myHealthRecord/index.json
  99. 741
      src/gift/pages/myHealthRecord/index.scss
  100. 1091
      src/gift/pages/myHealthRecord/index.ts
  101. Some files were not shown because too many files have changed in this diff Show More

2
project.config.json

@ -71,5 +71,5 @@ @@ -71,5 +71,5 @@
}
]
},
"appid": "wx71ac9c27c3c3e3f4"
"appid": "wxf9ce8010f1ad24aa"
}

25
src/app.json

@ -71,6 +71,31 @@ @@ -71,6 +71,31 @@
]
},
{
"root": "gift",
"pages": [
"pages/giftList/index",
"pages/giftDetail/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",
"pages": ["pages/doc1/index"]
}

110
src/app.ts

@ -16,25 +16,72 @@ App<IAppOption>({ @@ -16,25 +16,72 @@ App<IAppOption>({
// 测试号 wx2b0bb13edf717c1d
// dev
// appid:wxf9ce8010f1ad24aa
// url: 'https://m.xd.hbraas.com',
// upFileUrl: 'https://m.xd.hbraas.com/',
// imageUrl: 'https://m.xd.hbraas.com/xd/',
url: 'https://m.xd.hbraas.com',
upFileUrl: 'https://m.xd.hbraas.com/',
imageUrl: 'https://m.xd.hbraas.com/xd/',
// pro
// appid:wx71ac9c27c3c3e3f4
url: 'https://m.xd.hbsaas.com',
upFileUrl: 'https://m.xd.hbsaas.com/',
imageUrl: 'https://m.xd.hbsaas.com/api/xd/',
// url: 'https://m.xd.hbsaas.com',
// upFileUrl: 'https://m.xd.hbsaas.com/',
// imageUrl: 'https://m.xd.hbsaas.com/api/xd/',
loginState: '',
isLogin: 0,
isNewReg: 0,
loginType: 0,
scene: null,
scene: {},
backPath: '',
zdUserInfo: {},
DiagnoseType: [
{
id: 1,
name: 'Ⅰ型 眼肌无力,可伴闭眼无力,其它肌群肌力正常',
},
{
id: 2,
name: 'Ⅱa 型 主要累及四肢肌或(和)躯干肌,可有较轻的咽喉肌受累',
},
{
id: 3,
name: 'Ⅱb 型 主要累及咽喉肌或(和)呼吸肌,可有轻度或相同的四肢肌或(和)躯干肌受累',
},
{
id: 4,
name: 'Ⅲa 型 主要累及四肢肌或(和)躯干肌,可有较轻的咽喉肌受累',
},
{
id: 5,
name: 'Ⅲb 型 主要累及咽喉肌或(和)呼吸肌,可有轻度或相同的四肢肌或(和)躯干肌受累',
},
{
id: 6,
name: 'Ⅳa 型 主要累及四肢肌或(和)躯干肌受累,可有较轻的咽喉肌受累',
},
{
id: 7,
name: 'Ⅳb 型 主要累及咽喉肌或(和)呼吸肌,可有轻度或相同的四肢肌或(和)躯干肌受累',
},
{
id: 8,
name: 'Ⅴ型 气管插管,伴或不伴机械通气(除外术后常规使用);仅鼻饲而不进行气管插管的病例为Ⅳb 型',
},
{
id: 9,
name: '其它',
},
],
storyStatus: {
1: '已提交待审核',
2: '审核未通过',
3: '审核通过待校正',
4: '校正完成',
5: '已发布',
100: '审核未通过',
},
},
onLaunch() {
Page = page as WechatMiniprogram.Page.Constructor;
@ -53,6 +100,7 @@ App<IAppOption>({ @@ -53,6 +100,7 @@ App<IAppOption>({
}).then((res: any) => {
this.globalData.loginState = res.loginState;
this.globalData.isLogin = res.isLogin;
this.globalData.isNewReg = res.isNewReg;
this.globalData.loginType = res.loginType;
});
},
@ -68,7 +116,21 @@ App<IAppOption>({ @@ -68,7 +116,21 @@ App<IAppOption>({
this.globalData.scene = parseScene(options.query.scene);
}
},
waitLogin({ type = 0 } = { type: 'any' }) {
updateLoginInfo(callback?: (any) => void) {
wx.ajax({
method: 'GET',
url: '?r=xd/user/get-account-info',
data: {},
}).then((res) => {
this.globalData.isLogin = res.isLogin;
this.globalData.loginType = res.loginType;
this.globalData.isNewReg = res.isNewReg;
if (callback) {
callback(res);
}
});
},
waitLogin({ type = [0] } = { type: 'any' }) {
return new Promise((resolve) => {
const checkLogin = () => {
if (this.globalData.loginState) {
@ -84,25 +146,41 @@ App<IAppOption>({ @@ -84,25 +146,41 @@ App<IAppOption>({
checkLogin();
});
},
checkLoginType(type: 0 | 1 | 2 | 'any') {
const { loginType, isLogin } = this.globalData;
checkLoginType(type) {
const { loginType, isLogin, isNewReg } = this.globalData;
if (type === 'any') {
return true;
}
if (isLogin !== 1) {
if (type === 0) {
if (type.includes(0) && loginType === 0) {
return true;
}
wx.reLaunch({
url: '/pages/login/index',
url: '/patient/pages/login/index',
});
return false;
}
if (loginType !== 2) {
if (isNewReg !== 1) {
const typePageUrl = {
1: '/patient/pages/entryInfo/index',
2: '/pages/login/index',
}[loginType as 1 | 2];
wx.reLaunch({
url: typePageUrl,
});
return false;
}
if (!type.includes(loginType)) {
const typePageUrl = {
1: '/patient/pages/index/index',
2: '/pages/index/index',
}[loginType as 1 | 2];
wx.reLaunch({
url: '/pages/login/index',
url: typePageUrl,
});
return false;
}
@ -136,7 +214,9 @@ App<IAppOption>({ @@ -136,7 +214,9 @@ App<IAppOption>({
},
// zd相关函数
zdMpBehavior(data: { PageName: string; doctor?: boolean }) {
let url = '?r=xd/mp-behavior/add';
const { loginType } = this.globalData;
if (loginType === 0) return;
let url = '?r=zd/mp-behavior/add';
if (data.doctor) {
url = '?r=zd/doctor/mp-behavior/add';
}

144
src/components/calendar/core.js

@ -0,0 +1,144 @@ @@ -0,0 +1,144 @@
import { dateUtil, getCalendarConfig } from './utils/index'
/**
* 计算当前月份前后两月应占的格子
* @param {number} year 年份
* @param {number} month 月份
*/
function calculateEmptyGrids(year, month, config) {
const prevMonthGrids = calculatePrevMonthGrids(year, month, config)
const nextMonthGrids = calculateNextMonthGrids(year, month, config)
return {
prevMonthGrids,
nextMonthGrids
}
}
/**
* 计算上月应占的格子
* @param {number} year 年份
* @param {number} month 月份
*/
function calculatePrevMonthGrids(year, month, config) {
let emptyGrids = []
const prevMonthDays = dateUtil.getDatesCountOfMonth(year, month - 1)
let firstDayOfWeek = dateUtil.firstDayOfWeek(year, month)
if (config.firstDayOfWeek === 'Mon') {
if (firstDayOfWeek === 0) {
firstDayOfWeek = 6
} else {
firstDayOfWeek -= 1
}
}
if (firstDayOfWeek > 0) {
const len = prevMonthDays - firstDayOfWeek
const { onlyShowCurrentMonth } = config
const YMInfo = dateUtil.getPrevMonthInfo({ year, month })
for (let i = prevMonthDays; i > len; i--) {
if (onlyShowCurrentMonth) {
emptyGrids.push('')
} else {
const week = dateUtil.getDayOfWeek(+year, +month, i)
emptyGrids.push({
...YMInfo,
date: i,
week
})
}
}
emptyGrids.reverse()
}
return emptyGrids
}
/**
* 计算下一月日期是否需要多展示的日期
* 某些月份日期为5排某些月份6排统一为6排
* @param {number} year
* @param {number} month
* @param {object} config
*/
function calculateExtraEmptyDate(year, month, config) {
let extDate = 0
if (+month === 2) {
extDate += 7
let firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1)
if (config.firstDayOfWeek === 'Mon') {
if (+firstDayofMonth === 1) extDate += 7
} else {
if (+firstDayofMonth === 0) extDate += 7
}
} else {
let firstDayofMonth = dateUtil.getDayOfWeek(year, month, 1)
if (config.firstDayOfWeek === 'Mon') {
if (firstDayofMonth !== 0 && firstDayofMonth < 6) {
extDate += 7
}
} else {
if (firstDayofMonth <= 5) {
extDate += 7
}
}
}
return extDate
}
/**
* 计算下月应占的格子
* @param {number} year 年份
* @param {number} month 月份
*/
function calculateNextMonthGrids(year, month, config) {
let emptyGrids = []
const datesCount = dateUtil.getDatesCountOfMonth(year, month)
let lastDayWeek = dateUtil.getDayOfWeek(year, month, datesCount)
if (config.firstDayOfWeek === 'Mon') {
if (lastDayWeek === 0) {
lastDayWeek = 6
} else {
lastDayWeek -= 1
}
}
let len = 7 - (lastDayWeek + 1)
const { onlyShowCurrentMonth } = config
if (!onlyShowCurrentMonth) {
len = len + calculateExtraEmptyDate(year, month, config)
}
const YMInfo = dateUtil.getNextMonthInfo({ year, month })
for (let i = 1; i <= len; i++) {
const week = dateUtil.getDayOfWeek(+year, +month, i)
if (onlyShowCurrentMonth) {
emptyGrids.push('')
} else {
emptyGrids.push({
id: i - 1,
...YMInfo,
date: i,
week: week || 7
})
}
}
return emptyGrids
}
/**
* 设置日历面板数据
* @param {number} year 年份
* @param {number} month 月份
* @param {number} curDate 日期
*/
function calculateCurrentMonthDates(year, month) {
return dateUtil.calcDates(year, month)
}
export function calcJumpData({ dateInfo, config, component }) {
dateInfo = dateInfo || dateUtil.todayFMD()
const { year, month, date } = dateInfo
const calendarConfig = config || getCalendarConfig(component)
const emptyGrids = calculateEmptyGrids(year, month, calendarConfig)
const calendar = {
curYear: year,
curMonth: month,
curDate: date,
dates: calculateCurrentMonthDates(year, month),
...emptyGrids
}
return calendar
}

12
src/components/calendar/helper.js

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
import { dateUtil } from './utils/index'
export function calcTargetYMInfo() {
return {
right: dateUtil.getPrevMonthInfo,
left: dateUtil.getNextMonthInfo,
prev_month: dateUtil.getPrevMonthInfo,
next_month: dateUtil.getNextMonthInfo,
prev_year: dateUtil.getPrevYearInfo,
next_year: dateUtil.getNextYearInfo
}
}

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

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

258
src/components/calendar/index.js

@ -0,0 +1,258 @@ @@ -0,0 +1,258 @@
import plugins from './plugins/index'
import { calcJumpData } from './core'
import { renderCalendar } from './render'
import { calcTargetYMInfo } from './helper'
import { dateUtil, calendarGesture, logger } from './utils/index'
Component({
options: {
styleIsolation: 'apply-shared',
multipleSlots: true // 在组件定义时的选项中启用多slot支持
},
properties: {
config: {
type: Object,
value: {}
}
},
lifetimes: {
attached: function() {
this.initComp()
}
},
methods: {
initComp() {
const calendarConfig = this.setDefaultDisableDate()
this.setConfig(calendarConfig)
},
// 禁用某天日期配置默认为今天
setDefaultDisableDate() {
const calendarConfig = this.properties.config || {}
if (calendarConfig.disableMode && !calendarConfig.disableMode.date) {
calendarConfig.disableMode.date = dateUtil.toTimeStr(
dateUtil.todayFMD()
)
}
return calendarConfig
},
initCalendar(config) {
const { defaultDate } = config
let date = dateUtil.todayFMD()
if (defaultDate && typeof defaultDate === 'string') {
const dateInfo = defaultDate.split('-')
if (dateInfo.length < 3) {
return logger.warn('defaultDate配置格式应为: 2018-4-2 或 2018-04-02')
} else {
date = {
year: +dateInfo[0],
month: +dateInfo[1],
date: +dateInfo[2]
}
}
}
const waitRenderData = calcJumpData({
dateInfo: date,
config
})
const timestamp = dateUtil.todayTimestamp()
if (config.autoChoosedWhenJump) {
const target = waitRenderData.dates.filter(
item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(date)
)
if (target && target.length) {
if (!waitRenderData.selectedDates) {
waitRenderData.selectedDates = target
} else {
waitRenderData.selectedDates.push(target[0])
}
}
}
return {
...waitRenderData,
todayTimestamp: timestamp,
weeksCh: dateUtil.getWeekHeader(config.firstDayOfWeek)
}
},
setConfig(config) {
if (config.markToday && typeof config.markToday === 'string') {
config.highlightToday = true
}
config.theme = config.theme || 'default'
this.setData(
{
config
},
() => {
for (let plugin of plugins.installed) {
const [, p] = plugin
if (typeof p.install === 'function') {
p.install(this)
}
if (typeof p.methods === 'function') {
const methods = p.methods(this)
for (let fnName in methods) {
if (fnName.startsWith('__')) continue
const fn = methods[fnName]
if (typeof fn === 'function') {
if (!this.calendar) this.calendar = {}
this.calendar[fnName] = fn
}
}
}
}
const initData = this.initCalendar(config)
renderCalendar.call(this, initData, config)
}
)
},
tapDate(e) {
const { info } = e.currentTarget.dataset
const { date, disable } = info || {}
if (disable || !date) return
const { calendar, config } = this.data
let calendarData = calendar
let calendarConfig = config
if (config.takeoverTap) {
return this.triggerEvent('takeoverTap', info)
}
for (let plugin of plugins.installed) {
const [, p] = plugin
if (typeof p.onTapDate === 'function') {
const {
calendarData: __calendarData,
calendarConfig: __calendarConfig
} = p.onTapDate(info, calendarData, calendarConfig)
calendarData = __calendarData
calendarConfig = __calendarConfig
}
}
renderCalendar.call(this, calendarData, calendarConfig).then(() => {
this.triggerEvent('afterTapDate', info)
})
},
/**
* 日历滑动开始
* @param {object} e
*/
calendarTouchstart(e) {
const t = e.touches[0]
const startX = t.clientX
const startY = t.clientY
this.swipeLock = true
this.setData({
'gesture.startX': startX,
'gesture.startY': startY
})
},
/**
* 日历滑动中
* @param {object} e
*/
calendarTouchmove(e) {
const { gesture } = this.data
const { preventSwipe } = this.properties.config
if (!this.swipeLock || preventSwipe) return
if (calendarGesture.isLeft(gesture, e.touches[0])) {
this.handleSwipe('left')
this.swipeLock = false
}
if (calendarGesture.isRight(gesture, e.touches[0])) {
this.handleSwipe('right')
this.swipeLock = false
}
},
calendarTouchend(e) {
this.setData({
'calendar.leftSwipe': 0,
'calendar.rightSwipe': 0
})
},
handleSwipe(direction) {
let swipeKey = 'calendar.leftSwipe'
if (direction === 'right') {
swipeKey = 'calendar.rightSwipe'
}
this.setData({
[swipeKey]: 1
})
const { calendar } = this.data
let calendarData = calendar
const { curYear, curMonth } = calendarData
const getMonthInfo = calcTargetYMInfo()[direction]
const target = getMonthInfo({
year: +curYear,
month: +curMonth
})
target.direction = direction
this.renderCalendar(target)
},
changeDate(e) {
const { type } = e.currentTarget.dataset
const { calendar: calendarData } = this.data
const { curYear, curMonth } = calendarData
const getMonthInfo = calcTargetYMInfo()[type]
const target = getMonthInfo({
year: +curYear,
month: +curMonth
})
target.direction = type
this.renderCalendar(target)
},
renderCalendar(target) {
let { calendar: calendarData, config } = this.data
const { curYear, curMonth } = calendarData || {}
for (let plugin of plugins.installed) {
const [, p] = plugin
if (typeof p.onSwitchCalendar === 'function') {
calendarData = p.onSwitchCalendar(target, calendarData, this)
}
}
return renderCalendar.call(this, calendarData, config).then(() => {
let triggerEventName = 'whenChangeMonth'
if (config.weekMode) {
triggerEventName = 'whenChangeWeek'
}
this.triggerEvent(triggerEventName, {
current: {
year: +curYear,
month: +curMonth
},
next: target
})
this.triggerEvent('onSwipe', {
current: {
year: +curYear,
month: +curMonth
},
next: target,
type: triggerEventName
})
})
},
doubleClickJumpToToday() {
const { multi, weekMode } = this.calendar.getCalendarConfig() || {}
if (multi || weekMode) return
if (this.count === undefined) {
this.count = 1
} else {
this.count += 1
}
if (this.lastClick) {
const difference = new Date().getTime() - this.lastClick
if (
difference < 500 &&
this.count >= 2 &&
typeof this.calendar.jump === 'function'
) {
const today = dateUtil.todayFMD()
this.calendar.jump(today)
}
this.count = undefined
this.lastClick = undefined
} else {
this.lastClick = new Date().getTime()
}
this.triggerEvent('jumpToToday')
}
}
})

3
src/components/calendar/index.json

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

116
src/components/calendar/index.wxml

@ -0,0 +1,116 @@ @@ -0,0 +1,116 @@
<view class="flex b tb ac" wx:if="{{calendar}}">
<view class="calendar b tb">
<!-- 头部操作栏 -->
<view
wx:if="{{!config.hideHeader}}"
class="handle {{config.theme}}_handle-color fs32 b lr ac pc"
>
<view class="prev fs36" wx:if="{{!config.weekMode}}">
<text
wx:if="{{!config.hideSelectYear}}"
class="prev-handle iconfont icon-doubleleft"
bindtap="changeDate"
data-type="prev_year"
></text>
<text
class="prev-handle iconfont icon-left"
bindtap="changeDate"
data-type="prev_month"
></text>
</view>
<view class="flex date-in-handle b lr cc blod" bindtap="doubleClickJumpToToday"
>{{calendar.curYear || "--"}} 年 {{calendar.curMonth || "--"}} 月</view
>
<view class="next fs36" wx:if="{{!config.weekMode}}">
<text
class="next-handle iconfont icon-right"
bindtap="changeDate"
data-type="next_month"
></text>
<text
wx:if="{{!config.hideSelectYear}}"
class="next-handle iconfont icon-doubleright"
bindtap="changeDate"
data-type="next_year"
></text>
</view>
</view>
<!-- 星期栏 -->
<view class="weeks b lr ac {{config.theme}}_week-color">
<view class="week fs28" wx:for="{{calendar.weeksCh}}" wx:key="index" data-idx="{{index}}">
{{item}}
</view>
</view>
<!-- 日历面板主体 -->
<view
class="b lr wrap"
bindtouchstart="calendarTouchstart"
catchtouchmove="calendarTouchmove"
catchtouchend="calendarTouchend"
>
<!-- 上月日期格子 -->
<view
class="grid b ac pc {{config.theme}}_prev-month-date"
wx:for="{{calendar.prevMonthGrids}}"
wx:key="index"
data-idx="{{index}}"
>
<view class="date-wrap b cc">
<view class="date">
{{item.date}}
</view>
</view>
</view>
<!-- 本月日期格子 -->
<view
wx:for="{{calendar.dates}}"
wx:key="index"
data-idx="{{index}}"
data-info="{{item}}"
bindtap="tapDate"
class="grid {{item.class ? item.class : ''}} {{config.theme}}_normal-date b ac pc"
>
<view
class="date-wrap b cc {{config.emphasisWeek && (item.week === 0 || item.week === 6) ? config.theme + '_weekend-color' : ''}}"
>
<view
class="date b ac pc {{item.class ? item.class : ''}} {{item.isToday && config.highlightToday ? config.theme + '_today' : ''}} {{item.choosed ? config.theme + '_choosed' : ''}} {{item.disable ? config.theme + '_date-disable' : ''}} {{config.chooseAreaMode ? 'date-area-mode' : ''}} {{calendar.todoLabelCircle && item.showTodoLabel && !item.choosed ? config.theme + '_todo-circle todo-circle' : '' }}"
>
{{config.markToday && item.isToday ? config.markToday : item.date}}
<view
wx:if="{{(config.showLunar && item.lunar && !item.showTodoLabel) || (item.showTodoLabel && calendar.todoLabelPos !== 'bottom') || config.showHolidays}}"
class="date-desc {{config.theme}}_date-desc date-desc-bottom {{(item.choosed || item.isToday) ? 'date-desc-bottom-always' : ''}} {{item.disable ? config.theme + '_date-desc-disable' : ''}}"
>
<text
class="{{config.showHolidays && !item.showTodoLabel && item.label && !item.choosed ? config.theme + '_date-desc-lunar' : ''}} {{item.type === 'festival' ? config.theme + '_festival' : ''}}"
>{{item.label || item.lunar.Term || item.lunar.IDayCn}}</text
>
</view>
<block wx:for="{{item.color}}" wx:for-item="col" wx:for-index="colIndex" wx:key="*this">
<view
wx:if="{{item.showTodoLabel && !calendar.todoLabelCircle}}"
class="{{item.todoText ? 'date-desc' : config.theme + '_todo-dot todo-dot'}} {{config.showLunar ? config.theme + '_date-desc-lunar' : ''}} {{calendar.todoLabelPos === 'bottom' ? 'date-desc-bottom todo-dot-bottom' : 'date-desc-top todo-dot-top'}} {{calendar.showLabelAlways && item.choosed && calendar.todoLabelPos === 'bottom' ? 'date-desc-bottom-always todo-dot-bottom-always' : ''}} {{calendar.showLabelAlways && item.choosed && calendar.todoLabelPos === 'top' ? 'date-desc-top-always todo-dot-top-always' : ''}}"
style="background-color: {{item.todoText ? '' : col || calendar.todoLabelColor}}; color: {{col}};left:{{(item.color.length>1 ? 35 : 50)*(colIndex+1)}}%"
>
{{item.todoText}}
</view>
</block>
</view>
</view>
</view>
<!-- 下月日期格子 -->
<view
class="grid b ac pc {{config.theme}}_next-month-date"
wx:for="{{calendar.nextMonthGrids}}"
wx:key="index"
data-idx="{{index}}"
>
<view class="date-wrap b cc">
<view class="date">
{{item.date}}
</view>
</view>
</view>
</view>
</view>
</view>

247
src/components/calendar/index.wxss

@ -0,0 +1,247 @@ @@ -0,0 +1,247 @@
@import "./theme/iconfont.wxss";
@import "./theme/theme-default.wxss";
@import "./theme/theme-elegant.wxss";
@import "./theme/theme-nuohe.wxss";
.blod {
font-weight: bold;
}
.b {
display: flex;
}
.lr {
flex-direction: row;
}
.tb {
flex-direction: column;
}
.pc {
justify-content: center;
}
.ac {
align-items: center;
}
.cc {
align-items: center;
justify-content: center;
}
.wrap {
flex-wrap: wrap;
}
.flex {
flex-grow: 1;
}
.bg {
background-image: linear-gradient(to bottom, #faefe7, #ffcbd7);
overflow: hidden;
}
.white-color {
color: #fff;
}
.fs24 {
font-size: 24rpx;
}
.fs28 {
font-size: 28rpx;
}
.fs32 {
font-size: 32rpx;
}
.fs36 {
font-size: 36rpx;
}
.calendar {
width: 100%;
box-sizing: border-box;
}
/* 日历操作栏 */
.handle {
height: 80rpx;
}
.prev-handle,
.next-handle {
padding: 20rpx;
}
.date-in-handle {
height: 80rpx;
}
/* 星期栏 */
.weeks {
height: 50rpx;
line-height: 50rpx;
opacity: 0.5;
}
.week {
text-align: center;
}
.grid,
.week {
width: 14.286014285714286%;
}
.date-wrap {
width: 100%;
height: 80rpx;
position: relative;
left: 0;
top: 0;
}
.date {
position: relative;
left: 0;
top: 0;
width: 55rpx;
height: 55rpx;
text-align: center;
line-height: 55rpx;
font-size: 28rpx;
font-weight: 200;
border-radius: 50%;
transition: all 0.3s;
font-weight: bold;
animation-name: choosed;
animation-duration: 0.5s;
animation-timing-function: linear;
animation-iteration-count: 1;
}
.date-area-mode {
width: 100%;
border-radius: 0;
}
.date-desc {
width: 150%;
height: 32rpx;
font-size: 20rpx;
line-height: 32rpx;
position: absolute;
left: 50%;
transform: translateX(-50%);
overflow: hidden;
word-break: break-all;
text-overflow: ellipsis;
white-space: nowrap;
-webkit-line-clamp: 1;
text-align: center;
}
@keyframes choosed {
from {
transform: scale(1);
}
50% {
transform: scale(0.9);
}
to {
transform: scale(1);
}
}
/* 日期圆圈标记 */
.todo-circle {
border-width: 1rpx;
border-style: solid;
box-sizing: border-box;
}
/* 待办点标记相关样式 */
.todo-dot {
width: 16rpx;
height: 16rpx;
border-radius: 50%;
position: absolute;
left: 50%;
bottom: -10rpx !important;
transform: translateX(-50%);
}
.todo-dot-top {
top: 3rpx;
}
.todo-dot.todo-dot-top-always {
top: -8rpx;
}
.todo-dot.todo-dot-bottom {
bottom: 0;
}
.todo-dot.todo-dot-bottom-always {
bottom: -10rpx;
}
/* 日期描述文字(待办文字/农历)相关样式 */
.date-desc.date-desc-top {
top: -6rpx;
}
.date-desc.date-desc-top-always {
top: -20rpx;
}
.date-desc.date-desc-bottom {
bottom: -14rpx;
}
.todo-circle .date-desc.date-desc-bottom {
bottom: -30rpx;
}
.date-desc.date-desc-bottom-always {
bottom: -28rpx;
}

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

@ -0,0 +1,212 @@ @@ -0,0 +1,212 @@
/* *
@Author: drfu*
@Description: 数据来源于国务院办公厅关于2020年部分节假日安排的通知国办发明电201916_政府信息公开专栏http://www.gov.cn/zhengce/content/2019-11/21/content_5454164.htm
@Date: 2020-10-12 14:29:45*
* @Last Modified by: drfu
* @Last Modified time: 2020-10-16 17:38:08
*/
// 节日列表
export const festival = {
// 农历固定日期节日
lunar: {
1: {
1: {
type: 'festival',
name: '春节',
label: '春节'
},
8: {
type: 'festival',
name: '腊八节',
label: '腊八'
},
15: {
type: 'festival',
name: '元宵节',
label: '元宵'
}
},
7: {
7: {
type: 'festival',
name: '七夕节',
label: '七夕'
},
15: {
type: 'festival',
name: '中元节',
label: '中元节'
}
},
9: {
9: {
type: 'festival',
name: '重阳节',
label: '重阳节'
}
}
},
// 阳历固定日期节日
solar: {
2: {
14: {
type: 'festival',
name: '情人节',
label: '情人节'
}
},
3: {
12: {
type: 'festival',
name: '植树节',
label: '植树节'
}
},
4: {
1: {
type: 'festival',
name: '愚人节',
label: '愚人节'
},
5: {
type: 'festival',
name: '清明节',
label: '清明节'
}
},
5: {
1: {
type: 'festival',
name: '劳动节',
label: '劳动节'
}
},
6: {
1: {
type: 'festival',
name: '儿童节',
label: '儿童节'
}
},
7: {
1: {
type: 'festival',
name: '建党节',
label: '建党节'
}
},
8: {
1: {
type: 'festival',
name: '建军节',
label: '建军节'
}
},
9: {
10: {
type: 'festival',
name: '教师节',
label: '教师节'
}
},
10: {
1: {
type: 'festival',
name: '国庆节',
label: '国庆节'
}
},
12: {
25: {
type: 'festival',
name: '圣诞节',
label: '圣诞节'
}
}
}
}
export const holidays = {
2020: {
1: {
1: {
type: 'holiday',
name: '元旦',
label: '休'
},
19: {
type: 'work',
name: '调班',
label: '班'
},
'24-30': {
type: 'holiday',
name: '春节',
label: '休'
}
},
2: {
1: {
type: 'work',
name: '调班',
label: '班'
}
},
4: {
'4-6': {
type: 'holiday',
name: '清明节',
label: '休'
},
26: {
type: 'work',
name: '调班',
label: '班'
}
},
5: {
'1-5': {
type: 'holiday',
name: '劳动节',
label: '休'
},
9: {
type: 'work',
name: '调班',
label: '班'
}
},
6: {
'25-27': {
type: 'holiday',
name: '端午节',
label: '休'
},
28: {
type: 'work',
name: '调班',
label: '班'
}
},
9: {
27: {
type: 'work',
name: '调班',
label: '班'
}
},
10: {
'1-8': {
type: 'holiday',
name: '国庆节/中秋节',
label: '休'
},
10: {
type: 'work',
name: '调班',
label: '班'
}
}
}
}

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

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

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

@ -0,0 +1,201 @@ @@ -0,0 +1,201 @@
/* *
@Author: drfu*
@Description: 显示法定节假日班/休情况
@Date: 2020-10-12 14:29:45*
* @Last Modified by: drfu
* @Last Modified time: 2020-10-16 17:34:13
*/
import { holidays, festival } from './holidays-map'
import { dateUtil, getCalendarData, logger } from '../../utils/index'
/**
* 当前是否在休假期内
* @param {object} { year, month }
* @param {object} { start, end, current }
* @returns
*/
function inHolidays({ year, month }, { start, end, current }) {
const getTimeStamp = dateUtil.getTimeStamp
const startTimestamp = getTimeStamp({
year,
month,
date: start
})
const endTimestamp = getTimeStamp({
year,
month,
date: end
})
const currentDateTimestamp = getTimeStamp({
year,
month,
date: current
})
if (
currentDateTimestamp >= startTimestamp &&
currentDateTimestamp <= endTimestamp
) {
return true
}
return false
}
function addSpecialFestival(date, component) {
const { convertlLunar2Solar, convertSolarLunar } = component.calendar || {}
const lunarDateInfo = convertSolarLunar(date)
const { lYear, lMonth } = lunarDateInfo || {}
// 春节
const info = {
type: 'festival',
name: '除夕',
label: '除夕'
}
if (lMonth === 12) {
if (!festival.lunar['12']) festival.lunar['12'] = {}
if (convertlLunar2Solar(`${lYear}-12-30`) === -1) {
festival.lunar['12']['29'] = info
} else {
festival.lunar['12']['30'] = info
}
}
}
/**
* 是否匹配到节日
* @param {object} [dateInfo={}]
* @param {object} [component={}]
* @returns {object|boolean} 匹配到的节日数据或者false
*/
function hasFestivalDate(dateInfo = {}, component = {}) {
const { month, date } = dateInfo
let festivalDate = festival.solar[month] && festival.solar[month][date]
if (!festivalDate) {
const { convertSolarLunar } = component.calendar || {}
const lunarDateInfo = convertSolarLunar(dateInfo)
const { lMonth, lDay } = lunarDateInfo
festivalDate = festival.lunar[lMonth] && festival.lunar[lMonth][lDay]
if (!festivalDate) {
const festivalOfMonth = festival.lunar[lMonth] || {}
const festivalDateKey = Object.keys(festivalOfMonth).find(item =>
item.match(new RegExp(`\\b${lDay}\\b`))
)
if (!festivalDateKey) {
festivalDate = false
} else {
const festivalInfo = festival.lunar[lMonth][festivalDateKey]
if (!festivalInfo) {
festivalDate = false
} else {
const { condition } = festivalInfo
if (typeof condition === 'function') {
festivalDate = condition(lunarDateInfo)
} else {
festivalDate = false
}
}
}
}
}
return festivalDate
}
export default () => {
return {
name: 'holidays',
beforeRender(calendarData = {}, calendarConfig = {}, component) {
let { dates = [] } = calendarData
if (calendarConfig.showHolidays || calendarConfig.showFestival) {
dates = dates.map(d => {
let item = { ...d }
const { year, month, date } = item
const holidaysOfMonth =
(holidays[year] && holidays[year][month]) || {}
const holidayDate = holidaysOfMonth[date]
if (holidayDate) {
item = {
...item,
...holidayDate
}
} else {
const holidayKeys = Object.keys(holidaysOfMonth).filter(item =>
item.includes('-')
)
let target = ''
for (let v of holidayKeys) {
const [start, end] = v.split('-')
if (+d.date >= +start && +d.date <= +end) {
target = v
break
}
}
const [start, end] = target.split('-')
const isInHolidays = inHolidays(
{
year,
month
},
{
start,
end,
current: date
}
)
if (isInHolidays) {
item = {
...item,
...holidaysOfMonth[target]
}
} else if (calendarConfig.showFestival) {
const { convertSolarLunar, convertlLunar2Solar } =
component.calendar || {}
if (
typeof convertSolarLunar !== 'function' ||
typeof convertlLunar2Solar !== 'function'
) {
return logger.warn(
'农历节日显示需要引入农历插件(/component/v2/plugins/solarLunar)'
)
}
addSpecialFestival(item, component)
const festivalDate = hasFestivalDate(item, component)
if (festivalDate) {
item = {
...item,
...festivalDate
}
}
}
}
return item
})
}
return {
calendarData: {
...calendarData,
dates: dates
},
calendarConfig
}
},
methods(component) {
return {
getHolidaysOfCurrentYear() {
const calendar = getCalendarData('calendar', component)
const { curYear } = calendar
return this.methods(component).getHolidaysOfYear(curYear)
},
getHolidaysOfYear(year) {
if (!year) return logger.warn('getHolidaysOfCurrentYear() 入参错误')
if (!holidays[year]) {
logger.warn('未匹配到当前年份节假日信息,请自行补充')
return {
err: 'not match'
}
}
return holidays[year]
}
}
}
}
}

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

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

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

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

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

@ -0,0 +1,277 @@ @@ -0,0 +1,277 @@
/**
* @Author: drfu*
* @Description: 基础功能
* @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu
* @Last Modified time: 2020-10-11 13:28:52
* */
import { calcJumpData } from '../../core'
import { renderCalendar } from '../../render'
import {
dateUtil,
getCalendarData,
setCalendarData,
getCalendarConfig
} from '../../utils/index'
export default () => {
return {
name: 'base',
beforeRender(calendarData = {}, calendarConfig) {
const calendar = calendarData
const { selectedDates = [], dates } = calendar
let _dates = [...dates]
if (selectedDates.length) {
const selectedDatesStr = selectedDates.map(date =>
dateUtil.toTimeStr(date)
)
_dates.forEach(date => {
const dateStr = dateUtil.toTimeStr(date)
if (selectedDatesStr.includes(dateStr)) {
date.choosed = true
}
})
}
return {
calendarData: {
...calendarData,
dates: _dates
},
calendarConfig
}
},
onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) {
const calendar = {
...calendarData
}
const dateIndex = dateUtil.findDateIndexInArray(
tapedDate,
calendarData.dates
)
const { multi, inverse } = calendarConfig
let dates = [...calendar.dates]
const { selectedDates = [] } = calendar
if (!multi) {
let preSelectedDate = {}
if (selectedDates.length) {
preSelectedDate = [...selectedDates].pop() || {}
}
const timeStr = dateUtil.toTimeStr
if (!inverse && timeStr(preSelectedDate) === timeStr(tapedDate)) {
return calendar
}
let _tapedDate = { ...tapedDate, choosed: !tapedDate.choosed }
dates[dateIndex] = _tapedDate
if (preSelectedDate.date) {
const idx = dateUtil.findDateIndexInArray(preSelectedDate, dates)
const date = dates[idx]
if (date) {
date.choosed = false
}
}
if (dates[dateIndex].choosed) {
calendar.selectedDates = [dates[dateIndex]]
} else {
calendar.selectedDates = []
}
} else {
dates[dateIndex] = {
...dates[dateIndex],
choosed: !dates[dateIndex].choosed
}
if (!calendar.selectedDates) {
calendar.selectedDates = []
}
if (dates[dateIndex].choosed) {
calendar.selectedDates.push(dates[dateIndex])
} else {
calendar.selectedDates = calendar.selectedDates.filter(
date =>
dateUtil.toTimeStr(date) !== dateUtil.toTimeStr(dates[dateIndex])
)
}
}
return {
calendarData: {
...calendar,
dates
},
calendarConfig
}
},
onSwitchCalendar(date, calendarData = {}, component) {
const calendarConfig = getCalendarConfig(component)
if (calendarConfig.weekMode) {
return calendarData
}
const updatedRenderData = calcJumpData({
dateInfo: date,
config: calendarConfig
})
return {
...calendarData,
...updatedRenderData
}
},
methods(component) {
return {
jump: dateInfo => {
if (Object.prototype.toString.call(dateInfo) !== '[object Object]')
return
const updatedRenderData = calcJumpData({
dateInfo,
component
})
const existCalendarData = getCalendarData('calendar', component)
const config = getCalendarConfig(component)
if (config.autoChoosedWhenJump) {
const target = updatedRenderData.dates[dateInfo.date - 1]
if (!updatedRenderData.selectedDates) {
updatedRenderData.selectedDates = [target]
} else {
updatedRenderData.selectedDates.push(target)
}
}
return renderCalendar.call(component, {
...existCalendarData,
...updatedRenderData
})
},
getCalendarConfig() {
return getCalendarConfig(component)
},
setCalendarConfig(config) {
return new Promise((resolve, reject) => {
if (!component || !component.data.config) {
reject('异常:未找到组件配置信息')
return
}
let conf = { ...component.config, ...config }
component.config = conf
setCalendarData({ config: conf }, component)
.then(resolve)
.catch(reject)
})
},
cancelSelectedDates(cancelDates = []) {
const existCalendarData = getCalendarData('calendar', component) || {}
const { dates = [], selectedDates = [] } = existCalendarData
let updatedRenderData = {}
const config = getCalendarConfig(component)
let chooseAreaData = {}
if (config.chooseAreaMode) {
chooseAreaData = {
chooseAreaTimestamp: [],
tempChooseAreaTimestamp: []
}
}
if (!cancelDates.length) {
dates.forEach(item => {
item.choosed = false
})
updatedRenderData = {
dates,
selectedDates: []
}
} else {
const cancelDatesStr = cancelDates.map(date =>
dateUtil.toTimeStr(date)
)
const filterSelectedDates = selectedDates.filter(
date => !cancelDatesStr.includes(dateUtil.toTimeStr(date))
)
dates.forEach(date => {
if (cancelDatesStr.includes(dateUtil.toTimeStr(date))) {
date.choosed = false
}
})
updatedRenderData = {
dates,
selectedDates: filterSelectedDates
}
}
return renderCalendar.call(component, {
...existCalendarData,
...updatedRenderData,
...chooseAreaData
})
},
setSelectedDates: targetDates => {
const existCalendarData = getCalendarData('calendar', component)
let { dates, selectedDates = [] } = existCalendarData || {}
let __selectedDates = []
let __dates = dates
if (!targetDates) {
__dates = dates.map(item => {
const date = { ...item }
date.choosed = true
if (existCalendarData.showLabelAlways && date.showTodoLabel) {
date.showTodoLabel = true
} else {
date.showTodoLabel = false
}
return date
})
__selectedDates = dates
} else if (targetDates && targetDates.length) {
const allSelected = dateUtil.uniqueArrayByDate(
selectedDates.concat(targetDates)
)
const allSelectedDateStr = allSelected.map(d =>
dateUtil.toTimeStr(d)
)
__dates = dates.map(item => {
const date = { ...item }
if (allSelectedDateStr.includes(dateUtil.toTimeStr(date))) {
date.choosed = true
__selectedDates.push(date)
}
if (existCalendarData.showLabelAlways && date.showTodoLabel) {
date.showTodoLabel = true
} else {
date.showTodoLabel = false
}
return date
})
}
return renderCalendar.call(component, {
...existCalendarData,
dates: __dates,
selectedDates: __selectedDates
})
},
setDateStyle: toSetDates => {
if (!Array.isArray(toSetDates)) return Promise.reject()
const existCalendarData = getCalendarData('calendar', component)
const { dates = [], specialStyleDates } = existCalendarData || {}
if (Array.isArray(specialStyleDates)) {
toSetDates = dateUtil.uniqueArrayByDate([
...specialStyleDates,
...toSetDates
])
}
const toSetDatesStr = toSetDates.map(item => dateUtil.toTimeStr(item))
const _dates = dates.map(item => {
const idx = toSetDatesStr.indexOf(dateUtil.toTimeStr(item))
if (idx > -1) {
return {
...item,
class: toSetDates[idx].class
}
} else {
return item
}
})
return renderCalendar.call(component, {
...existCalendarData,
dates: _dates,
specialStyleDates: toSetDates
})
}
}
}
}
}

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

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

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

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

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

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

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

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

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

@ -0,0 +1,221 @@ @@ -0,0 +1,221 @@
/**
* @Author: drfu*
* @Description: 禁用启用日期选择
* @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu
* @Last Modified time: 2020-10-08 21:25:00
* */
import { getCalendarData, dateUtil, logger } from '../utils/index'
import { renderCalendar } from '../render'
function convertEnableAreaToTimestamp(timearea = []) {
const start = timearea[0].split('-')
const end = timearea[1].split('-')
if (start.length !== 3 || end.length !== 3) {
logger.warn('enableArea() 参数格式为: ["2018-2-1", "2018-3-1"]')
return {}
}
const startTimestamp = dateUtil
.newDate(start[0], start[1], start[2])
.getTime()
const endTimestamp = dateUtil.newDate(end[0], end[1], end[2]).getTime()
return {
start,
end,
startTimestamp,
endTimestamp
}
}
function isValiditeOfDateArea(dateArea) {
const {
start,
end,
startTimestamp,
endTimestamp
} = convertEnableAreaToTimestamp(dateArea)
if (!start || !end) return
const datesCountOfStart = dateUtil.getDatesCountOfMonth(start[0], start[1])
const datesCountOfEnd = dateUtil.getDatesCountOfMonth(end[0], end[1])
if (start[2] > datesCountOfStart || start[2] < 1) {
logger.warn('enableArea() 开始日期错误,指定日期不在指定月份天数范围内')
return false
} else if (start[1] > 12 || start[1] < 1) {
logger.warn('enableArea() 开始日期错误,月份超出1-12月份')
return false
} else if (end[2] > datesCountOfEnd || end[2] < 1) {
logger.warn('enableArea() 截止日期错误,指定日期不在指定月份天数范围内')
return false
} else if (end[1] > 12 || end[1] < 1) {
logger.warn('enableArea() 截止日期错误,月份超出1-12月份')
return false
} else if (startTimestamp > endTimestamp) {
logger.warn('enableArea()参数最小日期大于了最大日期')
return false
} else {
return true
}
}
function handleDisableMode(calendarConfig) {
const { disableMode } = calendarConfig
if (!disableMode) return {}
const disableBound =
dateUtil.getTimeStamp(disableMode.date) || dateUtil.todayTimestamp()
return {
disableBound,
disableType: disableMode.type
}
}
function disabledByConfig(dateInfo, currentDate, calendarConfig) {
const date = { ...dateInfo }
const { disableType, disableBound } = handleDisableMode(calendarConfig)
if (
(disableType === 'before' && disableBound && currentDate < disableBound) ||
(disableType === 'after' && disableBound && currentDate > disableBound)
) {
date.disable = true
} else {
date.disable = false
}
return date
}
export default () => {
return {
name: 'enable',
beforeRender(calendarData = {}, calendarConfig = {}) {
const {
dates,
enableArea,
enableDates,
disableDates,
renderCausedBy
} = calendarData
const _dates = [...dates].map(date => {
let item = { ...date }
const timeStr = dateUtil.toTimeStr(date)
const timestamp = +dateUtil.getTimeStamp(item)
if (renderCausedBy === 'enableDates') {
if (enableDates && enableDates.length) {
if (enableDates.includes(timeStr)) {
item.disable = false
} else {
item.disable = true
}
return item
}
} else if (renderCausedBy === 'enableArea') {
if (enableArea && enableArea.length) {
const [startTimestamp, endTimestamp] = enableArea || []
const ifOutofArea =
+startTimestamp > timestamp || timestamp > +endTimestamp
item.disable = ifOutofArea
return item
}
} else if (renderCausedBy === 'disableDates') {
if (disableDates && disableDates.length) {
if (disableDates && disableDates.includes(timeStr)) {
item.disable = true
} else {
item.disable = false
}
return item
}
}
return disabledByConfig(item, timestamp, calendarConfig)
})
return {
calendarData: {
...calendarData,
dates: _dates
},
calendarConfig
}
},
methods(component) {
return {
enableArea: (dateArea = []) => {
if (dateArea.length === 2) {
const validate = isValiditeOfDateArea(dateArea)
if (validate) {
const existCalendarData = getCalendarData('calendar', component)
const {
startTimestamp,
endTimestamp
} = convertEnableAreaToTimestamp(dateArea)
return renderCalendar.call(component, {
...existCalendarData,
renderCausedBy: 'enableArea',
enableArea: [startTimestamp, endTimestamp]
})
}
} else {
return Promise.inject(
'enableArea()参数需为时间范围数组,形如:["2018-8-4" , "2018-8-24"]'
)
}
},
enableDates: (toSet = []) => {
if (!toSet.length) return
const existCalendarData = getCalendarData('calendar', component)
const { enableDates = [] } = existCalendarData || {}
let toSetDates = toSet.map(item => {
if (typeof item === 'string') {
return dateUtil.transformDateRow2Dict(item)
}
return item
})
if (enableDates.length) {
toSetDates = dateUtil.uniqueArrayByDate([
...toSetDates,
...enableDates.map(d => dateUtil.transformDateRow2Dict(d))
])
}
return renderCalendar.call(component, {
...existCalendarData,
renderCausedBy: 'enableDates',
enableDates: toSetDates.map(date => {
if (typeof date !== 'string') {
return dateUtil.toTimeStr(date)
}
return date
})
})
},
disableDates: toSet => {
const existCalendarData = getCalendarData('calendar', component)
const { disableDates = [], dates = [] } = existCalendarData || {}
let toSetDates = toSet.map(item => {
let date = { ...item }
if (typeof date === 'string') {
return dateUtil.transformDateRow2Dict(item)
}
return item
})
if (disableDates && disableDates.length) {
toSetDates = dateUtil.uniqueArrayByDate([
...toSetDates,
...disableDates.map(d => dateUtil.transformDateRow2Dict(d))
])
}
return renderCalendar.call(component, {
...existCalendarData,
renderCausedBy: 'disableDates',
dates,
disableDates: toSetDates.map(date => {
if (typeof date !== 'string') {
return dateUtil.toTimeStr(date)
}
return date
})
})
}
}
}
}
}

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

File diff suppressed because it is too large Load Diff

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

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

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

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

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

@ -0,0 +1,305 @@ @@ -0,0 +1,305 @@
/**
* @Author: drfu*
* @Description: 时间区域选择
* @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu
* @Last Modified time: 2020-10-11 13:56:32
* */
import { renderCalendar } from '../render'
import {
logger,
dateUtil,
getCalendarConfig,
getCalendarData
} from '../utils/index'
function pusheNextMonthDateArea(
dateInfo = {},
startTimestamp,
endTimestamp,
selectedDates = []
) {
let tempOfSelectedDate = [...selectedDates]
const dates = dateUtil.calcDates(dateInfo.year, dateInfo.month)
let datesLen = dates.length
for (let i = 0; i < datesLen; i++) {
const date = dates[i]
const timeStamp = dateUtil.getTimeStamp(date)
if (timeStamp <= endTimestamp && timeStamp >= startTimestamp) {
tempOfSelectedDate.push({
...date,
choosed: true
})
}
if (i === datesLen - 1 && timeStamp < endTimestamp) {
pusheNextMonthDateArea(
dateUtil.getNextMonthInfo(date),
startTimestamp,
endTimestamp,
tempOfSelectedDate
)
}
}
return tempOfSelectedDate
}
function pushPrevMonthDateArea(
dateInfo = {},
startTimestamp,
endTimestamp,
selectedDates = []
) {
let tempOfSelectedDate = [...selectedDates]
const dates = dateUtil.sortDatesByTime(
dateUtil.calcDates(dateInfo.year, dateInfo.month),
'desc'
)
let datesLen = dates.length
let firstDate = dateUtil.getTimeStamp(dates[0])
for (let i = 0; i < datesLen; i++) {
const date = dates[i]
const timeStamp = dateUtil.getTimeStamp(date)
if (timeStamp >= startTimestamp && timeStamp <= endTimestamp) {
tempOfSelectedDate.push({
...date,
choosed: true
})
}
if (i === datesLen - 1 && firstDate > startTimestamp) {
pushPrevMonthDateArea(
dateUtil.getPrevMonthInfo(date),
startTimestamp,
endTimestamp,
tempOfSelectedDate
)
}
}
return tempOfSelectedDate
}
/**
* 当设置日期区域非当前时保存其它月份的日期至已选日期数组
* @param {object} info
*/
function calcDateWhenNotInOneMonth(info) {
const { firstDate, lastDate, startTimestamp, endTimestamp } = info
let { selectedDate } = info
if (dateUtil.getTimeStamp(firstDate) > startTimestamp) {
selectedDate = pushPrevMonthDateArea(
dateUtil.getPrevMonthInfo(firstDate),
startTimestamp,
endTimestamp,
selectedDate
)
}
if (dateUtil.getTimeStamp(lastDate) < endTimestamp) {
selectedDate = pusheNextMonthDateArea(
dateUtil.getNextMonthInfo(lastDate),
startTimestamp,
endTimestamp,
selectedDate
)
}
return [...selectedDate]
}
/**
* 指定日期区域转时间戳
* @param {array} timearea 时间区域
*/
export function convertTimeRangeToTimestamp(timearea = []) {
const start = timearea[0].split('-')
const end = timearea[1].split('-')
if (start.length !== 3 || end.length !== 3) {
logger.warn('enableArea() 参数格式为: ["2018-2-1", "2018-3-1"]')
return {}
}
const startTimestamp = dateUtil
.newDate(start[0], start[1], start[2])
.getTime()
const endTimestamp = dateUtil.newDate(end[0], end[1], end[2]).getTime()
return {
start,
end,
startTimestamp,
endTimestamp
}
}
/**
* 校验时间区域是否合法
* @param {array} dateArea 时间区域
*/
function validateTimeRange(dateArea) {
const {
start,
end,
startTimestamp,
endTimestamp
} = convertTimeRangeToTimestamp(dateArea)
if (!start || !end) return
const startMonthDays = dateUtil.getDatesCountOfMonth(start[0], start[1])
const endMonthDays = dateUtil.getDatesCountOfMonth(end[0], end[1])
if (start[2] > startMonthDays || start[2] < 1) {
logger.warn('enableArea() 开始日期错误,指定日期不在当前月份天数范围内')
return false
} else if (start[1] > 12 || start[1] < 1) {
logger.warn('enableArea() 开始日期错误,月份超出1-12月份')
return false
} else if (end[2] > endMonthDays || end[2] < 1) {
logger.warn('enableArea() 截止日期错误,指定日期不在当前月份天数范围内')
return false
} else if (end[1] > 12 || end[1] < 1) {
logger.warn('enableArea() 截止日期错误,月份超出1-12月份')
return false
} else if (startTimestamp > endTimestamp) {
logger.warn('enableArea()参数最小日期大于了最大日期')
return false
} else {
return true
}
}
export default () => {
return {
name: 'timeRange',
beforeRender(calendarData = {}, calendarConfig = {}) {
const {
chooseAreaTimestamp = [],
dates = [],
selectedDates = []
} = calendarData
let __dates = dates
let __selectedDates = selectedDates
const [startDateTimestamp, endDateTimestamp] = chooseAreaTimestamp
if (chooseAreaTimestamp.length === 2) {
__selectedDates = []
__dates = dates.map(d => {
const date = { ...d }
const dateTimeStamp = dateUtil.getTimeStamp(date)
if (
dateTimeStamp >= startDateTimestamp &&
endDateTimestamp >= dateTimeStamp
) {
date.choosed = true
__selectedDates.push(date)
} else {
date.choosed = false
__selectedDates = __selectedDates.filter(
item => dateUtil.getTimeStamp(item) !== dateTimeStamp
)
}
return date
})
const monthOfStartDate = new Date(startDateTimestamp).getMonth()
const monthOfEndDate = new Date(endDateTimestamp).getMonth()
if (monthOfStartDate !== monthOfEndDate) {
__selectedDates = calcDateWhenNotInOneMonth({
firstDate: __dates[0],
lastDate: __dates[__dates.length - 1],
startTimestamp: startDateTimestamp,
endTimestamp: endDateTimestamp,
selectedDate: __selectedDates
})
}
}
return {
calendarData: {
...calendarData,
dates: __dates,
selectedDates: dateUtil.sortDatesByTime(
dateUtil.uniqueArrayByDate(__selectedDates)
)
},
calendarConfig
}
},
onTapDate(tapedDate, calendarData = {}, calendarConfig = {}) {
if (!calendarConfig.chooseAreaMode) {
return {
calendarData,
calendarConfig
}
}
let {
tempChooseAreaTimestamp = [],
chooseAreaTimestamp: existChooseAreaTimestamp = [],
selectedDates = [],
dates = []
} = calendarData
const timestamp = dateUtil.getTimeStamp(tapedDate)
let __dates = [...dates]
let __selectedDates = [...selectedDates]
if (
tempChooseAreaTimestamp.length === 2 ||
existChooseAreaTimestamp.length === 2
) {
tempChooseAreaTimestamp = [tapedDate]
__selectedDates = []
__dates.forEach(d => (d.choosed = false))
} else if (tempChooseAreaTimestamp.length === 1) {
const preChoosedDate = tempChooseAreaTimestamp[0]
const preTimestamp = dateUtil.getTimeStamp(preChoosedDate)
if (preTimestamp <= timestamp) {
tempChooseAreaTimestamp.push(tapedDate)
} else if (preTimestamp > timestamp) {
tempChooseAreaTimestamp.unshift(tapedDate)
}
} else {
tempChooseAreaTimestamp = [tapedDate]
}
let chooseAreaTimestamp = []
if (tempChooseAreaTimestamp.length === 2) {
const [startDate, endDate] = tempChooseAreaTimestamp
const startDateTimestamp = dateUtil.getTimeStamp(startDate)
const endDateTimestamp = dateUtil.getTimeStamp(endDate)
chooseAreaTimestamp = [startDateTimestamp, endDateTimestamp]
}
return {
calendarData: {
...calendarData,
chooseAreaTimestamp,
tempChooseAreaTimestamp,
dates: __dates,
selectedDates: __selectedDates
},
calendarConfig: {
...calendarConfig,
multi: true
}
}
},
methods(component) {
return {
/**
* 设置连续日期选择区域
* @param {array} dateArea 区域开始结束日期数组
*/
chooseDateArea: (dateArea = []) => {
if (dateArea.length === 1) {
dateArea = dateArea.concat(dateArea)
}
if (dateArea.length !== 2) return
const isRight = validateTimeRange(dateArea)
if (!isRight) return
const config = getCalendarConfig(component) || {}
const { startTimestamp, endTimestamp } = convertTimeRangeToTimestamp(
dateArea
)
const existCalendarData = getCalendarData('calendar', component)
return renderCalendar.call(
component,
{
...existCalendarData,
chooseAreaTimestamp: [startTimestamp, endTimestamp]
},
{
...config,
multi: true,
chooseAreaMode: true
}
)
}
}
}
}
}

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

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

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

@ -0,0 +1,135 @@ @@ -0,0 +1,135 @@
/**
* @Author: drfu*
* @Description: 代办事项
* @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu
* @Last Modified time: 2020-10-11 14:23:02
* */
import { getCalendarData, dateUtil } from '../utils/index'
import { renderCalendar } from '../render'
function updateDatePropertyOfTodoLabel(todos, dates, showLabelAlways) {
const datesInfo = [...dates]
for (let todo of todos) {
let targetIdx = datesInfo.findIndex(
item => dateUtil.toTimeStr(item) === dateUtil.toTimeStr(todo)
)
let target = datesInfo[targetIdx]
if (!target) continue
if (showLabelAlways) {
target.showTodoLabel = true
} else {
target.showTodoLabel = !target.choosed
}
if (target.showTodoLabel) {
target.todoText = todo.todoText
}
target.color = todo.color
}
return datesInfo
}
export default () => {
return {
name: 'todo',
beforeRender(calendarData = {}, calendarConfig = {}, component) {
const { todos = [], dates = [], showLabelAlways } = calendarData
const dateWithTodoInfo = updateDatePropertyOfTodoLabel(
todos,
dates,
showLabelAlways
)
return {
calendarData: {
...calendarData,
dates: dateWithTodoInfo
},
calendarConfig
}
},
methods(component) {
return {
setTodos: (options = {}) => {
const calendar = getCalendarData('calendar', component)
if (!calendar || !calendar.dates) {
return Promise.reject('请等待日历初始化完成后再调用该方法')
}
const {
circle,
dotColor = '',
pos = 'bottom',
showLabelAlways,
dates: todoDates = []
} = options
const { todos = [] } = calendar
const tranformStr2NumOfTodo = todoDates.map(date =>
dateUtil.tranformStr2NumOfDate(date)
)
const calendarData = {
dates: calendar.dates,
todos: dateUtil.uniqueArrayByDate(
todos.concat(tranformStr2NumOfTodo)
)
}
if (!circle) {
calendarData.todoLabelPos = pos
calendarData.todoLabelColor = dotColor
}
calendarData.todoLabelCircle = circle || false
calendarData.showLabelAlways = showLabelAlways || false
const existCalendarData = getCalendarData('calendar', component)
return renderCalendar.call(component, {
...existCalendarData,
...calendarData
})
},
deleteTodos(todos = []) {
if (!(todos instanceof Array) || !todos.length)
return Promise.reject('deleteTodos()应为入参为非空数组')
const existCalendarData = getCalendarData('calendar', component)
const allTodos = existCalendarData.todos || []
const toDeleteTodos = todos.map(item => dateUtil.toTimeStr(item))
const remainTodos = allTodos.filter(
item => !toDeleteTodos.includes(dateUtil.toTimeStr(item))
)
const { dates, curYear, curMonth } = existCalendarData
const _dates = [...dates]
const currentMonthTodos = dateUtil.filterDatesByYM(
{
year: curYear,
month: curMonth
},
remainTodos
)
_dates.forEach(item => {
item.showTodoLabel = false
})
currentMonthTodos.forEach(item => {
_dates[item.date - 1].showTodoLabel = !_dates[item.date - 1].choosed
})
return renderCalendar.call(component, {
...existCalendarData,
dates: _dates,
todos: remainTodos
})
},
clearTodos() {
const existCalendarData = getCalendarData('calendar', component)
const _dates = [...existCalendarData.dates]
_dates.forEach(item => {
item.showTodoLabel = false
})
return renderCalendar.call(component, {
...existCalendarData,
dates: _dates,
todos: []
})
},
getTodos() {
return getCalendarData('calendar.todos', component) || []
}
}
}
}
}

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

@ -0,0 +1,432 @@ @@ -0,0 +1,432 @@
/**
* @Author: drfu*
* @Description: 周视图
* @Date: 2020-10-08 21:22:09*
* @Last Modified by: drfu
* @Last Modified time: 2020-10-12 14:39:45
* */
import { renderCalendar } from '../render'
import {
getCalendarConfig,
getCalendarData,
logger,
dateUtil
} from '../utils/index'
import { calcJumpData } from '../core'
/**
* 当月第一周所有日期
*/
function firstWeekInMonth(
target = {},
calendarDates = [],
calendarConfig = {}
) {
const { firstDayOfWeek } = calendarConfig
const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
const { year, month } = target
let firstDay = dateUtil.getDayOfWeek(year, month, 1)
if (firstDayOfWeekIsMon && firstDay === 0) {
firstDay = 7
}
const [, end] = [0, 7 - firstDay]
return calendarDates.slice(0, firstDayOfWeekIsMon ? end + 1 : end)
}
/**
* 当月最后一周所有日期
*/
function lastWeekInMonth(target = {}, calendarDates = [], calendarConfig = {}) {
const { firstDayOfWeek } = calendarConfig
const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
const { year, month } = target
const lastDay = dateUtil.getDatesCountOfMonth(year, month)
let lastDayWeek = dateUtil.getDayOfWeek(year, month, lastDay)
if (firstDayOfWeekIsMon && lastDayWeek === 0) {
lastDayWeek = 7
}
const [start, end] = [lastDay - lastDayWeek, lastDay]
return calendarDates.slice(firstDayOfWeekIsMon ? start : start - 1, end)
}
/**
* 判断目标日期是否在某些指定日历内
*/
function dateIsInDatesRange(target, dates) {
if (!target || !dates || !dates.length) return false
const targetDateStr = dateUtil.toTimeStr(target)
let rst = false
for (let date of dates) {
const dateStr = dateUtil.toTimeStr(date)
if (dateStr === targetDateStr) {
rst = true
return rst
}
rst = false
}
return rst
}
function getDatesWhenTargetInFirstWeek(target, firstWeekDates) {
const { year, month } = target
const prevMonthInfo = dateUtil.getPrevMonthInfo({ year, month })
let lastMonthDatesCount = dateUtil.getDatesCountOfMonth(
prevMonthInfo.year,
prevMonthInfo.month
)
let dates = firstWeekDates
let firstWeekCount = firstWeekDates.length
for (let i = 0; i < 7 - firstWeekCount; i++) {
const week = dateUtil.getDayOfWeek(+year, +month, lastMonthDatesCount)
dates.unshift({
year: prevMonthInfo.year,
month: prevMonthInfo.month,
date: lastMonthDatesCount,
week
})
lastMonthDatesCount -= 1
}
return dates
}
function getDatesWhenTargetInLastWeek(target, lastWeekDates) {
const { year, month } = target
const prevMonthInfo = dateUtil.getNextMonthInfo({ year, month })
let dates = lastWeekDates
let lastWeekCount = lastWeekDates.length
for (let i = 0; i < 7 - lastWeekCount; i++) {
const week = dateUtil.getDayOfWeek(+year, +month, i + 1)
dates.push({
year: prevMonthInfo.year,
month: prevMonthInfo.month,
date: i + 1,
week
})
}
return dates
}
function getDates(target, calendarDates = [], calendarConfig = {}) {
const { year, month, date } = target
const targetDay = dateUtil.getDayOfWeek(year, month, date)
const { firstDayOfWeek } = calendarConfig
const firstDayOfWeekIsMon = firstDayOfWeek === 'Mon'
if (firstDayOfWeekIsMon) {
const startIdx = date - (targetDay || 7)
return calendarDates.splice(startIdx, 7)
} else {
const startIdx = date - targetDay - 1
return calendarDates.splice(startIdx, 7)
}
}
function getTargetWeekDates(target, calendarConfig) {
if (!target) return
const { year, month } = target
const calendarDates = dateUtil.calcDates(year, month)
const firstWeekDates = firstWeekInMonth(target, calendarDates, calendarConfig)
const lastWeekDates = lastWeekInMonth(target, calendarDates, calendarConfig)
if (dateIsInDatesRange(target, firstWeekDates)) {
return getDatesWhenTargetInFirstWeek(target, firstWeekDates)
} else if (dateIsInDatesRange(target, lastWeekDates)) {
return getDatesWhenTargetInLastWeek(target, lastWeekDates)
} else {
return getDates(target, calendarDates, calendarConfig)
}
}
/**
* 计算周视图下当前这一周最后一天
*/
function calculateLastDateOfCurrentWeek(calendarData = {}) {
const { dates = [] } = calendarData
return dates[dates.length - 1]
}
/**
* 计算周视图下当前这一周第一天
*/
function calculateFirstDateOfCurrentWeek(calendarData = {}) {
const { dates } = calendarData
return dates[0]
}
/**
* 计算下一周的日期
*/
function calculateNextWeekDates(calendarData = {}) {
let { curYear, curMonth } = calendarData
let calendarDates = []
let lastDateInThisWeek = calculateLastDateOfCurrentWeek(calendarData)
const { year: LYear, month: LMonth } = lastDateInThisWeek
if (curYear !== LYear || curMonth !== LMonth) {
calendarDates = dateUtil.calcDates(LYear, LMonth)
curYear = LYear
curMonth = LMonth
} else {
calendarDates = dateUtil.calcDates(curYear, curMonth)
}
const lastDateInThisMonth = dateUtil.getDatesCountOfMonth(curYear, curMonth)
const count = lastDateInThisMonth - lastDateInThisWeek.date
const lastDateIdx = calendarDates.findIndex(
date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(lastDateInThisWeek)
)
const startIdx = lastDateIdx + 1
if (count >= 7) {
return {
dates: calendarDates.splice(startIdx, 7),
year: curYear,
month: curMonth
}
} else {
const nextMonth = dateUtil.getNextMonthInfo({
year: curYear,
month: curMonth
})
const { year, month } = nextMonth || {}
const calendarDatesOfNextMonth = dateUtil.calcDates(year, month)
const remainDatesOfThisMonth = calendarDates.splice(startIdx)
const patchDatesOfNextMonth = calendarDatesOfNextMonth.splice(
0,
7 - remainDatesOfThisMonth.length
)
return {
dates: [...remainDatesOfThisMonth, ...patchDatesOfNextMonth],
...nextMonth
}
}
}
/**
* 计算上一周的日期
*/
function calculatePrevWeekDates(calendarData = {}) {
let { curYear, curMonth } = calendarData
let firstDateInThisWeek = calculateFirstDateOfCurrentWeek(calendarData)
let calendarDates = []
const { year: FYear, month: FMonth } = firstDateInThisWeek
if (curYear !== FYear || curMonth !== FMonth) {
calendarDates = dateUtil.calcDates(FYear, FMonth)
curYear = FYear
curMonth = FMonth
} else {
calendarDates = dateUtil.calcDates(curYear, curMonth)
}
const firstDateIdx = calendarDates.findIndex(
date => dateUtil.toTimeStr(date) === dateUtil.toTimeStr(firstDateInThisWeek)
)
if (firstDateIdx - 7 >= 0) {
const startIdx = firstDateIdx - 7
return {
dates: calendarDates.splice(startIdx, 7),
year: curYear,
month: curMonth
}
} else {
const prevMonth = dateUtil.getPrevMonthInfo({
year: curYear,
month: curMonth
})
const { year, month } = prevMonth || {}
const calendarDatesOfPrevMonth = dateUtil.calcDates(year, month)
const remainDatesOfThisMonth = calendarDates.splice(
0,
firstDateInThisWeek.date - 1
)
const patchDatesOfPrevMonth = calendarDatesOfPrevMonth.splice(
-(7 - remainDatesOfThisMonth.length)
)
return {
dates: [...patchDatesOfPrevMonth, ...remainDatesOfThisMonth],
...prevMonth
}
}
}
export default () => {
return {
name: 'week',
beforeRender(calendarData = {}, calendarConfig = {}, component) {
const { initializedWeekMode, selectedDates } = calendarData
if (calendarConfig.weekMode && !initializedWeekMode) {
const { defaultDate } = calendarConfig
const target =
(selectedDates && selectedDates[0]) ||
(defaultDate && dateUtil.transformDateRow2Dict(defaultDate)) ||
dateUtil.todayFMD()
const waitRenderData = this.methods(
component
).__calcDatesWhenSwitchView('week', target)
const { data, config } = waitRenderData || {}
const setSelectDates = this.methods(
component
).__selectTargetDateWhenJump(target, data.dates, config)
return {
calendarData: {
...data,
...setSelectDates,
weeksCh: dateUtil.getWeekHeader(calendarConfig.firstDayOfWeek),
initializedWeekMode: true
},
calendarConfig
}
}
return {
calendarData,
calendarConfig
}
},
onSwitchCalendar(target = {}, calendarData = {}, component) {
const { direction } = target
const { curYear, curMonth } = calendarData
const calendarConfig = getCalendarConfig(component)
let waitRenderData = {}
if (calendarConfig.weekMode) {
if (direction === 'left') {
waitRenderData = calculateNextWeekDates(calendarData)
} else {
waitRenderData = calculatePrevWeekDates(calendarData)
}
const { dates, year, month } = waitRenderData
return {
...calendarData,
dates,
curYear: year || curYear,
curMonth: month || curMonth
}
}
return calendarData
},
methods(component) {
return {
__selectTargetDateWhenJump: (target = {}, dates = [], config = {}) => {
let selectedDate = target
const weekDates = dates.map((date, idx) => {
const tmp = { ...date }
tmp.id = idx
const isTarget =
dateUtil.toTimeStr(target) === dateUtil.toTimeStr(tmp)
if (isTarget && !target.choosed && config.autoChoosedWhenJump) {
tmp.choosed = true
selectedDate = tmp
}
return tmp
})
return {
dates: weekDates,
selectedDates: [selectedDate]
}
},
__calcDatesForWeekMode(target, config = {}, calendarData = {}) {
const { year, month } = target || {}
const weekDates = getTargetWeekDates(target, config)
weekDates.forEach((date, idx) => (date.id = idx))
return {
data: {
...calendarData,
prevMonthGrids: null,
nextMonthGrids: null,
dates: weekDates,
curYear: year,
curMonth: month
},
config: {
...config,
weekMode: true
}
}
},
__calcDatesForMonthMode(target, config = {}, calendarData = {}) {
const { year, month } = target || {}
const waitRenderData = calcJumpData({
dateInfo: target,
config
})
return {
data: {
...calendarData,
...waitRenderData,
curYear: year,
curMonth: month
},
config: {
...config,
weekMode: false
}
}
},
/**
* 月视图切换
* @param {string} view 视图 [week, month]
* @param {object} target
*/
__calcDatesWhenSwitchView: (view, target) => {
const calendarConfig = getCalendarConfig(component)
if (calendarConfig.multi)
return logger.warn('多选模式不能切换周月视图')
const existCalendarData = getCalendarData('calendar', component) || {}
const {
selectedDates = [],
dates = [],
curYear,
curMonth
} = existCalendarData
const currentMonthSelected = selectedDates.filter(
item => curYear === +item.year || curMonth === +item.month
)
let jumpTarget = {}
if (target) {
jumpTarget = target
} else {
if (currentMonthSelected.length) {
jumpTarget = currentMonthSelected.pop()
} else {
jumpTarget = dates[0]
}
}
if (view === 'week') {
return this.methods(component).__calcDatesForWeekMode(
jumpTarget,
calendarConfig,
existCalendarData
)
} else {
return this.methods(component).__calcDatesForMonthMode(
jumpTarget,
calendarConfig,
existCalendarData
)
}
},
weekModeJump: dateInfo => {
const target = dateInfo || dateUtil.todayFMD()
const existCalendarData = getCalendarData('calendar', component) || {}
const waitRenderData = this.methods(
component
).__calcDatesWhenSwitchView('week', target)
const { data, config } = waitRenderData || {}
const setSelectDates = this.methods(
component
).__selectTargetDateWhenJump(target, data.dates, config)
return renderCalendar.call(
component,
{
...existCalendarData,
...data,
...setSelectDates
},
config
)
},
switchView: (view, target) => {
const waitRenderData = this.methods(
component
).__calcDatesWhenSwitchView(view, target)
const { data, config } = waitRenderData || {}
if (!data) return logger.warn('当前状态不能切换为周视图')
return renderCalendar.call(component, data, config)
}
}
}
}
}

49
src/components/calendar/render.js

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

29
src/components/calendar/theme/iconfont.wxss

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
@font-face {
font-family: 'iconfont';
src: url(data:font/truetype;charset=utf-8;base64,AAEAAAANAIAAAwBQRkZUTYda3jUAAAfEAAAAHEdERUYAKQANAAAHpAAAAB5PUy8yPllJ4AAAAVgAAABWY21hcAAP65kAAAHIAAABQmdhc3D//wADAAAHnAAAAAhnbHlmLotR3AAAAxwAAAGkaGVhZBTU+ykAAADcAAAANmhoZWEHKwOFAAABFAAAACRobXR4DasB4gAAAbAAAAAWbG9jYQC0AR4AAAMMAAAAEG1heHABEwAyAAABOAAAACBuYW1lKeYRVQAABMAAAAKIcG9zdEoLnOYAAAdIAAAAUgABAAAAAQAAiPM8al8PPPUACwQAAAAAANjbW5YAAAAA2NtblgCzAAQDTQL8AAAACAACAAAAAAAAAAEAAAOA/4AAXAQAAAAAAANNAAEAAAAAAAAAAAAAAAAAAAAEAAEAAAAHACYAAgAAAAAAAgAAAAoACgAAAP8AAAAAAAAAAQQAAZAABQAAAokCzAAAAI8CiQLMAAAB6wAyAQgAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABA5+vn7gOA/4AAXAOAAIAAAAABAAAAAAAABAAAAAAAAAAEAAAABAABLgD4ALQAswAAAAAAAwAAAAMAAAAcAAEAAAAAADwAAwABAAAAHAAEACAAAAAEAAQAAQAA5+7//wAA5+v//xgYAAEAAAAAAAABBgAAAQAAAAAAAAABAgAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgBMAI4A0gABAS4ABAMKAvwAEgAACQEmBh0BFBcJAQYdARQWNwE2NAL+/j0ECQYBaP6YBgkEAcMMAZkBYAMEBU0IBf7n/ucFCE0FBAMBYAoeAAAAAQD4AAQC1AL8ABIAAAE1NCYHAQYUFwEWNj0BNCcJATYC1AkE/j0MDAHDBAkG/pgBaAYCpk0FBAP+oAoeCv6gAwQFTQgFARkBGQUAAAIAtAAgA00C4AASACUAAAkBNiYrASIHAwYUFwEWOwEyNicTATYmKwEiBwMGFBcBFjsBMjYnAREBCQMEBU0IBf8HBwD/BQhNBQQDJwEJAwQFTQgF/wcHAP8FCE0FBAMBgAFTBAkG/roJFgn+ugYJBAFTAVMECQb+ugkWCf66BgkEAAAAAAIAswAgA0wC4AASACUAAAEDJisBIgYXCQEGFjsBMjcBNjQlAyYrASIGFwkBBhY7ATI3ATY0AhX/BQhNBQQDAQn+9wMEBU0IBQD/BwEp/wUITQUEAwEJ/vcDBAVNCAUA/wcBlAFGBgkE/q3+rQQJBgFGCRYJAUYGCQT+rf6tBAkGAUYJFgAAAAAAABIA3gABAAAAAAAAABUALAABAAAAAAABAAgAVAABAAAAAAACAAcAbQABAAAAAAADAAgAhwABAAAAAAAEAAgAogABAAAAAAAFAAsAwwABAAAAAAAGAAgA4QABAAAAAAAKACsBQgABAAAAAAALABMBlgADAAEECQAAACoAAAADAAEECQABABAAQgADAAEECQACAA4AXQADAAEECQADABAAdQADAAEECQAEABAAkAADAAEECQAFABYAqwADAAEECQAGABAAzwADAAEECQAKAFYA6gADAAEECQALACYBbgAKAEMAcgBlAGEAdABlAGQAIABiAHkAIABpAGMAbwBuAGYAbwBuAHQACgAACkNyZWF0ZWQgYnkgaWNvbmZvbnQKAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABSAGUAZwB1AGwAYQByAABSZWd1bGFyAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABWAGUAcgBzAGkAbwBuACAAMQAuADAAAFZlcnNpb24gMS4wAABpAGMAbwBuAGYAbwBuAHQAAGljb25mb250AABHAGUAbgBlAHIAYQB0AGUAZAAgAGIAeQAgAHMAdgBnADIAdAB0AGYAIABmAHIAbwBtACAARgBvAG4AdABlAGwAbABvACAAcAByAG8AagBlAGMAdAAuAABHZW5lcmF0ZWQgYnkgc3ZnMnR0ZiBmcm9tIEZvbnRlbGxvIHByb2plY3QuAABoAHQAdABwADoALwAvAGYAbwBuAHQAZQBsAGwAbwAuAGMAbwBtAABodHRwOi8vZm9udGVsbG8uY29tAAACAAAAAAAAAAoAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAcAAAABAAIBAgEDAQQBBQVyaWdodARsZWZ0CmRvdWJsZWxlZnQLZG91YmxlcmlnaHQAAAAAAAH//wACAAEAAAAMAAAAFgAAAAIAAQADAAYAAQAEAAAAAgAAAAAAAAABAAAAANWkJwgAAAAA2NtblgAAAADY21uW) format('truetype');
font-weight: normal;
font-style: normal;
}
.iconfont {
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
}
.icon-right::before {
content: "\e7eb";
}
.icon-left::before {
content: "\e7ec";
}
.icon-doubleleft::before {
content: "\e7ed";
}
.icon-doubleright::before {
content: "\e7ee";
}

61
src/components/calendar/theme/theme-default.wxss

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
/* 日历主要颜色相关样式 */
.default_color,
.default_weekend-color,
.default_handle-color,
.default_week-color {
color: #ff629a;
}
.default_today {
color: #fff;
background-color: #874fb4;
}
.default_choosed {
color: #fff;
background-color: #ff629a;
}
.default_date-disable {
color: #c7c7c7;
}
.default_choosed.default_date-disable {
color: #e2e2e2;
background-color: #c2afb6;
}
.default_prev-month-date,
.default_next-month-date {
color: #e2e2e2;
}
.default_normal-date {
color: #88d2ac;
}
.default_todo-circle {
border-color: #88d2ac;
}
.default_todo-dot {
background-color: #e54d42;
}
.default_date-desc {
color: #c2c2c2;
}
.default_date-desc-lunar {
color: #e54d42;
}
.default_date-desc-disable {
color: #e2e2e2;
}
.default_festival {
color: #c2c2c2;
}

58
src/components/calendar/theme/theme-elegant.wxss

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
.elegant_color,
.elegant_weekend-color,
.elegant_handle-color,
.elegant_week-color {
color: #333;
}
.elegant_today {
color: #000;
background-color: #e1e7f5;
}
.elegant_choosed {
color: #000;
background-color: #e2e2e2;
}
.elegant_date-disable {
color: #c7c7c7;
}
.elegant_choosed.elegant_date-disable {
color: #999;
background-color: #ebebeb;
}
.elegant_prev-month-date,
.elegant_next-month-date {
color: #e2e2e2;
}
.elegant_normal-date {
color: #777;
}
.elegant_todo-circle {
border-color: #161035;
}
.elegant_todo-dot {
background-color: #161035;
}
.elegant_date-desc {
color: #c2c2c2;
}
.elegant_date-desc-lunar {
color: #161035;
}
.elegant_date-desc-disable {
color: #e2e2e2;
}
.elegant_festival {
color: #c2c2c2;
}

90
src/components/calendar/theme/theme-nuohe.wxss

@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
/* 日历主要颜色相关样式 */
.nuohe_color,
.nuohe_weekend-color,
.nuohe_handle-color,
.nuohe_week-color {
color: rgba(51, 51, 51, 1);
}
.nuohe_today {
color: #fff;
background-color: #874fb4;
}
.nuohe_choosed {
color: rgba(51, 51, 51, 1);
background-color: rgba(189, 189, 189, 0.3);
}
.nuohe_date-disable {
color: #c7c7c7;
}
.nuohe_choosed.nuohe_date-disable {
color: #e2e2e2;
background-color: #c2afb6;
}
.nuohe_prev-month-date,
.nuohe_next-month-date {
color: #e2e2e2;
}
.nuohe_normal-date {
color: rgba(51, 51, 51, 1);
}
.nuohe_todo-circle {
border-color: #88d2ac;
}
.nuohe_todo-dot {
background-color: #e54d42;
}
.nuohe_date-desc {
color: #c2c2c2;
}
.nuohe_date-desc-lunar {
color: #e54d42;
}
.nuohe_date-desc-disable {
color: #e2e2e2;
}
.nuohe_festival {
color: #c2c2c2;
}
.date.doc {
position: relative;
background-color: #e5e5e5;
}
.date.doc::after {
position: absolute;
z-index: 1;
top: -5rpx;
right: -5rpx;
content: "";
width: 17rpx;
height: 24rpx;
background-repeat: no-repeat;
background-size: cover;
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACwAAABACAYAAABhspUgAAAAAXNSR0IArs4c6QAACAVJREFUaEPtmltsHFcZx/9nZu92bMdJSMitzoWkoXVKUrVV8wKk4gHxgJTwgKA8lhfgCZBoUJEqUYGA0AhRQUSpFJQIHlyqogZFIipUoKiAKJAYQkp9qR1ir9fe6+zuXM4FfWf2MrOJY+/aS0zlkRxZzsw5v/nP/3znO+c7DItcl4vFTWVl/7wg5EctKSK2knCVBFcKcrGH7vL3MvfwVnYeGbsaustgAAODCSDCDLU1Hp/Ym+o7fnrvB9+9U3NssT5ezWe+k5X8qwvCQ0FwVKSEswJg6sfmHH+cm2l0SZ3Tj8F84ChjiDID+1I9ly4ceuTjbQFfyM2MpDk/meEu8oKjJIUG9khh1YHEtUeupgPAWl3AAENEwzLEmIGd8dToq8OPDbcF/OLCrZFZ7p5Mcxc5wVEUAmQLT8mOLFHvfCwzF7ZEC3CcGdiRSIxeHD7WHvDZhZsjM56ngbMELDlsWVO4c4ExOd8E9i1R969vhzhj2BFPjv76cJvApPCtkMK8YYkVOALLUXh7PNE+8M/Iw553MiN8S1ii6eGVAI+mZ0PfhzHoAWfWBlyMMWyPJ0dfG368PUu8nJ8bWRD8ZPYOUWIlwH+YmQ4Dg8FoAPu22J5Ijb7ywKPtAV8uZZ/LC36qIH11q7UIIZRCp8CW5+Ly7M3bgVkzUlC0ONC74VcvHTj6ybaiBN38RmVhV9YxTBs2nrl08VTRrjy1gvEGZRh+HGu5epOp808ceehMFFEkDYN/f++Df1+sn0UnjtYHjB9+63tQ6ssrAV70WcZOyy8+/ZXltL0o8Hfzk3u4jc94Bh7nSm0uOZWNruvFozBMkzEG+iF3KGm5XJTAZFVIxRXCjnGkNB0pIwXPTWYcu6/MeYLAgh1HozHeE48VE6Y5vyFiXknFoufO73/4nWVZ4kwmc9BG5QVLiONcKSYYEFU0z/vd1P3rQaEiBYiwnSvr2Jgo5mFxTz9Gcbj+AjTjmczPKbbF41fej9jnzz5w9J/B9kMKP58e/1xO4ayjZNKlwaUUkqYJJZsDjRKfBcH1dN3pRa3dKpUwX61oqRs5RS1amLWpOmWYzv5k7xfO3X/0p/W+GsBnMtNPLQjvx1UlDUcKQDEkDKanYRJR6W+tMM0dzPPOYYMvmauWkStXfOBA1kYxWecWMJAwDHV/T9+Xzh088kLDSmfmpx9b8Lw3qpDxqv7MCilmaFBJ/9aMmZYcY05VK78aFw2DrGXBdp2AymSLQDIEAynD9B4c3PKRnwwduqIV/ubc5N+Kgj9EnqQEhxIQ+iwyEHPJIm+WSxBMj7TV4NX+lVIiXyzURGCg/NjP3ijdNEAzH/FsjcX/dWn42CH2g+zMJ9Ju5bWyFDrnFQB6GMGSur4N6Bpzq5hwnVUBbW2kWq3CcXyV6QoMvgZwghk43Dtwgn17burlrHBPaGAlEQFDnN68Bku41NDvrQLsVVK2FZhzAcsqNYCpP/rCZA2tsGGAgIeSvRfZs3Pj0wUhdpZr028vo/cj4OaHJ+WvVIpdUbfeaKHg26KpMoU3P7cgaALeHIun2TPpcaskeE9ZSp0v9DPTjwoB4Cytx+xyV4FLxSKE9FeL9TDnZ3D+KoSA+yIRm52aGVOWEiBLVKXEoBHRdtDRoXbNcQ9XuwxMliBrhIBr8VgDGwxJZoI9TcCSo6wkHCmxUQOHV8Zz3MVVu9JVha2SBR6YjCjlrK/1tCUMwwf+WgDYrQGLlsC1VoDJFiHgoMLBSLsWgClSJOvAJdncd6hbYi0B08DzLVFTeB24g+F5t0G3rnAHgt72yLrC93LieO952ARHVDWXQQVuYbqaWQ2rLtrGVJmhEljR6pyRFqS1fIKS+LjB/JmuNQ7vlrMYUs1dxp3udRwrvdJV4GedJ3BDbl6yj1UFdgsJVNMbQp0mt5UQ67OXBLknwOO/OILi2KYQXN++Bez99F/XJvA75x+G9e7GEFzvfTnsf/Iv68CNKhFla50OujWtsD3fA2tyMPSpM3/eBSebCv0tPljBlkfCm9i9Q1kkNofXiF0fdJO/HEb++tYlvXmnGwYOpTF04lrov7oOPDFyGIUb7+sIuP9gBns+Fd6zXgdunen+7xT+z28OIPOn3R1ZYsujU9jxsbf/tx6m3pQMVxzGLhyFNdUycezOYd9n3wrBMeP23c+ue/hO0q7pOLwOfC/Sy1uvfwDZa9tC4g8Oz2L78X8vOTjviYeXpLrLDSsC3qqy2KZyjeYH3EnsKf92JTxLPvti9UOYkv233eefWKEqE52rWGSJFNx9pxbu9Wbge2/VvOYVru/Ar+UN7cb+8FosGTRrz35RpulhE+zrs1TjoKKMf5BuIzN1cTFYRcpwD6NOd2scxRIVZZqbN/q0la7sN6tIumTwjdlxXUWqCAIW6KeiTMtxxXnh4boTPoK4ZJxq84ZssQgvAEwl3HpVXyusK0kG2HNzk/mSEP0VJfS5NCosKjq7USuAU15lKYkbXa4i3czlwOkUQe0KAtfrzf2RqMVOZ6Z+VxD8w1RUJEtElV9JDx4Ipd8nXFtX+btxOULg7ay/d9eohDL/tFX9PCZB70qk3mQ/ys0M5T3nWlXKXqrYcyaRpFtrRw7qiPQyRa3Aso8JLevdqAg/mptHwW1uZ9XPYxIwiUc/GyLRyuH+LcO6d4KuCv5SRYojrpQDFIcjMLTp60dcdMJel6D1YM+y0MI3uUIg57n4RyGLoueGE/xar2SLHsO0NsXi13b1DDz5/H0Hxv8Lo3UyF0Y2DrcAAAAASUVORK5CYII=");
}
.date.error {
background-color: rgba(207, 83, 117, 1);
border-radius: 50%;
color: #fff;
}
.date.primary {
background-color: rgba(37, 217, 200, 1);
color: #fff;
border-radius: 50%;
}

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

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

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

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

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

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

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

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

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

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

4
src/components/ec-canvas/ec-canvas.wxml

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
<!-- 新的:接口对其了H5 -->
<canvas wx:if="{{isUseNewCanvas}}" type="2d" class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas>
<!-- 旧的 -->
<canvas wx:else class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas>

5
src/components/ec-canvas/ec-canvas.wxss

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
.ec-canvas {
width: 100%;
height: 100%;
z-index: 1;
}

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

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

352
src/components/freeAudio/index.js

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

54
src/components/freeAudio/index.wxml

@ -1,26 +1,28 @@ @@ -1,26 +1,28 @@
<view class="audio">
<view class="card-auth">
<image
class="icon extend-via-pseudo-elem"
src="{{imageUrl}}1/audio-{{play?'pause':'play'}}.png?t={{Timestamp}}"
catchtap="togglePlay"
></image>
<view
class="center"
>
<image class="progress-bg" mode="aspectFill" src="https://m.zd.hbraas.com/zd/1/firee-audio-bg.png?t=1689998782161"></image>
<slider
active
activeColor="#E04775"
backgroundColor="#E04775"
bind:changing="handleAuthChangeimg"
bindchange="handleAuthChange"
block-color="#E04775"
block-size="12"
class="progress"
value="{{progress}}"
/>
</view>
<text class="time" wx:if="{{duration}}">{{duration}}</text>
</view>
</view>
<view class="audio">
<view class="card-auth">
<image
class="icon extend-via-pseudo-elem"
src="{{imageUrl}}za-images/1/audio-{{play?'pause':'play'}}.png?t={{Timestamp}}"
catchtap="togglePlay"
></image>
<view class="center">
<image
class="progress-bg"
mode="aspectFill"
src="https://m.zd.hbraas.com/zd/1/firee-audio-bg.png?t=1689998782161"
></image>
<slider
active
activeColor="#E04775"
backgroundColor="#E04775"
bind:changing="handleAuthChangeimg"
bindchange="handleAuthChange"
block-color="#E04775"
block-size="12"
class="progress"
value="{{progress}}"
/>
</view>
<text class="time" wx:if="{{duration}}">{{duration}}</text>
</view>
</view>

14
src/components/pageNavbar/index.wxml

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<van-nav-bar title="" custom-style="background:transparent;">
<view class="navbar" slot="left">
<van-icon wx:if="{{back}}" class="back-icon" name="arrow-left" color="#333333" size="22" bind:tap="handleBack" />
<image wx:if="{{drug}}" class="drug-nav-img" src="{{imageUrl}}1.5/page-title.png?t={{Timestamp}}"></image>
<image wx:else class="nav-img" src="{{imageUrl}}1/page-title.png?t={{Timestamp}}"></image>
</view>
</van-nav-bar>
<van-nav-bar title="" custom-style="background:transparent;">
<view class="navbar" slot="left">
<van-icon wx:if="{{back}}" class="back-icon" name="arrow-left" color="#333333" size="22" bind:tap="handleBack" />
<image wx:if="{{drug}}" class="drug-nav-img" src="{{imageUrl}}za-images/1.5/page-title.png?t={{Timestamp}}"></image>
<image wx:else class="nav-img" src="{{imageUrl}}za-images/1/page-title.png?t={{Timestamp}}"></image>
</view>
</van-nav-bar>

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

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"van-tabbar": "@vant/weapp/tabbar/index",
"van-tabbar-item": "@vant/weapp/tabbar-item/index"
}
}

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

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
/* custom-tab-bar/index.wxss */
.tab-item {
.icon {
width: 50rpx;
height: 50rpx;
}
.name {
font-size: 24rpx;
color: #CCCCCC;
&.active{
color: #CF5375;
}
&.drug-active{
color: #25D9C8;
}
}
}

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

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
import { getCurrentPageUrl } from '@/utils/util';
const app = getApp();
Component({
properties: {},
data: {
imageUrl: app.globalData.imageUrl,
isChild: 0,
active: 0,
list: [
{
pagePath: '/patient/pages/index/index',
text: '首页',
icon: 'home',
iconActive: 'home-active',
},
{
pagePath: '/patient/pages/repository/index',
text: 'MG全知道',
icon: 'story',
iconActive: 'story-active',
},
{
pagePath: '/patient/pages/live/index',
text: '周三大咖说',
icon: 'gift',
iconActive: 'gift-active',
},
{
pagePath: '/patient/pages/story/index',
text: '向往的生活',
icon: 'class',
iconActive: 'class-active',
},
{
pagePath: '/patient/pages/my/index',
text: '我的',
icon: 'my',
iconActive: 'my-active',
},
],
userInfo: {},
showRed: false,
anyWhere: false,
config: {} as any,
},
observers: {},
lifetimes: {
ready() {
app.zdGetTheme().then((res) => {
this.setData({
theme: res,
});
});
const pagePath = getCurrentPageUrl();
const active = this.data.list.findIndex((item) => item.pagePath === pagePath);
this.setData({
active,
anyWhere: app.globalData.anyWhere,
});
this.setData({
showRed: app.globalData.showRed,
});
// getApp().registerListener(() => {
// this.setData({
// anyWhere: app.globalData.anyWhere,
// });
// wx.ajax({
// method: 'GET',
// url: '?r=zd/common/get-config',
// }).then((res) => {
// this.setData({
// config: res,
// });
// });
// });
},
},
methods: {
onChange() {},
handleNav(e) {
const { index } = e.currentTarget.dataset;
const { list, config } = this.data;
const pagePath = list[index].pagePath;
app.globalData.BeginnerCardId = '';
this.setData({
anyWhere: app.globalData.anyWhere,
});
if (pagePath == '/patient/pages/my/index') {
app.zdPermissionVerification(2, 0, `/patient/pages/index/index`).then(() => {
wx.reLaunch({
url: pagePath,
});
});
} else if (pagePath == '/patient/pages/repository/index' && config.picTextEbookStatus == 1) {
app.zdPermissionVerification(2, 0, `/pages/repository/index`).then(() => {
const webviewUrl = encodeURIComponent(
`${app.globalData.url}/zdcare/#/cover?loginState=${app.globalData.loginState}`,
);
wx.navigateTo({
url: `/patient/pages/webview/index?url=${webviewUrl}`,
});
});
} else {
wx.reLaunch({
url: pagePath,
});
}
},
},
});

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

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
<van-tabbar active="{{ active }}" active-color="#CF5375" bind:change="onChange" inactive-color="#CCCCCC">
<block wx:for="{{list}}" wx:key="*this">
<van-tabbar-item
class="tab-item"
wx:if="{{ index != 3 || !anyWhere}}"
bind:tap="handleNav"
data-index="{{index}}"
icon="{{imageUrl}}za-images/tabbar/{{active==index ? (theme === 'DRUG' ? 'drug-' :'' ) + item.iconActive: item.icon}}.png"
>
<!-- <image class="icon" mode="aspectFit" slot="icon" src="{{imageUrl}}/tabbar/{{item.icon}}.png" /> -->
<!-- <image class="icon" mode="aspectFit" slot="icon-active" src="{{imageUrl}}/tabbar/{{item.iconActive}}.png" /> -->
<view class="name {{index==active && (theme === 'DRUG' ? 'drug-active' :'active')}}">{{item.text}}</view>
<view class="hot"></view>
</van-tabbar-item>
</block>
</van-tabbar>

408
src/components/star/index.ts

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

278
src/components/toast/index.ts

@ -1,139 +1,139 @@ @@ -1,139 +1,139 @@
const app = getApp()
Component({
properties: {
show: {
type: Boolean,
value: false,
},
type: String,
params: {
type: Object,
value() {
return {}
},
},
},
observers: {
show(val) {
if (val) {
app.getTheme().then((res) => {
this.setData({
theme: res,
})
})
if (this.data.params.timeOut) {
let time = this.data.params.timeOut
const timerFunc = () => {
if (time <= 0) {
this.setData({
timeOut: '',
})
clearInterval(this.timer)
return
}
this.setData({
timeOut: `${time}s`,
})
--time
}
timerFunc()
this.timer = setInterval(timerFunc, 1000)
}
if (['storyLead', 'storyStar', 'storyShare'].includes(this.data.type)) {
this.getSettingInfo()
}
}
this.setData({
userInfo: app.globalData.userInfo,
})
},
type(val) {
if (val === 'healthCare') {
this.getOpenPatientList()
}
},
},
data: {
imageUrl: '',
protocol: true,
timeOut: '',
settingsInfo: {},
userInfo: {},
openPatientList: {},
},
lifetimes: {
attached() {
this.setData({
imageUrl: app.globalData.imageUrl,
Timestamp: app.globalData.Timestamp,
})
},
},
methods: {
timer: null as any,
handleOk() {
if (this.data.timeOut) {
return
}
this.triggerEvent('ok', { protocol: this.data.protocol })
},
handleCancel(e = { currentTarget: { dataset: { key: '' } } }) {
const { key } = e.currentTarget.dataset
if (this.timer) {
clearInterval(this.timer)
this.setData({
timeOut: '',
})
}
this.triggerEvent('cancel', { key })
},
handleTaskCancel() {
this.triggerEvent('taskCancel')
},
handleJump() {
this.triggerEvent('jump')
},
handleDel() {
this.triggerEvent('del')
},
routerTo(e) {
const { path } = e.currentTarget.dataset
wx.navigateTo({
url: path,
})
this.handleCancel()
},
getSettingInfo() {
wx.ajax({
method: 'GET',
url: '?r=xd/drugs/setting-info',
data: {},
}).then((res) => {
this.setData({
settingsInfo: res,
})
})
},
getOpenPatientList() {
wx.ajax({
method: 'GET',
url: '?r=xd/nrdl/open-patient-list',
data: {},
}).then((res) => {
this.setData({
openPatientList: res,
})
})
},
handleProtocolChange() {
this.setData({
protocol: !this.data.protocol,
})
},
handleAdlQuestion() {
wx.navigateTo({
url: '/pages/repositoryDetail/index?id=9',
})
},
},
})
const app = getApp();
Component({
properties: {
show: {
type: Boolean,
value: false,
},
type: String,
params: {
type: Object,
value() {
return {};
},
},
},
observers: {
show(val) {
if (val) {
app.zdGetTheme().then((res) => {
this.setData({
theme: res,
});
});
if (this.data.params.timeOut) {
let time = this.data.params.timeOut;
const timerFunc = () => {
if (time <= 0) {
this.setData({
timeOut: '',
});
clearInterval(this.timer);
return;
}
this.setData({
timeOut: `${time}s`,
});
--time;
};
timerFunc();
this.timer = setInterval(timerFunc, 1000);
}
if (['storyLead', 'storyStar', 'storyShare'].includes(this.data.type)) {
this.getSettingInfo();
}
}
this.setData({
zdUserInfo: app.globalData.zdUserInfo,
});
},
type(val) {
if (val === 'healthCare') {
this.getOpenPatientList();
}
},
},
data: {
imageUrl: '',
protocol: true,
timeOut: '',
settingsInfo: {},
zdUserInfo: {},
openPatientList: {},
},
lifetimes: {
attached() {
this.setData({
imageUrl: app.globalData.imageUrl,
Timestamp: app.globalData.Timestamp,
});
},
},
methods: {
timer: null as any,
handleOk() {
if (this.data.timeOut) {
return;
}
this.triggerEvent('ok', { protocol: this.data.protocol });
},
handleCancel(e = { currentTarget: { dataset: { key: '' } } }) {
const { key } = e.currentTarget.dataset;
if (this.timer) {
clearInterval(this.timer);
this.setData({
timeOut: '',
});
}
this.triggerEvent('cancel', { key });
},
handleTaskCancel() {
this.triggerEvent('taskCancel');
},
handleJump() {
this.triggerEvent('jump');
},
handleDel() {
this.triggerEvent('del');
},
routerTo(e) {
const { path } = e.currentTarget.dataset;
wx.navigateTo({
url: path,
});
this.handleCancel();
},
getSettingInfo() {
wx.ajax({
method: 'GET',
url: '?r=xd/drugs/setting-info',
data: {},
}).then((res) => {
this.setData({
settingsInfo: res,
});
});
},
getOpenPatientList() {
wx.ajax({
method: 'GET',
url: '?r=xd/nrdl/open-patient-list',
data: {},
}).then((res) => {
this.setData({
openPatientList: res,
});
});
},
handleProtocolChange() {
this.setData({
protocol: !this.data.protocol,
});
},
handleAdlQuestion() {
wx.navigateTo({
url: '/pages/repositoryDetail/index?id=9',
});
},
},
});

147
src/components/toast/index.wxml

@ -6,9 +6,9 @@ @@ -6,9 +6,9 @@
show="{{ show }}"
>
<view class="popup-class" wx:if="{{type=='videoComplate'}}">
<image class="bg" src="{{imageUrl}}/popup-class-bg.png?t={{Timestamp}}"></image>
<image class="bg" src="{{imageUrl}}za-images/popup-class-bg.png?t={{Timestamp}}"></image>
<view class="popup-container">
<image class="badge" src="{{imageUrl}}2/class.gif"></image>
<image class="badge" src="{{imageUrl}}za-images/2/class.gif"></image>
<view class="op" wx:if="{{params.MemberDayScore}}">
<view class="op-tip">训练完成</view>
<view class="title">
@ -34,7 +34,7 @@ @@ -34,7 +34,7 @@
</view>
</view>
<view class="popup-unbind" wx:elif="{{type=='familyUnbind'}}">
<image class="badge" src="{{imageUrl}}/1/f-warn.png?t={{Timestamp}}"></image>
<image class="badge" src="{{imageUrl}}za-images/1/f-warn.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="content">
该亲友号解绑后
@ -50,7 +50,7 @@ @@ -50,7 +50,7 @@
</view>
</view>
<view class="popup-withdraw" wx:elif="{{type=='withdraw'}}">
<image class="badge" src="{{imageUrl}}1/del-story.png?t={{Timestamp}}"></image>
<image class="badge" src="{{imageUrl}}za-images/1/del-story.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="content">
<view>删除代表您将放弃发布此条内容</view>
@ -64,7 +64,7 @@ @@ -64,7 +64,7 @@
</view>
</view>
<view class="popup-withdraw" wx:elif="{{type=='rewithdraw'}}">
<image class="badge" src="{{imageUrl}}/rewithdraw.png?t={{Timestamp}}"></image>
<image class="badge" src="{{imageUrl}}za-images/rewithdraw.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="content">您是希望继续投稿吗?</view>
<view class="footer">
@ -74,7 +74,7 @@ @@ -74,7 +74,7 @@
</view>
</view>
<view class="popup-withdraw" wx:elif="{{type=='delwithdraw'}}">
<image class="badge" src="{{imageUrl}}1/del-story.png?t={{Timestamp}}"></image>
<image class="badge" src="{{imageUrl}}za-images/1/del-story.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="content" wx:if="{{params.Status != 5}}">
删除代表您将放弃发布此条内容
@ -97,7 +97,7 @@ @@ -97,7 +97,7 @@
</view>
</view>
<view class="popup-home-inhibitor" wx:elif="{{type=='homeInhibitor'}}">
<image class="badge" src="{{imageUrl}}/toast-home.png?t={{Timestamp}}"></image>
<image class="badge" src="{{imageUrl}}za-images/toast-home.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="container">
<view class="title">抑制物检测提醒</view>
@ -117,7 +117,7 @@ @@ -117,7 +117,7 @@
</view>
</view>
<view class="popup-my-health-record" wx:if="{{type == 'myHealthRecord'}}">
<image class="badge" src="{{imageUrl}}/records.png?t={{Timestamp}}"></image>
<image class="badge" src="{{imageUrl}}za-images/records.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="title">{{params.date}}</view>
<view class="week">{{params.week}}</view>
@ -164,8 +164,11 @@ @@ -164,8 +164,11 @@
</view>
<view class="popup-soory-enter" wx:if="{{type == 'storyEnter'}}">
<view class="popup-container">
<view class="container" style="background-image: url({{imageUrl}}1/popup-soory-enter-bg.png?t={{Timestamp}})">
<image class="badge" src="{{imageUrl}}1/toast-story-badge.png?t={{Timestamp}}"></image>
<view
class="container"
style="background-image: url({{imageUrl}}za-images/1/popup-soory-enter-bg.png?t={{Timestamp}})"
>
<image class="badge" src="{{imageUrl}}za-images/1/toast-story-badge.png?t={{Timestamp}}"></image>
<view class="content">
(1)您的故事中可能会涉及您、您的孩子或其它人的个人信息甚至敏感个人信息,如个人影像、个人健康信息及生活经历。建议您不要在故事中提及真实身份信息。请您谨慎考虑是否在此公开发布您的故事。您确认并承诺您已经向有关个人进行充分的告知并征得同意。如果有关个人未满14周岁,您确认并承诺您为该儿童的监护人并且同意公开发表该儿童的个人信息。
<view></view>
@ -201,10 +204,10 @@ @@ -201,10 +204,10 @@
<text class="num">{{settingsInfo.PublishStoryScore}}</text>
能量激励
</view>
<image class="bg" src="{{imageUrl}}3/story-lead1.png?t={{Timestamp}}"></image>
<image class="bg" src="{{imageUrl}}za-images/3/story-lead1.png?t={{Timestamp}}"></image>
</view>
<view class="popup-container">
<image class="bg" src="{{imageUrl}}3/story-lead2.png?t={{Timestamp}}"></image>
<image class="bg" src="{{imageUrl}}za-images/3/story-lead2.png?t={{Timestamp}}"></image>
<view class="container">
<view class="content">
<view>你知道吗?</view>
@ -225,9 +228,9 @@ @@ -225,9 +228,9 @@
</view>
</view>
<view class="popup-story-star" wx:if="{{type == 'storyStar'}}">
<image class="badge" src="{{imageUrl}}3/story-star.png?t={{Timestamp}}"></image>
<image class="badge" src="{{imageUrl}}za-images/3/story-star.png?t={{Timestamp}}"></image>
<view class="popup-container">
<image class="bg" src="{{imageUrl}}3/story-lead2.png?t={{Timestamp}}"></image>
<image class="bg" src="{{imageUrl}}za-images/3/story-lead2.png?t={{Timestamp}}"></image>
<view class="container">
<view class="content">感谢加油!</view>
<view class="sub-content">
@ -244,13 +247,13 @@ @@ -244,13 +247,13 @@
</view>
</view>
<view class="popup-story-share" wx:if="{{type == 'storyShare'}}">
<!-- <image class="badge" src="{{imageUrl}}3/story-share.png?t={{Timestamp}}"></image> -->
<image class="badge" mode="aspectFill" src="{{imageUrl}}3/story-share.png?t={{Timestamp}}"></image>
<!-- <image class="badge" src="{{imageUrl}}za-images/3/story-share.png?t={{Timestamp}}"></image> -->
<image class="badge" mode="aspectFill" src="{{imageUrl}}za-images/3/story-share.png?t={{Timestamp}}"></image>
<view class="popup-container">
<image class="bg" src="{{imageUrl}}3/story-share-bg.png?t={{Timestamp}}"></image>
<image class="bg" src="{{imageUrl}}za-images/3/story-share-bg.png?t={{Timestamp}}"></image>
<view class="container">
<image class="satellite1" src="{{imageUrl}}3/satellite.png?t={{Timestamp}}"></image>
<image class="satellite2" src="{{imageUrl}}3/satellite.png?t={{Timestamp}}"></image>
<image class="satellite1" src="{{imageUrl}}za-images/3/satellite.png?t={{Timestamp}}"></image>
<image class="satellite2" src="{{imageUrl}}za-images/3/satellite.png?t={{Timestamp}}"></image>
<view class="sub-content">
<view>分享您的经验或故事</view>
<view>审核发布后</view>
@ -271,7 +274,11 @@ @@ -271,7 +274,11 @@
<view class="popup-beginner-guide" wx:if="{{type == 'beginnerGuide'}}">
<view class="popup-container">
<view class="container">
<image class="badge" mode="aspectFill" src="{{imageUrl}}3/beginner-guide-badge.png?t={{Timestamp}}"></image>
<image
class="badge"
mode="aspectFill"
src="{{imageUrl}}za-images/3/beginner-guide-badge.png?t={{Timestamp}}"
></image>
<view class="content">
<view>
<text class="name" wx:if="{{params.relationType==1}}">Hi,{{params.patientName}}</text>
@ -292,14 +299,14 @@ @@ -292,14 +299,14 @@
</view>
<view class="popup-adl-alert {{theme === 'DRUG' && 'popup-adl-alert-drug'}}" wx:if="{{type == 'aldAlert'}}">
<view class="popup-container">
<image class="badge" mode="aspectFill" src="{{imageUrl}}1.5/adl-alert.png?t={{Timestamp}}"></image>
<image class="badge" mode="aspectFill" src="{{imageUrl}}za-images/1.5/adl-alert.png?t={{Timestamp}}"></image>
<view class="container">
<view class="content">
<view>自在生活“双达标”测评提醒</view>
</view>
<view class="tip">建议您每次用药7天后做1次“双达标”测评,更好了解身体变化</view>
<!-- <view class="warn" bind:tap="handleAdlQuestion" data-url="/pages/repositoryDetail/index?id={{params.id}}"> -->
<!-- <image class="icon" mode="aspectFill" src="{{imageUrl}}1.5/warn.png?t={{Timestamp}}"></image> -->
<!-- <image class="icon" mode="aspectFill" src="{{imageUrl}}za-images/1.5/warn.png?t={{Timestamp}}"></image> -->
<!-- 什么是双达标? -->
<!-- </view> -->
<view class="c-footer">
@ -314,7 +321,7 @@ @@ -314,7 +321,7 @@
wx:if="{{type == 'aldAlertTest'}}"
>
<view class="popup-container">
<image class="badge" mode="aspectFill" src="{{imageUrl}}1.5/adl-alert-test.png?t={{Timestamp}}"></image>
<image class="badge" mode="aspectFill" src="{{imageUrl}}za-images/1.5/adl-alert-test.png?t={{Timestamp}}"></image>
<view class="container">
<view class="content">
<view>
@ -336,7 +343,7 @@ @@ -336,7 +343,7 @@
<view class="popup-vip" wx:if="{{type == 'vipScan'}}">
<view class="popup-container">
<view class="container">
<image class="badge" mode="aspectFill" src="{{imageUrl}}1.5/vip-toast.png?t={{Timestamp}}"></image>
<image class="badge" mode="aspectFill" src="{{imageUrl}}za-images/1.5/vip-toast.png?t={{Timestamp}}"></image>
<view class="content">
<view>
一步认证成为
@ -345,7 +352,7 @@ @@ -345,7 +352,7 @@
</view>
<view class="tip">
专属服务用户登记
<image class="icon" mode="aspectFill" src="{{imageUrl}}1.5/arrow-right.png?t={{Timestamp}}"></image>
<image class="icon" mode="aspectFill" src="{{imageUrl}}za-images/1.5/arrow-right.png?t={{Timestamp}}"></image>
</view>
<view class="c-footer">
<view class="submit" bind:tap="handleOk">立即认证</view>
@ -355,7 +362,7 @@ @@ -355,7 +362,7 @@
</view>
<view class="popup-task-model {{theme === 'DRUG' && 'popup-task-model-drug'}}" wx:if="{{type == 'taskModel'}}">
<view class="popup-container">
<image class="badge" mode="aspectFill" src="{{imageUrl}}1.5/adl-alert.png?t={{Timestamp}}"></image>
<image class="badge" mode="aspectFill" src="{{imageUrl}}za-images/1.5/adl-alert.png?t={{Timestamp}}"></image>
<view class="container">
<view class="content">
<view>给力加油站电话随访服务启动</view>
@ -365,7 +372,7 @@ @@ -365,7 +372,7 @@
<view>提醒您健康管理</view>
</view>
<view class="warn" bind:tap="routerTo" data-path="/pages/taskAgreement/index?page=/pages/index/index">
<image class="icon" mode="aspectFill" src="{{imageUrl}}1.5/warn.png?t={{Timestamp}}"></image>
<image class="icon" mode="aspectFill" src="{{imageUrl}}za-images/1.5/warn.png?t={{Timestamp}}"></image>
<text class="link">《电话随访知情同意书》</text>
</view>
<view class="c-footer">
@ -377,7 +384,7 @@ @@ -377,7 +384,7 @@
</view>
<view class="popup-health-care {{theme === 'DRUG' && 'popup-health-care-drug'}}" wx:if="{{type == 'healthCare'}}">
<view class="popup-container">
<image class="badge" mode="aspectFill" src="{{imageUrl}}1.5/adl-alert.png?t={{Timestamp}}"></image>
<image class="badge" mode="aspectFill" src="{{imageUrl}}za-images/1.5/adl-alert.png?t={{Timestamp}}"></image>
<view class="container">
<view class="content">
<view>艾加莫德进入医保</view>
@ -396,7 +403,7 @@ @@ -396,7 +403,7 @@
wx:if="{{type == 'ndrlAldAlert'}}"
>
<view class="popup-container">
<image class="badge" mode="aspectFill" src="{{imageUrl}}1.5/adl-alert.png?t={{Timestamp}}"></image>
<image class="badge" mode="aspectFill" src="{{imageUrl}}za-images/1.5/adl-alert.png?t={{Timestamp}}"></image>
<view class="container">
<view class="content">
<view>
@ -405,7 +412,7 @@ @@ -405,7 +412,7 @@
</view>
</view>
<view class="warn" bind:tap="handleAdlQuestion" data-url="/pages/repositoryDetail/index?id={{params.id}}">
<image class="icon" mode="aspectFill" src="{{imageUrl}}1.5/warn.png?t={{Timestamp}}"></image>
<image class="icon" mode="aspectFill" src="{{imageUrl}}za-images/1.5/warn.png?t={{Timestamp}}"></image>
什么是MG-ADL?
</view>
<view class="c-footer">
@ -416,7 +423,11 @@ @@ -416,7 +423,11 @@
</view>
<view class="popup-ndrl-follow" wx:if="{{type == 'popupNdrlFollow'}}">
<view class="popup-container">
<image class="badge" mode="aspectFill" src="{{imageUrl}}nrdl/nrdl-follow-badge.png?t={{Timestamp}}"></image>
<image
class="badge"
mode="aspectFill"
src="{{imageUrl}}za-images/nrdl/nrdl-follow-badge.png?t={{Timestamp}}"
></image>
<view class="container">
<view class="title">提交成功</view>
<view class="price" wx:if="{{params.rewardScore}}">
@ -434,8 +445,11 @@ @@ -434,8 +445,11 @@
</view>
<view class="popup-soory-enter" wx:if="{{type == 'giftEnter'}}">
<view class="popup-container">
<view class="container" style="background-image: url({{imageUrl}}1/popup-soory-enter-bg.png?t={{Timestamp}})">
<image class="badge" src="{{imageUrl}}1/toast-story-badge.png?t={{Timestamp}}"></image>
<view
class="container"
style="background-image: url({{imageUrl}}za-images/1/popup-soory-enter-bg.png?t={{Timestamp}})"
>
<image class="badge" src="{{imageUrl}}za-images/1/toast-story-badge.png?t={{Timestamp}}"></image>
<view class="content">
<mp-html class="mp-html" container-style="overflow: visible" content="{{params.doc}}"></mp-html>
</view>
@ -461,12 +475,12 @@ @@ -461,12 +475,12 @@
<view class="popup-adl-progress {{theme === 'DRUG' && 'popup-adl-progress-drug'}}" wx:if="{{type == 'adlProgresss'}}">
<view
class="popup-container"
style="background-image: url({{imageUrl}}2/progress-bg{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}})"
style="background-image: url({{imageUrl}}za-images/2/progress-bg{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}})"
>
<image
class="close"
bind:tap="handleCancel"
src="{{imageUrl}}2/adl-close{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}}"
src="{{imageUrl}}za-images/2/adl-close{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}}"
></image>
<view class="container">
<view class="title">
@ -491,9 +505,9 @@ @@ -491,9 +505,9 @@
<view class="item {{params.ContinuousTimes >= index +1 && 'active'}}" wx:for="{{5}}" wx:key="{{index}}">
<view class="name">第{{index+1}}周</view>
<view class="el">
<image class="icon" src="{{imageUrl}}2/adl-money.png?t={{Timestamp}}"></image>
<image class="icon" src="{{imageUrl}}za-images/2/adl-money.png?t={{Timestamp}}"></image>
<view class="status">
<image class="mini" src="{{imageUrl}}2/true.png?t={{Timestamp}}"></image>
<image class="mini" src="{{imageUrl}}za-images/2/true.png?t={{Timestamp}}"></image>
</view>
</view>
<view class="num" wx:if="{{params.Records[index]}}">{{params.Records[index].RewardScore}}</view>
@ -523,12 +537,12 @@ @@ -523,12 +537,12 @@
>
<view
class="popup-container"
style="background-image: url({{imageUrl}}2/progress-end-bg{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}})"
style="background-image: url({{imageUrl}}za-images/2/progress-end-bg{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}})"
>
<image
class="close"
bind:tap="handleCancel"
src="{{imageUrl}}2/adl-close{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}}"
src="{{imageUrl}}za-images/2/adl-close{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}}"
></image>
<view class="container">
<view class="title">
@ -547,12 +561,12 @@ @@ -547,12 +561,12 @@
>
<view
class="popup-container"
style="background-image: url({{imageUrl}}2/progress-bg{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}})"
style="background-image: url({{imageUrl}}za-images/2/progress-bg{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}})"
>
<image
class="close"
bind:tap="handleCancel"
src="{{imageUrl}}2/adl-close{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}}"
src="{{imageUrl}}za-images/2/adl-close{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}}"
></image>
<view class="container">
<view class="title">
@ -577,9 +591,9 @@ @@ -577,9 +591,9 @@
<view class="item {{params.ContinuousTimes >= index +1 && 'active'}}" wx:for="{{5}}" wx:key="{{index}}">
<view class="name">第{{index+1}}周</view>
<view class="el">
<image class="icon" src="{{imageUrl}}2/adl-money.png?t={{Timestamp}}"></image>
<image class="icon" src="{{imageUrl}}za-images/2/adl-money.png?t={{Timestamp}}"></image>
<view class="status">
<image class="mini" src="{{imageUrl}}2/true.png?t={{Timestamp}}"></image>
<image class="mini" src="{{imageUrl}}za-images/2/true.png?t={{Timestamp}}"></image>
</view>
</view>
<view class="num" wx:if="{{params.Records[index]}}">{{params.Records[index].RewardScore}}</view>
@ -608,12 +622,12 @@ @@ -608,12 +622,12 @@
>
<view
class="popup-container"
style="background-image: url({{imageUrl}}2/progress-end-bg{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}})"
style="background-image: url({{imageUrl}}za-images/2/progress-end-bg{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}})"
>
<image
class="close"
bind:tap="handleCancel"
src="{{imageUrl}}2/adl-close{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}}"
src="{{imageUrl}}za-images/2/adl-close{{theme === 'DRUG'?'2':'1'}}.png?t={{Timestamp}}"
></image>
<view class="container">
<view class="title">
@ -627,9 +641,16 @@ @@ -627,9 +641,16 @@
</view>
</view>
<view class="popup-dtp-drup" wx:if="{{type == 'dtpDrug'}}">
<view class="popup-container" style="background-image: url({{imageUrl}}nrdl/popup-dtp-bg.png?t={{Timestamp}})">
<view
class="popup-container"
style="background-image: url({{imageUrl}}za-images/nrdl/popup-dtp-bg.png?t={{Timestamp}})"
>
<view class="container">
<image class="title" mode="widthFix" src="{{imageUrl}}nrdl/popup-dtp-title.png?t={{Timestamp}}"></image>
<image
class="title"
mode="widthFix"
src="{{imageUrl}}za-images/nrdl/popup-dtp-title.png?t={{Timestamp}}"
></image>
<view class="content">双通道药店是指可购买医保药品并支持医保支付(报销)的药店</view>
<view class="footer">
<view bind:tap="handleOk" class="submit">已了解</view>
@ -645,7 +666,7 @@ @@ -645,7 +666,7 @@
<image
class="badge"
mode="aspectFill"
src="{{imageUrl}}double-standard/double-standards-badge{{theme === 'DRUG' ? '-drug' :''}}.png?t={{Timestamp}}"
src="{{imageUrl}}za-images/double-standard/double-standards-badge{{theme === 'DRUG' ? '-drug' :''}}.png?t={{Timestamp}}"
></image>
<view class="container">
<view class="content">
@ -665,23 +686,23 @@ @@ -665,23 +686,23 @@
>
<view
class="popup-container"
style="background: url({{imageUrl}}2/popup-dedicated-doctor{{theme === 'DRUG'?'-drug':''}}-bg.png?t={{Timestamp}}) no-repeat top center/100%"
style="background: url({{imageUrl}}za-images/2/popup-dedicated-doctor{{theme === 'DRUG'?'-drug':''}}-bg.png?t={{Timestamp}}) no-repeat top center/100%"
>
<image
class="content"
src="{{imageUrl}}2/popup-dedicated-doctor-content{{theme === 'DRUG'?'-drug':''}}.png?t={{Timestamp}}"
src="{{imageUrl}}za-images/2/popup-dedicated-doctor-content{{theme === 'DRUG'?'-drug':''}}.png?t={{Timestamp}}"
></image>
<view class="btn" bind:tap="handleOk">立即体验</view>
</view>
<image
class="close"
bind:tap="handleCancel"
src="{{imageUrl}}2/close.png?t={{Timestamp}}"
src="{{imageUrl}}za-images/2/close.png?t={{Timestamp}}"
bind:tap="handleCancel"
></image>
</view>
<view class="popup-export-loading-doctor" wx:if="{{type == 'exportLoadingDoctor'}}">
<image class="badge" src="{{imageUrl}}doctor/export.gif?t={{Timestamp}}"></image>
<image class="badge" src="{{imageUrl}}za-images/doctor/export.gif?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="title">正在生成您的ADL报告</view>
<view class="content">导出可能需要一些时间,请您耐心等待</view>
@ -691,21 +712,21 @@ @@ -691,21 +712,21 @@
<view class="popup-referral-toast" wx:if="{{type == 'referral-toast'}}">
<view
class="popup-container"
style="background: url({{imageUrl}}5/referral-toast-bg.png?t={{Timestamp}}) no-repeat top center/100%"
style="background: url({{imageUrl}}za-images/5/referral-toast-bg.png?t={{Timestamp}}) no-repeat top center/100%"
>
<view class="btn" bind:tap="handleOk">确定</view>
</view>
<image
class="close"
bind:tap="handleCancel"
src="{{imageUrl}}2/close.png?t={{Timestamp}}"
src="{{imageUrl}}za-images/2/close.png?t={{Timestamp}}"
bind:tap="handleCancel"
></image>
</view>
<view class="popup-patient-detail-safe-doctor" wx:if="{{type == 'patientDetailSafeDoctor'}}">
<view
class="popup-container"
style="background: url({{imageUrl}}5/safe-bg.png?t={{Timestamp}}) no-repeat top center/100%"
style="background: url({{imageUrl}}za-images/5/safe-bg.png?t={{Timestamp}}) no-repeat top center/100%"
>
<view class="content">
以下内容涉及患者个人信息,仅用于{{params.HospitalName}}{{params.Name}}医生进行患者随访管理,请在安全环境下查看,不截图,不转发
@ -715,26 +736,26 @@ @@ -715,26 +736,26 @@
<image
class="close"
bind:tap="handleCancel"
src="{{imageUrl}}2/close.png?t={{Timestamp}}"
src="{{imageUrl}}za-images/2/close.png?t={{Timestamp}}"
bind:tap="handleCancel"
></image>
</view>
<view class="popup-public-toast" wx:if="{{type == 'public-toast'}}">
<view
class="popup-container"
style="background: url({{imageUrl}}/5/public-bg1.png?t={{Timestamp}}) no-repeat top center/100%"
style="background: url({{imageUrl}}za-images/5/public-bg1.png?t={{Timestamp}}) no-repeat top center/100%"
>
<image class="code" src="{{imageUrl}}5/code.png?t={{Timestamp}}" show-menu-by-longpress></image>
<image class="code" src="{{imageUrl}}za-images/5/code.png?t={{Timestamp}}" show-menu-by-longpress></image>
</view>
<image
class="close"
bind:tap="handleCancel"
src="{{imageUrl}}2/close.png?t={{Timestamp}}"
src="{{imageUrl}}za-images/2/close.png?t={{Timestamp}}"
bind:tap="handleCancel"
></image>
</view>
<view class="popup-site-conform" wx:if="{{type == 'siteConform'}}">
<image class="badge" src="{{imageUrl}}icon4.png?t={{Timestamp}}"></image>
<image class="badge" src="{{imageUrl}}za-images/icon4.png?t={{Timestamp}}"></image>
<view class="popup-container">
<view class="title">您已选择</view>
<view class="content">{{params.ProvinceName}}{{params.CityName ? '—' + params.CityName : ''}}</view>
@ -747,10 +768,10 @@ @@ -747,10 +768,10 @@
<view class="popup-level-up" wx:if="{{type == 'adlLevelUp'}}">
<view
class="popup-container"
style="background: url({{imageUrl}}bg5.png?t={{Timestamp}}) no-repeat top center/100%"
style="background: url({{imageUrl}}za-images/bg5.png?t={{Timestamp}}) no-repeat top center/100%"
>
<image class="close" bind:tap="handleCancel" src="{{imageUrl}}icon15.png?t={{Timestamp}}"></image>
<image class="btn" bind:tap="handleOk" src="{{imageUrl}}icon16.png?t={{Timestamp}}"></image>
<image class="close" bind:tap="handleCancel" src="{{imageUrl}}za-images/icon15.png?t={{Timestamp}}"></image>
<image class="btn" bind:tap="handleOk" src="{{imageUrl}}za-images/icon16.png?t={{Timestamp}}"></image>
</view>
</view>
</van-popup>

61
src/components/viewFile/index.js

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
// components/viewFile/index.js
const app = getApp();
Component({
/**
* 组件的属性列表
*/
properties: {
fileList: {
type: Array,
value: [],
},
// 是否可以删除
canDelete: {
type: Boolean,
value: false,
},
// 是否可以下载
canDownLoad: {
type: Boolean,
value: false,
},
},
/**
* 组件的初始数据
*/
data: {
Timestamp: app.globalData.Timestamp,
imageUrl: app.globalData.imageUrl,
},
/**
* 组件的方法列表
*/
methods: {
deleteFile(e) {
const { index, item } = e.currentTarget.dataset;
this.triggerEvent("deleteFile", {
index,
item,
});
},
viewFile(e) {
const { index } = e.currentTarget.dataset;
const { fileList } = this.properties;
let sources = [];
fileList.map((e) => {
const obj = {
url: e.fileUrl,
type: e.type, // image video
poster: e.imgUrl,
};
sources.push(obj);
});
wx.previewMedia({
current: index,
sources: sources,
});
},
},
});

6
src/components/viewFile/index.json

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

12
src/components/viewFile/index.wxml

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
<!-- components/viewFile/index.wxml -->
<view class="page">
<view class="item mar" wx:for="{{fileList}}" wx:key="index" data-index="{{index}}" catchtap="viewFile">
<image class="image" mode="aspectFill" src="{{item.imgUrl}}"></image>
<view wx:if="{{item.type === 'video'}}" class="item_mask">
<van-icon size="48rpx" color="rgba(0,0,0,0.6)" name="play-circle" class="item_mask_icon" />
</view>
<view wx:if="{{canDelete}}" class="clear" catchtap="deleteFile" data-item="{{item}}" data-index="{{index}}">
<van-icon name="clear" color="rgba(0,0,0,0.6)" size="32rpx" />
</view>
</view>
</view>

48
src/components/viewFile/index.wxss

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
/* components/viewFile/index.wxss */
.page{
display: flex;
flex-wrap: wrap;
}
.item{
width: 144rpx;
height: 144rpx;
position: relative;
}
.item .image{
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.clear{
width: 32rpx;
height: 32rpx;
background: #fff;
position: absolute;
right: -16rpx;
top: -16rpx;
border-radius: 100%;
overflow: hidden;
font-size: 0;
}
.mar{
margin-right: 16rpx;
margin-bottom: 16rpx;
}
.item_mask {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
}
.item_mask_icon {
border-radius: 100%;
overflow: hidden;
background: #fff;
font-size: 0;
}

66
src/components/viewVideo/index.js

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
/* eslint-disable */
const app = getApp();
Component({
behaviors: ["wx://form-field"],
externalClasses: ["my-class"],
properties: {
src: {
type: String,
value: "",
},
poster: {
type: String,
value: "",
},
ViewNum: {
type: Number,
value: "",
},
autoplay: {
type: Boolean,
value: false,
},
},
observers: {
autoplay(val) {
if (val) {
this.setData({
play: true,
});
}
},
},
relations: {},
data: {
Timestamp: app.globalData.Timestamp,
play: false,
imageUrl: app.globalData.imageUrl,
},
lifetimes: {
created() {},
attached() {},
detached() {},
error() {},
},
pageLifetimes: {
show() {},
hide() {},
resize() {},
},
methods: {
hanldePlay() {
console.log(1111111111);
const videoContext = wx.createVideoContext("video", this);
videoContext.play();
this.setData({
play: true,
});
},
handlePause() {
console.log(11111111);
this.setData({
play: false,
});
},
},
});

4
src/components/viewVideo/index.json

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

46
src/components/viewVideo/index.scss

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
.video {
height: 388rpx;
position: relative;
overflow: hidden;
.video-context {
width: 100%;
height: 100%;
}
.play {
position: absolute;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-50%, -50%);
width: 96rpx;
height: 96rpx;
}
.status-bar {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 0 48rpx;
box-sizing: border-box;
height: 78rpx;
display: flex;
align-items: center;
flex-direction: row-reverse;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.02) 0%, #000000 100%);
>view,>image{
margin-right: 32rpx;
};
transition: all 0.8s;
.time {
font-size: 24rpx;
color: #ffffff;
}
.start {
font-size: 24rpx;
color: #ffffff;
}
}
.hide {
transform: translateY(100%);
}
}

21
src/components/viewVideo/index.wxml

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
<view class="video">
<video
class="video-context"
id="video"
controls="{{play}}"
autoplay="{{autoplay}}"
catch:pause="handlePause"
show-center-play-btn="{{false}}"
poster="{{poster}}"
object-fit="cover"
src="{{src}}"
></video>
<image
wx:if="{{!play}}"
class="play"
bind:tap="hanldePlay"
src="{{imageUrl}}za-images/video-play.png?t={{Timestamp}}"
></image>
<view class="status-bar {{play && 'hide'}}">
</view>
</view>

46
src/components/viewVideo/index.wxss

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
.video {
height: 388rpx;
position: relative;
overflow: hidden;
}
.video .video-context {
width: 100%;
height: 100%;
}
.video .play {
position: absolute;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-50%, -50%);
width: 96rpx;
height: 96rpx;
}
.video .status-bar {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 0 48rpx;
box-sizing: border-box;
height: 78rpx;
display: flex;
align-items: center;
flex-direction: row-reverse;
background: linear-gradient(180deg, rgba(0, 0, 0, 0.02) 0%, #000000 100%);
>view,>image{
margin-right: 32rpx;
};
transition: all 0.8s;
}
.video .status-bar .time {
font-size: 24rpx;
color: #ffffff;
}
.video .status-bar .start {
font-size: 24rpx;
color: #ffffff;
}
.video .hide {
transform: translateY(100%);
}

231
src/components/zdUploadFile/index.js

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

8
src/components/zdUploadFile/index.json

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

20
src/components/zdUploadFile/index.wxml

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
<!-- components/uploadFile/index.wxml -->
<view class="page">
<view class="item mar" wx:for="{{fileList}}" wx:key="index" data-index="{{index}}" catchtap="viewFile">
<image class="image" mode="aspectFill" src="{{item.imgUrl}}"></image>
<view wx:if="{{item.type === 'video'}}" class="item_mask">
<van-icon size="48rpx" color="rgba(0,0,0,0.6)" name="play-circle" class="item_mask_icon" />
</view>
<view wx:if="{{canDelete}}" class="clearBox" catchtap="deleteFile" data-item="{{item}}" data-index="{{index}}">
<view class="clear">
<van-icon name="{{imageUrl}}za-images/1/upload-del.png" color="#A09D9D" size="46rpx" />
</view>
</view>
</view>
<view wx:if="{{upload && (maxNum === -1 || maxNum > fileList.length)}}" catchtap="selectFile">
<slot wx:if="{{isSlot}}"></slot>
<view wx:else class="btn mar">
<van-icon name="{{imageUrl}}za-images/1/upload-icon.png" color="#A09D9D" size="60rpx" />
</view>
</view>
</view>

77
src/components/zdUploadFile/index.wxss

@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
/* components/uploadFile/index.wxss */
.page {
display: flex;
flex-wrap: wrap;
}
.btn {
width: 180rpx;
height: 180rpx;
background: #fff;
border-radius: 12rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #F8F8F8;
}
.btn .text {
color: #9E9999;
font-size: 24rpx;
line-height: 34prx;
margin-top: 16rpx;
}
.item {
width: 180rpx;
height: 180rpx;
position: relative;
line-height: 0;
}
.item .image {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.clearBox {
position: absolute;
right: -22rpx;
top: -28rpx;
padding: 10rpx;
z-index: 9;
}
.clear {
width: 100%;
height: 100%;
background: #fff;
border-radius: 100%;
overflow: hidden;
font-size: 0;
}
.mar {
margin-right: 18rpx;
margin-bottom: 26rpx;
}
.item_mask {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
}
.item_mask_icon {
border-radius: 100%;
overflow: hidden;
background: #fff;
font-size: 0;
}

25
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 @@ @@ -0,0 +1,6 @@
{
"navigationBarTitleText": "确认订单",
"usingComponents": {
"van-icon": "@vant/weapp/icon/index"
}
}

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

@ -0,0 +1,184 @@ @@ -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 @@ @@ -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 @@ @@ -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>

4
src/gift/pages/cutaneous/index.json

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
{
"navigationBarTitleText": "皮下剂型",
"usingComponents": {}
}

63
src/gift/pages/cutaneous/index.scss

@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
page {
background-color: #f7f6f7;
}
.page {
.page1 {
height: 869rpx;
}
.page2 {
position: relative;
height: 630rpx;
.mg-video {
position: absolute;
top: 290rpx;
right: 60rpx;
width: 600rpx;
height: 288rpx;
}
}
.page3 {
position: relative;
height: 782rpx;
.cidp-mask {
position: absolute;
top: 174rpx;
right: 30rpx;
z-index: 1;
width: 74rpx;
height: 304rpx;
}
.cidp-list {
position: absolute;
top: 184rpx;
right: 30rpx;
width: 632rpx;
height: 288rpx;
overflow-x: auto;
overflow-y: hidden;
display: flex;
gap: 16rpx;
.cidp-item {
flex-shrink: 0;
width: 216rpx;
height: 288rpx;
}
}
}
.page4 {
height: 302rpx;
}
.page5 {
height: 306rpx;
}
.page6 {
display: block;
width: 100%;
height: 574rpx;
}
}
#video {
width: 0;
height: 0;
}

65
src/gift/pages/cutaneous/index.ts

@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
const _app = getApp<IAppOption>()
Page({
data: {
mg: [
{
url: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241129469_MG%E4%B8%93%E5%8C%BA%E8%A7%86%E9%A2%9101.mp4',
},
],
cidp: [
{
url: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241129233_CIDP%E4%B8%93%E5%8C%BA%E8%A7%86%E9%A2%9101.mp4',
},
{
url: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241129667_CIDP%E4%B8%93%E5%8C%BA%E8%A7%86%E9%A2%9103.mp4',
},
{
url: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241129630_CIDP%E8%A7%86%E9%A2%91%E4%B8%93%E5%8C%BA02.mp4',
},
{
url: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241129281_CIDP%E4%B8%93%E5%8C%BA%E8%A7%86%E9%A2%9104.mp4',
},
],
},
videoContext: null as WechatMiniprogram.VideoContext | null,
onLoad() {
this.videoContext = wx.createVideoContext('video')
},
onUnload() {
if (this.videoContext) {
this.videoContext.stop()
}
},
handleVideo(e: any) {
const { key, index } = e.currentTarget.dataset
const url = this.data[key][index].url
if (this.videoContext) {
this.setData({
videoUrl: url,
})
this.videoContext.play()
this.videoContext.requestFullScreen({
direction: 0,
})
}
},
handleFullScreen(e) {
if (!e.detail.fullScreen && this.videoContext) {
this.videoContext.stop()
}
},
handleDetail(e: any) {
const { id } = e.currentTarget.dataset
wx.navigateTo({
url: `/gift/pages/cutaneousDetail/index?id=${id}`,
})
},
handleVideoDetail() {
wx.navigateTo({
url: `/gift/pages/cutaneousVideo/index`,
})
},
})
export {}

82
src/gift/pages/cutaneous/index.wxml

@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
<view class="page">
<view
class="page1"
style="background: url({{imageUrl}}/cutaneous/home1.png?t={{Timestamp}}) no-repeat top center/100%;"
></view>
<view
class="page2"
style="background: url({{imageUrl}}/cutaneous/home2.png?t={{Timestamp}}) no-repeat top center/100%;"
bind:tap="handleDetail"
data-id="2"
>
<image
class="mg-video"
src="{{imageUrl}}/cutaneous/video1-1.png?t={{Timestamp}}"
data-key="mg"
data-index="0"
catch:tap="handleVideo"
></image>
</view>
<view
class="page3"
style="background: url({{imageUrl}}/cutaneous/home3.png?t={{Timestamp}}) no-repeat top center/100%;"
bind:tap="handleDetail"
data-id="3"
>
<image class="cidp-mask" src="{{imageUrl}}/cutaneous/cidp-mask.png?t={{Timestamp}}"></image>
<view class="cidp-list">
<image
class="cidp-item"
src="{{imageUrl}}/cutaneous/video2-1.png?t={{Timestamp}}"
data-key="cidp"
data-index="0"
catch:tap="handleVideo"
></image>
<image
class="cidp-item"
src="{{imageUrl}}/cutaneous/video2-2.png?t={{Timestamp}}"
data-key="cidp"
data-index="1"
catch:tap="handleVideo"
></image>
<image
class="cidp-item"
src="{{imageUrl}}/cutaneous/video2-3.png?t={{Timestamp}}"
data-key="cidp"
data-index="2"
catch:tap="handleVideo"
></image>
<image
class="cidp-item"
src="{{imageUrl}}/cutaneous/video2-4.png?t={{Timestamp}}"
data-key="cidp"
data-index="3"
catch:tap="handleVideo"
></image>
</view>
</view>
<view
class="page4"
style="background: url({{imageUrl}}/cutaneous/home4.png?t={{Timestamp}}) no-repeat top center/100%;"
bind:tap="handleDetail"
data-id="4"
></view>
<view
class="page5"
style="background: url({{imageUrl}}/cutaneous/home5.png?t={{Timestamp}}) no-repeat top center/100%;"
bind:tap="handleDetail"
data-id="5"
></view>
<image class="page6" bind:tap="handleVideoDetail" src="{{imageUrl}}/cutaneous/home6.png?t={{Timestamp}}"></image>
</view>
<video
id="video"
src="{{videoUrl}}"
loop
show-play-btn
play-btn-position="center"
enable-play-gesture
bindfullscreenchange="handleFullScreen"
></video>

4
src/gift/pages/cutaneousDetail/index.json

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
{
"navigationBarTitleText": "皮下剂型",
"usingComponents": {}
}

11
src/gift/pages/cutaneousDetail/index.scss

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
.page {
.card {
width: 100%;
display: block;
}
}
#video {
width: 0;
height: 0;
}

26
src/gift/pages/cutaneousDetail/index.ts

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
const _app = getApp<IAppOption>()
Page({
data: {
list: {
2: ['2-1', '2-2', '2-3', '2-4'],
3: ['3-1', '3-2', '3-3', '3-4', '3-5'],
4: ['4-1', '4-2'],
5: ['5-1', '5-2', '5-3', '5-4', '5-5'],
},
curentList: [] as any,
},
onLoad(e) {
if (e.id) {
this.setData({
curentList: this.data.list[e.id],
})
} else {
this.setData({
curentList: this.data.list[2],
})
}
},
})
export {}

9
src/gift/pages/cutaneousDetail/index.wxml

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
<view class="page">
<image
class="card"
mode="widthFix"
wx:for="{{curentList}}"
wx:key="index"
src="{{imageUrl}}/cutaneous/{{item}}.png?t={{Timestamp}}"
></image>
</view>

4
src/gift/pages/cutaneousVideo/index.json

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
{
"navigationBarTitleText": "皮下剂型",
"usingComponents": {}
}

36
src/gift/pages/cutaneousVideo/index.scss

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
page {
background: linear-gradient(218deg, #e8bbe7 0%, #ffedf6 26%, #ffedf6 100%);
}
.page {
padding: 408rpx 40rpx 0;
.container {
padding: 40rpx 32rpx 42rpx;
background-color: #fff;
border-radius: 32rpx;
.content {
font-size: 32rpx;
line-height: 2;
color: #002b48;
}
.tip {
margin-top: 28rpx;
font-size: 32rpx;
color: rgba(87,87,87,0.5);
}
}
.btn {
margin-top: 42rpx;
height: 92rpx;
font-size: 32rpx;
color: #FFFFFF;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(90deg, #dd406a 0%, #9039b0 100%);
border-radius: 112rpx 112rpx 112rpx 112rpx;
}
}
#video {
width: 0;
height: 0;
}

29
src/gift/pages/cutaneousVideo/index.ts

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
Page({
data: {
videoUrl: 'https://circlehbsaas.oss-cn-beijing.aliyuncs.com/video/20241214185_1.mp4',
},
videoContext: null as WechatMiniprogram.VideoContext | null,
onLoad() {
this.videoContext = wx.createVideoContext('video')
},
onUnload() {
if (this.videoContext) {
this.videoContext.stop()
}
},
handleVideo() {
if (this.videoContext) {
this.videoContext.play()
this.videoContext.requestFullScreen({
direction: 0,
})
}
},
handleFullScreen(e) {
if (!e.detail.fullScreen && this.videoContext) {
this.videoContext.stop()
}
},
})
export {}

16
src/gift/pages/cutaneousVideo/index.wxml

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
<view
class="page"
style="background: url({{imageUrl}}cutaneous/video-bg.png?t={{Timestamp}}) no-repeat 0 60rpx/100% 648rpx;"
>
<view class="container">
<view class="content">
本视频仅用于专业医护人员或艾加莫德a注射液(皮下注射)已处方患者(或其护理者)在接受充分的皮下注射技术培训后自行注射艾加莫德a注射液(皮下注射);
本指导视频并不构成专业医疗建议、诊断或治疗的依据,请按照说明书并遵医嘱使用,切勿仅依赖本视频内容。
</view>
<view class="tip">*在观看视频前请阅读声明并确认您的身份</view>
</view>
<view class="btn btn1" bind:tap="handleVideo">我是专业医护人员</view>
<view class="btn btn2" bind:tap="handleVideo">我是卫力迦已处方患者(或其护理者)</view>
</view>
<video id="video" src="{{videoUrl}}" loop show-play-btn play-btn-position="center" enable-play-gesture bindfullscreenchange="handleFullScreen"></video>

4
src/gift/pages/dtpDurg/index.json

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
{
"navigationBarTitleText": "双通道药房",
"usingComponents": {}
}

128
src/gift/pages/dtpDurg/index.scss

@ -0,0 +1,128 @@ @@ -0,0 +1,128 @@
.page {
position: relative;
.banner {
width: 100%;
min-height: 344rpx;
}
.container {
padding: 48rpx 40rpx;
position: absolute;
top: 316rpx;
left: 0;
width: 100%;
min-height: 100vh;
border-radius: 24rpx 24rpx 0 0;
background-color: #fafafa;
box-sizing: border-box;
.title {
font-size: 36rpx;
color: #484848;
font-weight: bold;
}
.tags {
margin-top: 16rpx;
display: flex;
.tag {
margin-right: 16rpx;
padding-right: 8rpx;
font-size: 22rpx;
color: #e04775;
line-height: 1;
border-radius: 8rpx;
background-color: #f5dfe6;
display: flex;
align-items: center;
.icon {
margin-right: 8rpx;
padding: 4rpx;
width: 24rpx;
max-height: 24rpx;
background-color: #e04775;
border-radius: 8rpx;
}
}
}
.content {
margin-top: 32rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
.inner {
.site {
font-size: 28rpx;
color: #9e9e9e;
}
.tel {
font-size: 28rpx;
color: #9b9ea6;
}
}
.options {
flex-shrink: 0;
display: flex;
.option {
margin-left: 30rpx;
.phone {
width: 48rpx;
height: 48rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background-color: #fff;
box-shadow: 0 4rpx 20rpx 0 rgba(0, 0, 0, 0.1);
&-img {
width: 24rpx;
height: 24rpx;
}
}
.name {
margin-top: 8rpx;
font-size: 24rpx;
color: #484848;
}
}
}
}
.card {
margin-bottom: 16rpx;
padding: 32rpx 30rpx;
border-radius: 24rpx;
background-color: #fff;
.c-title {
font-size: 32rpx;
font-weight: bold;
color: #484848;
display: flex;
align-items: center;
.c-icon {
margin-right: 16rpx;
width: 36rpx;
height: 36rpx;
}
}
.c-content{
margin-top: 24rpx;
font-size: 28rpx;
color: #9E9E9E;
}
}
.remark{
padding: 32rpx;
border-radius: 24rpx;
background-color: #fff;
.r-title{
font-size: 32rpx;
color: #484848;
font-weight: bold;
}
.r-content{
margin-top: 20rpx;
font-size: 28rpx;
color: #9E9E9E;
}
}
}
}

52
src/gift/pages/dtpDurg/index.ts

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
const app = getApp<IAppOption>();
Page({
data: {
id: "",
detail: {} as any,
},
onLoad(options) {
this.setData({
id: options.id,
});
app.waitLogin().then(() => {
this.getDetail();
});
},
getDetail() {
wx.ajax({
method: "GET",
url: "?r=zd/dtp-pharmacy/detail",
data: {
Id: this.data.id,
},
}).then((res) => {
this.setData({
detail: res,
});
});
},
handleSite() {
const { LNG, LAT, ProvinceName, CityName, CountyName, Address, Name } = this.data.detail;
wx.openLocation({
latitude: LAT,
longitude: LNG,
name: Name,
address: `${ProvinceName}${CityName}${CountyName}${Address}`,
});
},
handlePhone() {
const tel = this.data.detail.Telephone;
if (!tel) {
wx.showToast({
icon: "none",
title: "电话暂未开通",
});
return;
}
wx.makePhoneCall({
phoneNumber: tel,
});
},
});

61
src/gift/pages/dtpDurg/index.wxml

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
<view class="page">
<image wx:if="{{detail.ImgUrl}}" class="banner" mode="widthFix" src="{{detail.ImgUrl}}"></image>
<image wx:else class="banner" mode="widthFix" src="{{imageUrl}}/nrdl/dtp-durg.png"></image>
<view class="container">
<view class="title">{{detail.Name}}</view>
<view class="tags">
<view class="tag" wx:if="{{detail.IsOwnInfusionCenter==1}}">
<image class="icon" mode="widthFix" src="{{imageUrl}}/nrdl/inject.png"></image>
<!-- {{detail.OwnInfusionCenterName}} -->
自有输注中心
</view>
<view class="tag" wx:if="{{detail.IsCooperationInfusionCenter==1}}">
<image class="icon" mode="widthFix" src="{{imageUrl}}/nrdl/cooperate.png"></image>
<!-- {{detail.CooperationInfusionCenterName}} -->
合作输注中心
</view>
</view>
<view class="content">
<view class="inner">
<view class="site">{{detail.ProvinceName}}{{detail.CityName}}{{detail.CountyName}}{{detail.Address}}</view>
<view class="tel">{{detail.Telephone}}</view>
</view>
<view class="options">
<view class="option" bind:tap="handleSite" wx:if="{{detail.Address}}">
<view class="phone">
<image class="phone-img" src="{{imageUrl}}/nrdl/site.png"></image>
</view>
<view class="name">地址</view>
</view>
<view class="option" bind:tap="handlePhone">
<view class="phone">
<image class="phone-img" src="{{imageUrl}}/nrdl/phone.png"></image>
</view>
<view class="name">电话</view>
</view>
</view>
</view>
<view class="card" wx:if="{{detail.IsOwnInfusionCenter==1}}">
<view class="c-title">
<image
class="c-icon"
src="{{imageUrl}}/nrdl/cooperate-1.png"
style="width: 32rpx; height: 30rpx; margin-right: 18rpx"
></image>
自有输注中心
</view>
<view class="c-content">{{detail.OwnInfusionCenterName}}</view>
</view>
<view class="card" wx:if="{{detail.IsCooperationInfusionCenter==1}}">
<view class="c-title">
<image class="c-icon" src="{{imageUrl}}/nrdl/inject-1.png" style="width: 36rpx; height: 36rpx"></image>
合作输注中心
</view>
<view class="c-content">{{detail.CooperationInfusionCenterName}}</view>
</view>
<view class="remark" wx:if="{{detail.Remark}}">
<view class="r-title">备注</view>
<view class="r-content">{{detail.Remark}}</view>
</view>
</view>
</view>

7
src/gift/pages/giftDetail/index.json

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
{
"navigationBarTitleText": "礼品详情",
"usingComponents": {
"van-stepper": "@vant/weapp/stepper/index",
"toast": "/components/toast/index"
}
}

185
src/gift/pages/giftDetail/index.scss

@ -0,0 +1,185 @@ @@ -0,0 +1,185 @@
.page {
background-color: #f9f9f9;
padding-bottom: 400rpx;
.banner {
width: 100%;
.banner-img {
display: block;
width: 100%;
height: 562rpx;
}
}
.container {
padding: 30rpx 40rpx;
.price {
display: flex;
align-items: baseline;
.num {
font-size: 56rpx;
color: #e04775;
font-weight: bold;
}
.sub {
font-size: 32rpx;
color: #e04775;
}
}
.title {
margin-top: 22rpx;
font-size: 36rpx;
color: #3f3f3f;
line-height: 48rpx;
font-weight: bold;
}
.list {
margin-top: 24rpx;
padding: 32rpx;
background: #ffffff;
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05);
border-radius: 24rpx;
.list-title {
padding-bottom: 16rpx;
position: relative;
font-size: 36rpx;
color: #3f3f3f;
font-weight: bold;
&::before {
content: "";
position: absolute;
top: 0;
left: -32rpx;
width: 12rpx;
height: 44rpx;
background: #e04775;
border-radius: 0rpx 8rpx 8rpx 0rpx;
}
}
.list-img {
display: block;
width: 100%;
}
}
}
.footer {
padding: 30rpx 40rpx 40rpx;
position: fixed;
bottom: 0;
left: 0;
width: 100vw;
box-sizing: border-box;
background: #ffffff;
box-shadow: 0rpx 8rpx 20rpx 0rpx rgba(0, 0, 0, 0.26);
.options {
padding-bottom: 25rpx;
.row {
display: flex;
align-items: center;
.label {
margin-right: 24rpx;
flex-shrink: 0;
font-size: 32rpx;
color: #b6b7ba;
}
.radios {
display: flex;
overflow: auto;
&::-webkit-scrollbar {
display: none;
}
.radio {
margin-right: 16rpx;
border-radius: 8rpx;
border: 1px solid #d0d0d0;
line-height: 40rpx;
padding: 0 20rpx;
font-size: 28rpx;
color: #aaaaaa;
white-space: nowrap;
&.active {
background-color: #e04775;
border-color: #e04775;
color: #fff;
}
}
}
.stepper {
display: flex;
align-items: center;
.custom-class {
border: 1px solid #e5e5e5;
border-radius: 8rpx;
}
.input-class {
color: #3f3f3f;
font-weight: bold;
background-color: #ffffff;
margin: 0;
}
.plus-class,
.minus-class {
margin: 0;
background-color: #f8f8f8;
}
.minus-class {
border-right: 1px solid #d7d7d7;
}
.plus-class {
border-left: 1px solid #d7d7d7;
}
.status {
margin-left: 8rpx;
font-size: 32rpx;
color: #e1e1e1;
}
}
}
.row:not(:first-of-type) {
margin-top: 24rpx;
}
}
.module {
border-top: 1px solid #f2f2f2;
padding-top: 25rpx;
display: flex;
align-items: center;
justify-content: space-between;
.wrap {
.price {
display: flex;
align-items: baseline;
.sub {
font-size: 28rpx;
color: #e04775;
}
.num {
font-size: 40rpx;
color: #e04775;
font-weight: bold;
}
}
.doc {
display: flex;
align-items: center;
font-size: 24rpx;
color: #999999;
.checkbox {
transform: scale(0.7);
}
.a {
color: #e04775;
}
}
}
.submit {
width: 298rpx;
height: 96rpx;
background: #e04775;
border-radius: 48rpx;
font-size: 36rpx;
color: #ffffff;
line-height: 96rpx;
text-align: center;
}
}
}
}

150
src/gift/pages/giftDetail/index.ts

@ -0,0 +1,150 @@ @@ -0,0 +1,150 @@
const app = getApp<IAppOption>();
Page({
data: {
id: "",
detail: {},
specVecItem: {} as any,
num: 1,
allPrice: "",
toastShow: false,
toastType: "giftEnter",
toastParams: {
doc: "",
},
protocol: false,
},
onLoad(options) {
this.setData({
id: options.id,
toastParams: {
doc: `<p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">为让用户更好的享受再鼎gMG给力加油站的服务,gMG给力加油站平台向用户提供了能量兑换服务,并提供了丰富的礼品,平台注册用户可使用有效的能量兑换礼品。</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">gMG给力加油站的礼品库将提供:</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">1) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">查看用户在能量商城选择兑换的商品信息;</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">2) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">确认兑换商品的订单信息;</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">3) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">实施兑换商品的物流配送服务。</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">基于以上服务内容,我们在此特别声明:</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">gMG给力加油站非常重视用户个人信息保护,我们制定了详细的<a style="color:#00A4ED" href="/pages/privacyAgreement/index?page=/gift/pages/giftDetail/index&id=${options.id}">《知情同意书》</a></span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">,我们将按照公示的政策及相关法律法规的要求,对您的个人信息予以保护。为了完整的向您提供能量的商品兑换服务,gMG给力加油站将需要您提供用户真实姓名、手机号、地址信息,以便完成您所兑换商品的物流配送。其中,当用户准备对兑换商品进行结算时,平台会生成兑换该商品的订单,同时该订单中会载明订单号、所兑换的商品或服务信息、应支付的能量值。以上所有信息构成用户的“订单信息”,平台将使用订单信息来进行用户的身份核验、确定交易、支付结算、完成配送。</span></p><p style="text-indent: 24pt; line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">用户点击本协议的"同意"按钮即视为完全接受以上声明条款,在点击之前请用户再次确认已知悉并完全理解声明的全部内容。</span></p>`,
// doc:` <p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">为让用户更好的享受再鼎gMG给力加油站的服务,gMG给力加油站平台向用户提供了能量兑换服务,并提供了丰富的礼品,平台注册用户可使用有效的能量兑换礼品。</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">gMG给力加油站的礼品库将提供:</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">1) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">查看用户在能量商城选择兑换的商品信息;</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">2) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">确认兑换商品的订单信息;</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 微软雅黑;">3) </span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">实施兑换商品的物流配送服务。</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">基于以上服务内容,我们在此特别声明:</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">gMG给力加油站非常重视用户个人信息保护,我们制定了详细的<a style="color:#00A4ED" href="/pages/privacyAgreement/index?page=/gift/pages/giftDetail/index&id=${options.id}">《知情同意书》</a></span><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">,我们将按照公示的政策及相关法律法规的要求,对您的个人信息予以保护。为了完整的向您提供能量的商品兑换服务,gMG给力加油站将需要您提供用户真实姓名、手机号、地址信息,以便完成您所兑换商品的物流配送。其中,当用户准备对兑换商品进行结算时,平台会生成兑换该商品的订单,同时该订单中会载明订单号、所兑换的商品或服务信息、应支付的能量值。以上所有信息构成用户的“订单信息”,平台将使用订单信息来进行用户的身份核验、确定交易、支付结算、完成配送。</span></p><p style="line-height: 1.5;"><span style="color: rgb(89, 89, 89); font-size: 14px; font-family: 宋体;">用户点击本协议的"同意"按钮即视为完全接受以上声明条款,在点击之前请用户再次确认已知悉并完全理解声明的全部内容。</span></p>`
},
});
app.waitLogin().then(() => {
this.setView();
this.getDetail();
this.getProtocol();
});
},
setView() {
wx.ajax({
method: "POST",
url: "?r=zd/gift-spu/set-visit-num",
data: { spuId: this.data.id },
showMsg: false,
});
},
getDetail() {
wx.ajax({
method: "GET",
url: "?r=zd/gift-spu/get-detail",
data: {
spuId: this.data.id,
},
}).then((res) => {
this.setData({
detail: {
...res,
detailList: JSON.parse(res.detail),
},
specVecItem: res.specVec[0],
allPrice: res.specVec[0].score,
num: res.specVec[0].stock >= 1 ? 1 : 0,
});
});
},
getProtocol() {
wx.ajax({
method: "GET",
url: "?r=zd/agreement/get-user-agreement",
data: {},
}).then((res) => {
this.setData({
protocol: res,
});
});
},
setProtocol() {
wx.ajax({
method: "POST",
url: "?r=zd/agreement/set-user-agreement",
data: {},
});
},
handleSpec(e: any) {
const { index } = e.currentTarget.dataset;
const specVecItem: any = this.data.detail.specVec[index];
console.log(specVecItem.stock>=1)
this.setData({
specVecItem: specVecItem,
allPrice: specVecItem.score,
num: specVecItem.stock >= 1 ? 1 : 0,
});
},
onChangeNumber(e: any) {
this.setData({
num: e.detail,
allPrice: this.data.specVecItem.score * e.detail,
});
},
handleDoc() {
this.setData({
toastShow: true,
toastType: "giftEnter",
});
},
handleToastOk(e) {
if (!e.detail.protocol) {
wx.showToast({
title: "请先勾选《用户须知》",
icon: "none",
});
return;
}
this.setProtocol();
this.setData({
protocol: e.detail.protocol,
});
this.handleToastCancel();
},
handleToastCancel() {
this.setData({
toastShow: false,
toastType: "",
});
},
handleProtocol() {
if (!this.data.protocol) {
this.setProtocol();
}
this.setData({
protocol: !this.data.protocol,
});
},
handleSubmit() {
if (!this.data.protocol) {
wx.showToast({
icon: "none",
title: "请先同意《用户须知》",
});
return;
}
wx.ajax({
method: "POST",
url: "?r=zd/gift-order/place-order",
data: {
giftId: this.data.specVecItem.giftId,
count: this.data.num,
},
loading: true,
}).then((res) => {
wx.navigateTo({
url: `/gift/pages/conformOrder/index?id=${res}`,
});
});
},
});

80
src/gift/pages/giftDetail/index.wxml

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
<view class="page">
<view class="banner">
<image class="banner-img" mode="aspectFill" src="{{detail.bigImg}}"></image>
</view>
<view class="container">
<view class="price">
<view class="num">{{specVecItem.score}}</view>
<view class="sub">能量</view>
</view>
<view class="title">{{detail.giftName}}</view>
<view class="list">
<view class="list-title">礼品详情</view>
<image class="list-img" mode="widthFix" wx:for="{{detail.detailList}}" wx:key="index" src="{{item.url}}"></image>
</view>
</view>
<view class="footer">
<view class="options">
<view class="row" wx:if="{{detail.specVec.length > 0 && detail.specVec[0].specName}}">
<view class="label">规格</view>
<view class="radios">
<view
class="radio {{specVecItem.giftId==item.giftId && 'active'}}"
wx:for="{{detail.specVec}}"
wx:key="index"
data-index="{{index}}"
bind:tap="handleSpec"
>
{{item.specName }}
</view>
</view>
</view>
<view class="row">
<view class="label">数量</view>
<view class="stepper">
<van-stepper
custom-class="custom-class"
value="{{ num }}"
min="{{0}}"
input-width="{{48}}"
input-class="input-class"
plus-class="plus-class"
minus-class="minus-class"
integer
disable-input
bind:change="onChangeNumber"
disable-plus="{{num>=specVecItem.stock}}"
/>
<view class="status" wx:if="{{num<=specVecItem.stock && specVecItem.stock>0 }}">有库存</view>
<view class="status" wx:else>无库存</view>
</view>
</view>
</view>
<view class="module">
<view class="wrap">
<view class="price">
<view class="sub">
合计
<text decode="true">&nbsp;</text>
</view>
<view class="num">{{allPrice}}</view>
</view>
<view class="doc">
<checkbox class="checkbox" checked="{{protocol}}" color="#DB3E6A" bind:tap="handleProtocol"></checkbox>
已阅读
<view class="a" bind:tap="handleDoc">《用户须知》</view>
</view>
</view>
<view class="submit" bind:tap="handleSubmit">立即兑换</view>
</view>
</view>
</view>
<toast
show="{{toastShow}}"
type="{{toastType}}"
params="{{toastParams}}"
bind:ok="handleToastOk"
bind:cancel="handleToastCancel"
></toast>

8
src/gift/pages/giftList/index.json

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
{
"navigationBarTitleText": "礼品中心",
"navigationStyle": "custom",
"usingComponents": {
"van-icon": "@vant/weapp/icon/index",
"navBar": "/components/zd-navBar/navBar"
}
}

185
src/gift/pages/giftList/index.scss

@ -0,0 +1,185 @@ @@ -0,0 +1,185 @@
page {
background-color: #f9f9f9;
}
.page {
.bg {
width: 100%;
height: 902rpx;
}
.page-container {
position: absolute;
left: 0;
top: 0;
width: 100%;
padding: 0 40rpx;
box-sizing: border-box;
padding-bottom: 200rpx;
.notice {
height: 44rpx;
background: linear-gradient(90deg, rgba(241, 241, 241, 0) 0%, #f1f1f1 52%, rgba(241, 241, 241, 0) 100%);
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 24rpx;
color: #3f3f3f;
.icon {
margin-right: 5rpx;
width: 30rpx;
height: 24rpx;
}
}
.banner {
margin-top: 16rpx;
background: #fafafa;
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05);
border-radius: 24rpx;
border: 2rpx solid rgba(151, 151, 151, 0.14);
.banner-header {
padding: 32rpx 0 32rpx 32rpx;
display: flex;
background: #ffffff;
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05);
border-radius: 24rpx;
border-bottom: 2rpx solid rgba(151, 151, 151, 0.14);
display: flex;
.user {
width: 106rpx;
height: 106rpx;
border-radius: 50%;
}
.wrap {
flex: 1;
padding: 0 150rpx 0 22rpx;
.title {
font-size: 24rpx;
color: #3f3f3f;
}
.price {
font-size: 48rpx;
color: #3f3f3f;
font-weight: bold;
}
}
.rule {
font-size: 24rpx;
color: #ffffff;
width: 136rpx;
height: 44rpx;
background: #f5ab1f;
border-radius: 24rpx 0 0 24rpx;
text-align: center;
line-height: 44rpx;
font-weight: bold;
}
}
.banner-footer {
padding: 20rpx 0 28rpx;
display: flex;
justify-content: space-between;
align-items: center;
.ver-line {
width: 2rpx;
height: 40rpx;
background-color: rgba(221, 221, 221, 0.6);
}
.option {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
font-size: 28rpx;
color: #484848;
font-weight: bold;
.icon {
margin-right: 22rpx;
width: 50rpx;
height: 50rpx;
}
}
}
}
.list {
margin-top: 48rpx;
.list-title {
margin-bottom: 20rpx;
width: 180rpx;
height: 40rpx;
}
.list-cate {
padding: 20rpx 0;
display: flex;
flex-wrap: nowrap;
max-width: 100vw;
box-sizing: border-box;
overflow-x: auto;
&::-webkit-scrollbar {
display: none;
}
.cate {
margin-right: 20rpx;
padding: 10rpx 24rpx;
white-space: nowrap;
line-height: 1;
font-size: 28rpx;
color: #484848;
background-color: #f2f2f2;
border-radius: 24rpx;
&.active {
color: #fff;
background-color: #e04775;
}
}
}
.list-container {
display: flex;
flex-wrap: wrap;
gap: 16rpx 22rpx;
.list-item {
margin-bottom: 16rpx;
width: 324rpx;
background: #ffffff;
box-shadow: 0rpx 4rpx 20rpx 0rpx rgba(0, 0, 0, 0.05);
border-radius: 24rpx;
.photo {
border-radius: 24rpx 24rpx 0 0;
width: 100%;
height: 324rpx;
}
.content {
padding: 18rpx 20rpx 22rpx;
.title {
margin-top: 18rpx;
font-size: 32rpx;
color: #484848;
font-weight: bold;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.footer {
margin-top: 6rpx;
display: flex;
justify-content: space-between;
.price {
font-size: 28rpx;
color: #e04775;
}
.btn {
width: 100rpx;
height: 44rpx;
text-align: center;
line-height: 44rpx;
font-size: 24rpx;
color: #ffffff;
background: #e04775;
border-radius: 24rpx;
font-weight: bold;
}
}
}
}
}
}
}
}

114
src/gift/pages/giftList/index.ts

@ -0,0 +1,114 @@ @@ -0,0 +1,114 @@
const app = getApp<IAppOption>();
Page({
data: {
bottom: 0,
selfScore: {
expire: {},
},
cateList: [],
cateId: "",
list: [],
pagination: {
page: 1,
pages: 1,
count: 1,
},
},
onLoad() {
const SystemInfo = app.globalSystemInfo;
if (SystemInfo) {
const { bottom } = SystemInfo.capsulePosition;
this.setData({
bottom: bottom,
});
}
app.waitLogin().then(() => {
app.getZdUserInfo(this, true);
this.getScore();
this.getList();
this.getCateList();
});
},
getScore() {
wx.ajax({
method: "GET",
url: "?r=zd/patient-score/get-self-score",
data: {},
}).then((res) => {
this.setData({
selfScore: res,
});
});
},
getCateList() {
wx.ajax({
method: "GET",
url: "?r=zd/gift-spu/get-cate-all-list",
data: {},
}).then((res) => {
this.setData({
cateList: res,
});
});
},
handleCate(e) {
const { id } = e.currentTarget.dataset;
this.setData({
cateId: id,
});
this.getList();
},
getList(newPage = 1) {
wx.ajax({
method: "POST",
url: `?r=zd/gift-spu/get-list&page=${newPage}`,
data: {
cateId: this.data.cateId ? [this.data.cateId] : [],
},
}).then((res) => {
let list = res.page == 1 ? res.list : [...this.data.list, ...res.list];
this.setData({
list: list,
pagination: {
page: res.page,
pages: res.pages,
count: res.count,
},
});
});
},
handlePirceDetail() {
wx.navigateTo({
url: "/gift/pages/priceDetail/index",
});
},
handleMyGift() {
wx.navigateTo({
url: "/gift/pages/myGift/index",
});
},
handleDetail(e) {
const { id } = e.currentTarget.dataset;
wx.navigateTo({
url: `/gift/pages/giftDetail/index?id=${id}`,
});
},
handleRule() {
wx.navigateTo({
url: `/gift/pages/scoreRule/index`,
});
},
handleBack() {
wx.reLaunch({
url: "/pages/my/index",
});
},
onReachBottom() {
const { page, pages } = this.data.pagination;
if (pages > page) {
this.getList(page + 1);
}
},
});

51
src/gift/pages/giftList/index.wxml

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
<view class="page">
<navBar color="#222222" background="{{background}}" fixed title="礼品中心" back bind:back="handleBack"></navBar>
<image class="bg" src="{{imageUrl}}1/my-bg.png?t={{Timestamp}}"></image>
<view class="page-container" style="padding-top:{{bottom+26}}px">
<view class="notice" wx:if="{{selfScore.expire.expireStatus==1}}">
<image class="icon" src="{{imageUrl}}2/notice.png?t={{Timestamp}}"></image>
你有{{selfScore.expire.expireScore}}能量将于7月1日过期
</view>
<view class="banner">
<view class="banner-header">
<image class="user" src="{{zdUserInfo.UserImg}}"></image>
<view class="wrap">
<view class="title">我的能量</view>
<view class="price">{{selfScore.score}}</view>
</view>
<view class="rule" bind:tap="handleRule">能量规则</view>
</view>
<view class="banner-footer">
<view class="option" bind:tap="handlePirceDetail">
<image class="icon" style="width:52rpx;height: 50rpx;" src="{{imageUrl}}2/money.png?t={{Timestamp}}"></image>
能量明细
</view>
<view class="ver-line"></view>
<view class="option" bind:tap="handleMyGift">
<image class="icon" style="width:48rpx;height: 54rpx;" src="{{imageUrl}}2/gift.png?t={{Timestamp}}"></image>
我的礼品
</view>
</view>
</view>
<view class="list">
<image class="list-title" src="{{imageUrl}}2/gift-list-title.png?t={{Timestamp}}"></image>
<view class="list-cate">
<view class="cate {{!cateId && 'active'}}" data-id="" bind:tap="handleCate">全部</view>
<view class="cate {{cateId == item.cateId && 'active'}}" wx:for="{{cateList}}" wx:key="cateId" data-id="{{item.cateId}}" bind:tap="handleCate">{{item.cateName}}</view>
</view>
<view class="list-container">
<view class="list-item" wx:for="{{list}}" wx:key="index" data-id="{{item.spuId}}" bind:tap="handleDetail">
<image class="photo" src="{{item.bigImg}}"></image>
<view class="content">
<view class="title">{{item.giftName}}</view>
<view class="footer">
<view class="price">{{item.lowestScore}}能量</view>
<view class="btn">兑换</view>
</view>
</view>
</view>
</view>
<pagination pagination="{{pagination}}"></pagination>
</view>
</view>
</view>

4
src/gift/pages/myGift/index.json

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
{
"navigationBarTitleText": "我的礼品",
"usingComponents": {}
}

110
src/gift/pages/myGift/index.scss

@ -0,0 +1,110 @@ @@ -0,0 +1,110 @@
page {
background-color: #f7f7f7;
}
.page {
padding: 32rpx 40rpx;
.card {
margin-bottom: 16rpx;
padding: 32rpx;
background: #ffffff;
border-radius: 24rpx;
.header {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 32rpx;
border-bottom: 1px solid #ebebeb;
.on {
font-size: 28rpx;
color: #bbbcbe;
}
.status {
font-size: 28rpx;
color: #e04775;
}
.suc {
color: #24d8c8;
}
}
.shop {
padding: 32rpx 0;
display: flex;
align-items: center;
.shop-img {
flex-shrink: 0;
width: 200rpx;
height: 200rpx;
border-radius: 24rpx;
}
.wrap {
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 {
display: inline-block;
margin-top: 8rpx;
font-size: 28rpx;
color: #b6b7ba;
border-radius: 10rpx;
}
.price {
margin-top: 14rpx;
display: flex;
align-items: center;
justify-content: space-between;
.num {
font-size: 32rpx;
color: #e04775;
font-weight: bold;
.sub {
font-size: 22rpx;
}
}
.val {
font-size: 28rpx;
color: #b6b7ba;
}
}
}
}
.footer {
border-top: 1px solid #ebebeb;
padding-top: 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
.content {
font-size: 28rpx;
color: #bbbcbe;
display: flex;
align-items: baseline;
.num {
font-size: 42rpx;
color: #e04775;
font-weight: bold;
}
}
.btn {
width: 152rpx;
height: 52rpx;
border-radius: 8rpx;
border: 1rpx solid rgba(158, 158, 158, 0.42);
font-size: 28rpx;
color: #3f3f3f;
text-align: center;
line-height: 52rpx;
}
}
}
}

48
src/gift/pages/myGift/index.ts

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
const app = getApp<IAppOption>();
Page({
data: {
list: [],
pagination: {
page: 1,
pages: 1,
count: 1,
},
},
onLoad() {
app.waitLogin().then(() => {
this.getList();
});
},
getList(newPage = 1) {
wx.ajax({
method: "POST",
url: "?r=zd/gift-order/get-order-list",
data: {
page: newPage,
},
}).then((res) => {
let list = res.page == 1 ? res.list : [...this.data.list, ...res.list];
this.setData({
list: list,
pagination: {
page: res.page,
pages: res.pages,
count: res.count,
},
});
});
},
handleDetail(e: any) {
const { id } = e.currentTarget.dataset;
wx.navigateTo({
url: `/gift/pages/orderDetail/index?id=${id}`,
});
},
onReachBottom() {
const { page, pages } = this.data.pagination;
if (pages > page) {
this.getList(page + 1);
}
},
});

28
src/gift/pages/myGift/index.wxml

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
<view class="page">
<view class="card" wx:for="{{list}}" wx:key="index" bind:tap="handleDetail" data-id="{{item.orderId}}">
<view class="header">
<view class="on">订单号:{{item.orderNo}}</view>
<view class="status" wx:if="{{item.status==2}}">{{item.statusName}}</view>
<view class="status suc" wx:else>{{item.statusName}}</view>
</view>
<view class="shop">
<image class="shop-img" src="{{item.giftBigImg}}"></image>
<view class="wrap">
<view class="name">{{item.giftName}}</view>
<view class="specification" wx:if="{{item.specName}}">规格:{{item.specName}}</view>
<view class="price">
<view class="num">{{item.giftScore}}<text class="sub">能量</text></view>
<view class="val">x{{item.orderCount}}</view>
</view>
</view>
</view>
<view class="footer">
<view class="content">
共{{item.orderCount}}件 消耗能量:
<view class="num">{{item.orderScore}}</view>
</view>
<view class="btn" wx:if="{{item.status==3}}">查看物流</view>
</view>
</view>
<pagination pagination="{{pagination}}"></pagination>
</view>

11
src/gift/pages/myHealthRecord/index.json

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
{
"navigationBarTitleText": "我的健康记录",
"navigationStyle": "custom",
"usingComponents": {
"navBar": "/components/zd-navBar/navBar",
"van-icon": "@vant/weapp/icon/index",
"calendar": "/components/calendar/index",
"toast": "/components/toast/index",
"ec-canvas": "/components/ec-canvas/ec-canvas"
}
}

741
src/gift/pages/myHealthRecord/index.scss

@ -0,0 +1,741 @@ @@ -0,0 +1,741 @@
page {
background-color: rgba(250, 250, 250, 1);
min-height: 100vh;
padding-bottom: 200rpx;
}
.page {
padding: 0 40rpx 33rpx;
.calendar-wrap {
height: 80rpx;
overflow: hidden;
transition: all 0.5s;
.calendar {
margin: 0;
}
.legend {
margin-top: 30rpx;
display: flex;
> view:not(:last-of-type),
> image {
margin-right: 38rpx;
}
justify-content: flex-end;
.item {
display: flex;
align-items: center;
> view:not(:last-of-type),
> image {
margin-right: 11rpx;
}
font-size: 24rpx;
color: rgba(79, 79, 79, 1);
&::before {
margin-right: 10rpx;
content: "";
width: 16rpx;
height: 16rpx;
border-radius: 50%;
}
}
.drugs {
.icon {
width: 17rpx;
height: 24rpx;
}
font-size: 24rpx;
color: rgba(79, 79, 79, 1);
}
.item1 {
&::before {
background-color: rgba(207, 83, 117, 1);
}
}
.item2 {
&::before {
background-color: rgba(37, 217, 200, 1);
}
}
}
&.expend {
height: 600rpx;
}
}
.p-fold {
padding: 20rpx;
text-align: center;
}
.chart {
margin-top: 34rpx;
.c-header {
display: flex;
justify-content: space-between;
align-items: center;
.title {
font-size: 32rpx;
color: rgba(71, 71, 71, 1);
font-weight: bold;
}
.more {
font-size: 24rpx;
color: rgba(204, 204, 204, 1);
}
}
.c-container {
margin-top: 24rpx;
background-color: #fff;
border-radius: 24rpx;
border: 1rpx solid rgba(0, 0, 0, 0.1);
.c-header {
display: flex;
justify-content: space-between;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
.c-nav {
overflow: hidden;
flex: 1;
display: flex;
.nav-item {
padding: 16rpx 0;
width: 80rpx;
text-align: center;
line-height: 42rpx;
font-size: 24rpx;
color: #666666;
font-weight: bold;
&.active {
position: relative;
color: #cf5375;
&::after {
position: absolute;
bottom: 0;
left: -5rpx;
content: "";
width: 90rpx;
height: 4rpx;
background: #cf5375;
}
}
}
}
.fill {
margin-right: 40rpx;
width: 24rpx;
height: 24rpx;
}
}
.c-content {
padding: 16rpx 0;
.search-num {
padding: 0 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
.col {
display: flex;
align-items: center;
.input {
font-size: 24rpx;
color: #666666;
border: 1px solid #ccc;
padding-left: 1em;
border-radius: 12rpx;
}
.btn {
margin-left: 20rpx;
padding: 4rpx 10rpx;
font-size: 24rpx;
color: #fff;
border-radius: 12rpx;
background-color: #e04775;
}
}
.all {
font-size: 24rpx;
color: rgba(79, 79, 79, 1);
}
}
.search {
padding: 0 36rpx 16rpx;
display: flex;
justify-content: space-between;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
.date {
display: flex;
align-items: center;
font-size: 24rpx;
color: #666666;
.line {
margin: 0 10rpx;
}
.icon {
transform: rotate(90deg);
color: #666666;
}
}
.result {
font-size: 24rpx;
color: #666666;
display: flex;
align-items: center;
.icon {
margin-right: 9rpx;
width: 26rpx;
height: 30rpx;
}
.question {
width: 24rpx;
height: 24rpx;
}
}
}
.wrap {
padding: 0 36rpx;
.w-header {
padding-top: 32rpx;
display: flex;
justify-content: space-between;
.title {
font-size: 32rpx;
color: #484848;
}
.legend {
display: flex;
align-items: center;
gap: 25rpx;
.item {
font-size: 20rpx;
color: #4f4f4f;
display: flex;
align-items: center;
.logo {
margin-right: 8rpx;
width: 16rpx;
height: 16rpx;
border-radius: 50%;
background-color: #cf5375;
&.hormone {
background-color: #3192A1;
}
}
.icon {
margin-right: 8rpx;
width: 17rpx;
height: 24rpx;
}
}
}
}
.unit {
font-size: 22rpx;
color: #ccc;
margin-bottom: -40rpx;
}
.w-chart {
position: relative;
padding-top: 20rpx;
height: 500rpx;
.touch {
position: absolute;
z-index: 100;
width: 100%;
height: 250rpx;
}
.left {
position: absolute;
top: 180rpx;
left: -65rpx;
width: 56rpx;
height: 56rpx;
background: #ffffff;
box-shadow: 0rpx 6rpx 28rpx 0rpx rgba(0, 0, 0, 0.18);
border: 1rpx solid #e8e8e8;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
.icon {
width: 18rpx;
height: 28rpx;
}
}
.right {
position: absolute;
top: 180rpx;
right: -65rpx;
width: 56rpx;
height: 56rpx;
background: #ffffff;
box-shadow: 0rpx 6rpx 28rpx 0rpx rgba(0, 0, 0, 0.18);
border: 1rpx solid #e8e8e8;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
.icon {
width: 18rpx;
height: 28rpx;
}
}
}
}
.share {
padding: 40rpx 0 10rpx;
font-size: 24rpx;
color: #e04775;
display: flex;
justify-content: center;
align-items: center;
.icon {
margin-right: 8rpx;
width: 22rpx;
height: 22rpx;
}
}
}
}
}
.banner {
margin: 36rpx 0 0;
padding: 20rpx;
border-radius: 24rpx;
background-color: #e04775;
display: flex;
align-items: center;
justify-content: space-between;
.inner {
flex: 1;
font-size: 28rpx;
color: #fafafa;
}
.btn {
flex-shrink: 0;
width: 152rpx;
height: 64rpx;
text-align: center;
line-height: 64rpx;
font-size: 28rpx;
color: #e04775;
background: #ffffff;
border-radius: 12rpx;
}
}
.tabs {
margin-top: 36rpx;
display: inline-flex;
background-color: #fff;
box-shadow: 0rpx 8rpx 32rpx 0rpx rgba(0, 0, 0, 0.13);
border-radius: 12rpx;
overflow: hidden;
.tab {
padding: 10rpx 20rpx;
line-height: 40rpx;
font-size: 28rpx;
color: #666666;
background-color: #fff;
&.active {
background-color: #e04775;
color: #fff;
}
&:nth-of-type(2) {
border: 1px solid #dddddd;
border-top: none;
border-bottom: none;
}
}
}
.detail {
margin-top: 34rpx;
.d-header {
display: flex;
justify-content: space-between;
align-items: center;
.title {
font-size: 32rpx;
color: rgba(71, 71, 71, 1);
font-weight: bold;
}
.more {
font-size: 24rpx;
color: rgba(204, 204, 204, 1);
}
}
.module {
margin-top: 30rpx;
.module-header {
display: flex;
.date {
flex-shrink: 0;
font-size: 24rpx;
color: #333333;
}
.tags {
margin-left: 14rpx;
flex: 1;
display: flex;
flex-wrap: nowrap;
overflow-x: scroll;
white-space: nowrap;
&::-webkit-scrollbar {
display: none;
}
.tag1 {
margin-left: 14rpx;
padding: 0 12rpx;
background: #d86687;
border-radius: 6rpx;
font-size: 24rpx;
line-height: 36rpx;
text-align: center;
color: #ffffff;
}
.tag2 {
margin-left: 14rpx;
padding: 0 12rpx;
background: #0b184f;
border-radius: 6rpx;
font-size: 24rpx;
line-height: 36rpx;
text-align: center;
color: #ffffff;
}
.tag3 {
margin-left: 14rpx;
padding: 0 12rpx;
background: #24d8c8;
border-radius: 6rpx;
font-size: 24rpx;
line-height: 36rpx;
text-align: center;
color: #ffffff;
}
}
}
.module-container {
margin-top: 24rpx;
display: flex;
.aside {
margin-right: 30rpx;
padding-left: 14rpx;
border-right: 1px dashed #dddddd;
}
.card {
flex: 1;
box-shadow: 0 4rpx 29rpx 0rpx rgba(207, 83, 116, 0.25);
border-radius: 24rpx;
.card-header {
padding: 20rpx 18rpx 4rpx 48rpx;
border-radius: 24rpx 24rpx 0 0;
display: flex;
align-items: center;
justify-content: space-between;
box-shadow: 8rpx 8rpx 16rpx 0rpx rgba(143, 217, 226, 0.1);
&.grade1 {
background: linear-gradient(90deg, #26dac9 7%, rgba(143, 217, 226, 0) 70%, rgba(143, 217, 226, 0) 100%);
}
&.grade2 {
background: linear-gradient(
90deg,
rgba(235, 111, 87, 1) 7%,
rgba(143, 217, 226, 0) 70%,
rgba(143, 217, 226, 0) 100%
);
}
&.grade3 {
background: linear-gradient(
90deg,
rgba(207, 83, 117, 1) 7%,
rgba(143, 217, 226, 0) 70%,
rgba(143, 217, 226, 0) 100%
);
}
.num {
display: flex;
align-items: baseline;
font-size: 96rpx;
line-height: 1;
color: #ffffff;
letter-spacing: 4rpx;
.sub {
font-size: 24rpx;
color: #fff;
}
}
.num-detail {
display: flex;
.n-item {
width: 73rpx;
&.active {
.box {
background-color: #cf5375;
}
}
.box {
width: 45rpx;
height: 45rpx;
width: 45rpx;
height: 45rpx;
font-size: 32rpx;
color: #fff;
text-align: center;
line-height: 45rpx;
background: #333333;
border-radius: 12rpx 12rpx 12rpx 12rpx;
}
.name {
font-size: 24rpx;
line-height: 48rpx;
color: rgba(51, 51, 51, 0.5);
}
}
}
.status {
font-size: 24rpx;
color: #989898;
text-align: right;
.s-num {
font-size: 32rpx;
}
.s-core {
font-size: 24rpx;
color: #989898;
// background: #484848;
border-radius: 6rpx;
}
}
}
.card-container {
padding: 8rpx 23rpx 20rpx;
border-radius: 0 0 24rpx 24rpx;
background-color: #fff;
.cc-title {
text-indent: 22rpx;
font-size: 24rpx;
color: rgba(79, 79, 79, 1);
}
.cc-content {
margin-top: 12rpx;
padding: 16rpx 20rpx;
border-radius: 24rpx;
background-color: rgba(249, 249, 249, 1);
.line {
font-size: 24rpx;
color: #666666;
line-height: 36rpx;
.dot {
color: #666666;
font-weight: bold;
}
.red {
color: #cf5375;
}
.green {
color: #25d9c8;
}
}
}
.fold {
margin-top: 16rpx;
.fold-header {
display: flex;
justify-content: flex-end;
font-size: 24rpx;
color: rgba(204, 204, 204, 1);
}
.fold-container {
padding-top: 10rpx;
height: 500rpx;
overflow: hidden;
transition: all 0.5s;
&.hide {
padding: 0;
height: 0;
}
.fold-img {
width: 100%;
}
.scurt {
width: 100%;
border: 1px solid rgba(0, 0, 0, 0.1);
box-sizing: border-box;
.s-header {
display: flex;
height: 40rpx;
margin-bottom: -1px;
border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
.none {
flex-shrink: 0;
width: 226rpx;
background-color: rgba(228, 228, 228, 1);
}
.bar {
flex: 1;
display: flex;
.num {
flex: 1;
text-align: center;
font-size: 24rpx;
color: #fff;
line-height: 40rpx;
}
}
}
.s-body {
display: flex;
.s-aside {
width: 28rpx;
background-color: rgba(102, 102, 102, 0.15);
flex-shrink: 0;
.sa-item {
display: flex;
text-align: center;
justify-content: center;
align-items: center;
font-size: 18rpx;
color: rgba(102, 102, 102, 1);
line-height: 1;
overflow: hidden;
&:not(:last-of-type) {
margin-bottom: -1px;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
}
.sa-item1 {
height: 158rpx;
}
.sa-item2 {
height: 54rpx;
}
.sa-item3 {
height: 106rpx;
}
.sa-item4 {
height: 108rpx;
}
}
.s-container {
flex: 1;
.sc-row {
display: flex;
height: 54rpx;
overflow: hidden;
.sc-title {
width: 198rpx;
font-size: 18rpx;
color: rgba(102, 102, 102, 1);
text-align: center;
line-height: 53rpx;
}
.sc-col {
margin-left: -1px;
border-left: 1px solid rgba(0, 0, 0, 0.1);
flex: 1;
text-align: center;
.icon {
margin-top: 11rpx;
width: 32rpx;
height: 32rpx;
}
}
}
.sc-row:not(:last-of-type) {
margin-bottom: -1px;
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}
.sc-row:nth-of-type(2n-1) {
background-color: rgba(217, 217, 217, 0.2);
}
}
}
}
}
}
}
}
.sub-card {
flex: 1;
padding: 14rpx 24rpx 14rpx 48rpx;
display: flex;
align-items: center;
justify-content: space-between;
background: linear-gradient(110deg, #2280d5 0%, #ffffff 60%, #ffffff 100%);
box-shadow: 0 4rpx 29rpx 0rpx rgba(207, 83, 116, 0.25);
border-radius: 24rpx;
.left {
font-size: 96rpx;
color: #fff;
line-height: 1;
.sub {
font-size: 24rpx;
}
}
.inner {
text-align: right;
.i-title {
font-size: 24rpx;
color: #989898;
.num {
font-size: 32rpx;
}
}
.sign {
font-size: 32rpx;
.num {
font-size: 40rpx;
}
}
.i-content {
font-size: 24rpx;
color: #989898;
}
}
}
.drug-card {
margin-top: 30rpx;
flex: 1;
box-shadow: 0 4rpx 29rpx 0rpx rgba(207, 83, 116, 0.25);
border-radius: 24rpx;
.d-header {
border-radius: 24rpx 0 0 0;
padding: 20rpx 50rpx;
display: flex;
align-items: center;
justify-content: space-between;
background: linear-gradient(95deg, #26dac9 7%, rgba(143, 217, 226, 0) 100%);
.name {
font-size: 28rpx;
color: #ffffff;
}
.status {
font-size: 22rpx;
color: #5b6363;
.num {
font-size: 22rpx;
color: #cf5375;
}
}
}
.content {
padding: 20rpx 50rpx;
font-size: 22rpx;
color: #666666;
}
}
}
}
}
.add {
position: fixed;
left: 50%;
bottom: 45rpx;
transform: translateX(-50%);
width: 152rpx;
height: 152rpx;
z-index: 10000;
}
}

1091
src/gift/pages/myHealthRecord/index.ts

File diff suppressed because it is too large Load Diff

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

Loading…
Cancel
Save