first commit

This commit is contained in:
well 2026-03-27 10:41:46 +08:00
commit 1230ba322a
1696 changed files with 94393 additions and 0 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"git.ignoreLimitWarning": true
}

28
app.js Normal file
View File

@ -0,0 +1,28 @@
// app.js
App({
onLaunch() {
},
globalData: {
userInfo: null,
usersaveinfo: null,
baseimgurl: 'https://ndnd.duiduiedu.com/',
// baseimgurl:'http://127.0.0.1:8081',
// baseUrl: 'http://127.0.0.1:8006/addons/unishop',
baseUrl: 'https://ndnd.duiduiedu.com/addons/unishop',
wxopenid: '',
session_key: '',
currentuserinfo: null,
wxuserid: 1,
picspaht: 'https://ndnd.duiduiedu.com/uploads/pics'
},
islogin: function () {
const userinfo = wx.getStorageSync('userinfo');
if (userinfo == null || userinfo.length == 0) {
wx.redirectTo({
url: '/pages/userlogin/userlogin',
})
}
}
})

140
app.json Normal file
View File

@ -0,0 +1,140 @@
{
"pages": [
"pages/index/index",
"pages/indexlives/indexlives",
"pages/leftright/leftright",
"pages/mine/mine",
"pages/tarbar/tarbar",
"pages/grid/grid",
"pages/picsdisplay/picsdisplay",
"pages/swipecell/swipecell",
"pages/main/main",
"pages/livelist/livelist",
"pages/courselearning/courselearning",
"pages/messageencyclopedias/messageencyclopedias",
"pages/messagelist/messagelist",
"pages/communityinfo/communityinfo",
"pages/allpapers/allpapers",
"pages/examlist/examlist",
"pages/caogaozhi/caogaozhi",
"pages/examing/examing",
"pages/singledouble/singledouble",
"pages/exampaper/exampaper",
"pages/exampaper2/exampaper2",
"pages/examanalysis/examanalysis",
"pages/explainnote/explainnote",
"pages/exammakings/exammakings",
"pages/examproblem/examproblem",
"pages/userlogin/userlogin",
"pages/communitylist/communitylist",
"pages/communityitemlist/communityitemlist",
"pages/viprecharge/viprecharge",
"pages/vipquanyi/vipquanyi",
"pages/chargeshop/chargeshop",
"pages/goodsinfo/goodsinfo",
"pages/collectionsub/collectionsub",
"pages/collectioncourse/collectioncourse",
"pages/myaddress/myaddress",
"pages/myorder/myorder",
"pages/livetest/livetest",
"pages/mycommunityinfo/mycommunityinfo",
"pages/myexamanalysis/myexamanalysis",
"pages/newtest/newtest",
"pages/vipmonth/vipmonth",
"pages/createwords/createwords",
"pages/communityinfocomment/communityinfocomment",
"pages/knowledge/knowledge",
"pages/daitika/daitika",
"pages/newmine/newmine",
"pages/indexcourselearning/indexcourselearning",
"pages/indexreslists/indexreslists",
"pages/indexrespage/indexrespage",
"pages/indexlivesvoid/indexlivesvoid",
"pages/indexsq/indexsq",
"pages/indexclass/indexclass",
"pages/indexclassintro/indexclassintro",
"pages/indexclasszx/indexclasszx",
"pages/indexjobtask/indexjobtask",
"pages/indexcreatewords/indexcreatewords",
"pages/indexclassres/indexclassres",
"pages/mytest/mytest",
"pages/indexclasssubwork/indexclasssubwork",
"pages/indexcreatewordssubwork/indexcreatewordssubwork",
"pages/indexobjectivework/indexobjectivework",
"pages/indexobjectactivelist/indexobjectactivelist",
"pages/indexobjectactiveworkok/indexobjectactiveworkok",
"pages/indexreslistsnew/indexreslistsnew",
"pages/classindex/classindex",
"pages/classcommunityitemlist/classcommunityitemlist",
"pages/classcourselearning/classcourselearning",
"pages/camp_list/index",
"pages/camp_detail/index",
"pages/camp_task_text_image/index",
"pages/camp_task_subjective_question/index",
"pages/camp_task_essay_question/index",
"pages/camp_task_objective_questions/index",
"pages/camp_task_objective_questions_result/index"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "Weixin",
"navigationBarTextStyle": "black"
},
"usingComponents": {
"van-button": "@vant/weapp/button/index",
"van-tab": "@vant/weapp/tab/index",
"van-tabs": "@vant/weapp/tabs/index",
"van-cell": "@vant/weapp/cell/index",
"van-cell-group": "@vant/weapp/cell-group/index",
"van-tabbar": "@vant/weapp/tabbar/index",
"van-tabbar-item": "@vant/weapp/tabbar-item/index",
"van-grid": "@vant/weapp/grid/index",
"van-grid-item": "@vant/weapp/grid-item/index",
"van-image": "@vant/weapp/image/index",
"van-swipe-cell": "@vant/weapp/swipe-cell/index",
"van-divider": "@vant/weapp/divider/index",
"van-progress": "@vant/weapp/progress/index",
"van-count-down": "@vant/weapp/count-down/index",
"van-circle": "@vant/weapp/circle/index",
"van-dialog": "@vant/weapp/dialog/index",
"van-overlay": "@vant/weapp/overlay/index",
"van-field": "@vant/weapp/field/index",
"van-switch": "@vant/weapp/switch/index",
"van-dropdown-menu": "@vant/weapp/dropdown-menu/index",
"van-dropdown-item": "@vant/weapp/dropdown-item/index",
"van-popup": "@vant/weapp/popup/index",
"van-action-sheet": "@vant/weapp/action-sheet/index",
"van-toast": "@vant/weapp/toast/index",
"van-calendar": "@vant/weapp/calendar/index",
"calendar": "/components/calendar/calendar",
"van-checkbox": "@vant/weapp/checkbox/index",
"van-checkbox-group": "@vant/weapp/checkbox-group/index",
"pause-mask": "/components/pause-mask/index"
},
"sitemapLocation": "sitemap.json",
"tabBar": {
"color": "#66666",
"selectedColor": "#f10b2e",
"list": [
{
"pagePath": "pages/index/index",
"text": "怼学习",
"iconPath": "./img/footerpic.png",
"selectedIconPath": "./img/footerpic1.png"
},
{
"pagePath": "pages/indexsq/indexsq",
"text": "怼社区",
"iconPath": "./img/footerpic.png",
"selectedIconPath": "./img/footerpic2.png"
},
{
"pagePath": "pages/mine/mine",
"text": "怼自己",
"iconPath": "./img/footerpic.png",
"selectedIconPath": "./img/footerpic3.png"
}
]
}
}

11
app.wxss Normal file
View File

@ -0,0 +1,11 @@
@import './miniprogram_npm/@vant/weapp/common/index.wxss';
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content:space-between;
padding: 20rpx 10rpx;
box-sizing: border-box;
overflow-x: hidden !important;
}

BIN
assets/icons/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
assets/icons/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
assets/icons/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
assets/icons/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

BIN
assets/icons/courses.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

BIN
assets/icons/default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
assets/icons/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
assets/icons/play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
assets/icons/unlock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
assets/images/背景.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

View File

@ -0,0 +1,149 @@
// components/calendar/calendar.js
const dayjs = require("./dayjs")
Component({
/**
* 组件的属性列表
*/
properties: {
//底下需要展示小圆点的日期数组
spot: {
type: Array,
value: []
},
//组件渲染时默认选中的时间
defaultDate: {
type: String,
optionalTypes: [Date, Number],
value: ''
}
},
/**
* 组件的初始数据
*/
data: {
dateList: [], //日历主体渲染数组
selectDay: {}, //选中时间
open: true, //日历是否展开
transform: 0 //收起时日历高度偏移倍数
},
/**
* 组件的方法列表
*/
methods: {
//picker设置月份
editMonth(e) {
const arr = e.detail.value.split("-")
this.setDate(parseInt(arr[0]), parseInt(arr[1]) - 1)
},
//上月切换按钮点击
lastMonth() {
const lastMonth = dayjs(new Date(this.data.selectDay.year, this.data.selectDay.month - 1))
this.setDate(lastMonth.year(), lastMonth.month())
},
//下月切换按钮点击
nextMonth() {
const nextMonth = dayjs(new Date(this.data.selectDay.year, this.data.selectDay.month + 1))
this.setDate(nextMonth.year(), nextMonth.month())
},
//设置选中日期
setDate(paramYear, paramMonth, paramDate) {
const date = Math.min(dayjs(`${paramYear}-${paramMonth + 1}`).daysInMonth(), this.data.selectDay.date)
const time = dayjs(`${paramYear}-${paramMonth + 1}-${paramDate || date}`)
const selectDay = {
year: paramYear,
month: paramMonth,
date: paramDate || date,
dateString: time.format("YYYY-MM-DD"),
}
//设置收起时的日历主体偏移量
let dateListStart = dayjs(`${paramYear}-${paramMonth + 1}`).day(0)
this.setData({
transform: dayjs(`${paramYear}-${paramMonth + 1}-${paramDate || date}`).day(0).diff(dateListStart, 'week')
})
if (paramYear !== this.data.selectDay.year) {
this.setData({
selectDay,
open: true
})
this.dateListInit(paramYear, paramMonth)
this.triggerEvent("dateChange", this.data.selectDay)
this.triggerEvent("monthChange", this.data.selectDay)
this.triggerEvent("yearChange", this.data.selectDay)
return
}
if (paramMonth !== this.data.selectDay.month) {
this.setData({
selectDay,
open: true
})
this.dateListInit(paramYear, paramMonth)
this.triggerEvent("dateChange", this.data.selectDay)
this.triggerEvent("monthChange", this.data.selectDay)
return
}
if (paramDate && paramDate !== this.data.selectDay.date) {
this.setData({
selectDay
})
this.triggerEvent("dateChange", this.data.selectDay)
}
},
//展开收起
openChange() {
this.setData({
open: !this.data.open
})
},
//日历主体的渲染方法
dateListInit(paramYear = this.data.selectDay.year, paramMonth = this.data.selectDay.month) {
let dateList = []; //需要遍历的日历数组数据
let startDate = dayjs(`${paramYear}-${paramMonth + 1}`).day(0) //日历渲染开始日期
let endDate = dayjs(`${paramYear}-${paramMonth + 1}`).endOf('month').day(6) //日历主体渲染结束日期
const timeArr = this.data.spot.map(item => {
return dayjs(item).format('YYYY-MM-DD')
}) //底部小圆点需要展示的数组
while (startDate < endDate) {
const dateString = startDate.format("YYYY-MM-DD")
dateList.push({
date: startDate.date(),
month: startDate.month(),
year: startDate.year(),
dateString,
spot: timeArr.indexOf(dateString) !== -1
})
startDate = startDate.add(1, 'day')
}
this.setData({
dateList: dateList
})
},
//某一天被点击时
selectChange(e) {
const year = e.currentTarget.dataset.year
const month = e.currentTarget.dataset.month
const date = e.currentTarget.dataset.date
this.setDate(year, month, date)
}
},
//组件生命周期
lifetimes: {
attached() {
let now = this.data.defaultDate ? dayjs(this.data.defaultDate) : dayjs()
this.setDate(now.year(), now.month(), now.date())
}
},
//监听参数变化
observers: {
spot: function (spot) {
console.log("==========")
console.log(spot);
this.dateListInit()
}
}
})

View File

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

View File

@ -0,0 +1,38 @@
<!--components/calendar/calendar.wxml-->
<view class="calendar">
<view class="title flex">
<view class="flex">
<picker value="{{selectDay.year+'-'+(selectDay.month+1)}}" bindchange="editMonth" mode="date" fields="month" class="year-month">{{selectDay.year}}.{{selectDay.month>8?selectDay.month+1:"0"+(selectDay.month+1)}}</picker>
<view class="last-icon" bindtap="lastMonth"> </view>
<view class="next-icon" bindtap="nextMonth"> </view>
</view>
<view catchtap="openChange" class="flex open">
<view>{{open?"收起":"展开"}}</view>
</view>
</view>
<!-- 日历头部 -->
<view class="flex-around calendar-week">
<view class="view">日</view>
<view class="view">一</view>
<view class="view">二</view>
<view class="view">三</view>
<view class="view">四</view>
<view class="view">五</view>
<view class="view">六</view>
</view>
<!-- 日历主体 -->
<view class="calendar-main">
<view class="date-group" style="height:{{open? dateList.length/7*72 : 72}}rpx;">
<view class="flex-start flex-wrap date-transform" style="transform: translateY({{open?0:-72*transform}}rpx);">
<view wx:for="{{dateList}}" wx:key="dateList" class="day">
<view class="bg {{(item.year === selectDay.year && item.month === selectDay.month) ?'': 'other-month'}} {{item.dateString === selectDay.dateString?'select':''}}" catchtap="selectChange" data-date="{{item.date}}" data-year="{{item.year}}" data-month="{{item.month}}" data-date-string="{{item.dateString}}">
{{item.date}}
</view>
<view class="spot" wx:if="{{item.spot}}"></view>
</view>
</view>
</view>
</view>
</view>

View File

@ -0,0 +1,157 @@
/* components/calendar/calendar.wxss */
.flex {
display: flex;
justify-content: space-between;
align-items: center;
}
.flex-start {
display: flex;
justify-content: flex-start;
align-items: center;
}
.flex-center {
display: flex;
justify-content: center;
align-items: center;
}
.flex-end {
display: flex;
justify-content: flex-end;
align-items: center;
}
.flex-around {
display: flex;
justify-content: space-around;
align-items: center;
}
.flex1 {
flex: 1;
}
.flex-wrap {
flex-wrap: wrap;
}
.align-start {
align-items: flex-start;
}
.align-end {
align-items: flex-end;
}
.align-stretch {
align-items: stretch;
}
.calendar {
background-color: #fff;
}
.calendar .title {
font-size: 40rpx;
color: #333;
padding: 30rpx;
line-height: 60rpx;
}
.calendar .title .year-month {
margin-right: 20rpx;
}
.calendar .title .last-icon {
width: 0;
height: 0;
border-right: 24rpx solid #999;
border-top: 12rpx solid transparent;
border-bottom: 12rpx solid transparent;
margin-left: 10rpx;
}
.calendar .title .next-icon {
width: 0;
height: 0;
border-left: 24rpx solid #999;
border-top: 12rpx solid transparent;
border-bottom: 12rpx solid transparent;
margin-left: 40rpx;
}
.calendar .title .open {
background-color: #f6f6f6;
color: #999;
font-size: 22rpx;
line-height: 36rpx;
border-radius: 18rpx;
padding: 0 14rpx;
}
.calendar .calendar-week {
line-height: 40rpx;
padding: 0 25rpx;
font-size: 28rpx;
color: #999;
}
.calendar .calendar-week .view {
width: 100rpx;
text-align: center;
}
.calendar .calendar-main {
padding: 30rpx 25rpx;
}
.calendar .calendar-main .date-group {
transition: all 0.3s;
overflow: hidden;
}
.calendar .calendar-main .date-transform {
transition: all 0.3s;
}
.calendar .calendar-main .day {
position: relative;
width: 100rpx;
color: #666;
text-align: center;
height: 72rpx;
}
.calendar .calendar-main .day .bg {
height: 56rpx;
line-height: 56rpx;
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.calendar .calendar-main .day .select {
width: 56rpx;
border-radius: 50%;
text-align: center;
color: #fff;
background: #409eff;
margin: 0 auto;
}
.calendar .calendar-main .day .other-month {
color: #ccc;
}
.calendar .calendar-main .day .spot {
width: 8rpx;
height: 8rpx;
background-color: #409eff;
border-radius: 50%;
margin: 6rpx auto 0;
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,19 @@
Component({
properties: {
show: {
type: Boolean,
value: false
},
timerText: {
type: String,
value: '00:00:00'
}
},
methods: {
handleTap() {
console.log('[pause-mask] handleTap triggered, show:', this.data.show);
this.triggerEvent('resume');
}
}
});

View File

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {},
"options": {
"virtualHost": true
}
}

View File

@ -0,0 +1,7 @@
<view class="pause-mask {{show ? 'show' : ''}}" bindtap="handleTap">
<view class="pause-content">
<image class="pause-icon" src="https://duiduiminiprogram.oss-cn-hangzhou.aliyuncs.com/mini/pause.png"></image>
<text class="timer-text">{{timerText}}</text>
<text class="tip-text">点击继续答题</text>
</view>
</view>

View File

@ -0,0 +1,65 @@
.pause-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.85);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
z-index: 1500;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
visibility: hidden;
pointer-events: none;
transition: all 0.3s ease;
}
.pause-mask.show {
opacity: 1;
visibility: visible;
pointer-events: auto;
}
.pause-content {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
transform: translateY(20rpx);
opacity: 0;
transition: all 0.3s ease;
color: #fff;
}
.pause-mask.show .pause-content {
transform: translateY(0);
opacity: 1;
}
.pause-icon {
/* width: 120rpx;
height: 120rpx; */
margin-bottom: 40rpx;
}
.pause-title {
font-size: 40rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.timer-text {
font-size: 48rpx;
font-weight: bold;
margin-bottom: 20rpx;
color: #fff;
}
.tip-text {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.8);
}

View File

@ -0,0 +1,93 @@
Component({
properties: {
// 题目对象
question: {
type: Object,
value: {}
},
// 题目索引
questionIndex: {
type: Number,
value: 0
},
// 用户答案数组(用于显示选中状态)
answers: {
type: Array,
value: []
},
// 选项标记数组
optionMarkers: {
type: Array,
value: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
},
// 是否显示答案解析
showAnalysis: {
type: Boolean,
value: false
},
// 是否显示答案图标(正确/错误标记)
showAnswerIcon: {
type: Boolean,
value: false
},
// 是否可点击选项
clickable: {
type: Boolean,
value: true
}
},
data: {
// 组件内部数据
},
attached() {
// 组件挂载时,检查数据
},
observers: {
// 监听 question 属性变化
'question': function(question) {
console.log('question-display 组件 question 属性变化:', question);
}
},
methods: {
// 选项点击事件
onOptionClick(e) {
if (!this.data.clickable) {
return;
}
const index = e.currentTarget.dataset.index;
this.triggerEvent('optionclick', {
optionIndex: index,
questionIndex: this.data.questionIndex
});
},
// 题目容器内触摸catch 阻止冒泡到问题面板;横向滑动时通知页面切换题目(因 swiper 收不到被 catch 的触摸)
onQuestionTouchStart(e) {
if (e.touches && e.touches[0]) {
this._touchStartX = e.touches[0].clientX;
this._touchStartY = e.touches[0].clientY;
this._swipeHorizontalEmitted = false;
}
},
onQuestionTouchMove(e) {
if (this._swipeHorizontalEmitted || !e.touches || !e.touches[0]) return;
const dx = e.touches[0].clientX - this._touchStartX;
const dy = e.touches[0].clientY - this._touchStartY;
const threshold = 40;
if (Math.abs(dx) > threshold && Math.abs(dx) > Math.abs(dy)) {
this._swipeHorizontalEmitted = true;
this.triggerEvent('swipehorizontal', { direction: dx > 0 ? 'right' : 'left' });
}
},
onQuestionTouchEnd() {
this._swipeHorizontalEmitted = false;
},
},
});

View File

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

View File

@ -0,0 +1,79 @@
<view class="question-page">
<!-- 题目容器内:纵向滑动由 scroll-view 滚动,横向滑动通过事件交给页面切换题目;使用 bind 以便选项 tap 能正常触发(问题面板已改为仅拖拽条可拖) -->
<scroll-view scroll-y class="question-content no-material" enhanced="true" show-scrollbar="true" bounces="true" enable-flex="true"
bindtouchstart="onQuestionTouchStart"
bindtouchmove="onQuestionTouchMove"
bindtouchend="onQuestionTouchEnd"
bindtouchcancel="onQuestionTouchEnd">
<view class="question-container">
<view class="question-header" wx:if="{{question}}">
<view class="question-type">{{questionIndex + 1}}. {{question.type === 'single_choice' || question.type === 1 || question.type === 2 ? '单选题' : '多选题'}}</view>
</view>
<!-- 题目内容:使用 rich-text 支持 HTML 渲染 -->
<view style="padding: 16rpx 0;" wx:if="{{question}}">
<rich-text
nodes="{{question.title || question.content || ''}}"
selectable="{{true}}"
style="color:#111;font-size:34rpx;line-height:1.6;"
></rich-text>
</view>
<!-- 选项列表 -->
<view class="options-list" wx:if="{{question && question.options && question.options.length > 0}}">
<view class="option-item {{answers && answers[questionIndex] && answers[questionIndex][optIndex] ? 'option-selected' : ''}} {{opt.cssClass || ''}}"
wx:for="{{question.options}}"
wx:key="id"
wx:for-item="opt"
wx:for-index="optIndex"
bindtap="onOptionClick"
data-index="{{optIndex}}">
<view class="option-content">
<text class="option-letter">{{optionMarkers && optionMarkers[optIndex] ? optionMarkers[optIndex] : String.fromCharCode(65 + optIndex)}}</text>
<text class="separator">|</text>
<rich-text
class="option-text"
nodes="{{opt.content || opt.option_content || opt.text || ''}}"
selectable="{{true}}"
></rich-text>
</view>
<image class="answer-icon"
src="/assets/icons/{{(opt.label === question.correct_answer || opt.option_label === question.correct_answer) ? 'correct.png' : ((opt.label === question.user_answer || opt.option_label === question.user_answer) ? 'wrong.png' : '')}}"
wx:if="{{showAnswerIcon && ((opt.label === question.correct_answer || opt.option_label === question.correct_answer) || (opt.label === question.user_answer || opt.option_label === question.user_answer))}}"
/>
</view>
</view>
<!-- 调试信息:如果没有选项 -->
<view wx:if="{{!question || !question.options || question.options.length === 0}}" style="padding: 20rpx; background: #fff3cd; margin: 20rpx; border-radius: 8rpx;">
<text style="color: #856404; font-size: 28rpx;">⚠️ 题目没有选项数据</text>
<text style="color: #856404; font-size: 24rpx; display: block; margin-top: 10rpx;">question: {{question ? '存在' : '不存在'}}</text>
<text style="color: #856404; font-size: 24rpx; display: block;">options: {{question && question.options ? question.options.length : '无'}}</text>
</view>
<!-- 答案解析区域(可选) -->
<view class="answer-analysis" wx:if="{{showAnalysis}}">
<view class="analysis-header analysis-header-user">
<text class="analysis-title">你的答案</text>
<text class="user-answer" wx:if="{{question.user_answer}}">{{question.user_answer}}</text>
</view>
<view class="analysis-header">
<text class="analysis-title">答案解析</text>
<text class="correct-answer" wx:if="{{question.correct_answer}}">正确答案:{{question.correct_answer}}</text>
</view>
<view class="analysis-content" wx:if="{{question.answer_analysis}}">
<rich-text
nodes="{{question.answer_analysis}}"
selectable="{{true}}"
></rich-text>
</view>
<view class="analysis-content" wx:else>
<text style="color: #999; font-size: 28rpx;">暂无解析</text>
</view>
</view>
<view class="bottom-spacing"></view>
</view>
</scroll-view>
</view>

View File

@ -0,0 +1,155 @@
.question-page {
display: flex;
flex-direction: column;
width: 100% !important;
height: 100% !important;
box-sizing: border-box;
min-width: 0;
position: relative;
/* padding-top: 20rpx; */
padding-bottom: 20rpx;
}
.question-content {
flex: 1;
width: 100% !important;
height: 100% !important;
box-sizing: border-box;
min-width: 0;
display: flex;
flex-direction: column;
}
.question-content.no-material {
/* 高度由父容器控制 */
}
.question-container {
background: #fff;
border-radius: 12rpx;
margin: 0 20rpx 30rpx 20rpx;
padding: 30rpx;
/* box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05); */
width: calc(100% - 40rpx) !important;
box-sizing: border-box;
flex: 1;
min-width: 0;
min-height: 0;
overflow-y: auto;
}
.question-header {
margin-bottom: 20rpx;
}
.question-type {
color: #666;
font-size: 30rpx;
}
.options-list {
margin-top: 30rpx;
width: 100%;
}
.option-item {
margin: 20rpx 0;
display: flex;
align-items: center;
padding: 24rpx 30rpx;
background: #fff;
border-radius: 8rpx;
border: 2rpx solid #E5E5E5;
position: relative;
box-sizing: border-box;
width: 100%;
transition: all 0.2s ease;
}
.option-selected {
background-color: #E3F0FF !important;
border-color: #1A7CFF !important;
}
.option-selected .option-letter,
.option-selected .option-text,
.option-selected .separator {
color: #1A7CFF !important;
}
.option-content {
flex: 1;
display: flex;
align-items: center;
}
.option-letter {
font-size: 32rpx;
color: #333;
font-weight: 500;
min-width: 40rpx;
}
.option-text {
flex: 1;
font-size: 32rpx;
color: #333;
margin-left: 20rpx;
}
.separator {
color: #E5E5E5;
margin: 0 20rpx;
}
.answer-icon {
width: 32rpx;
height: 32rpx;
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
}
.answer-analysis {
margin-top: 40rpx;
padding: 20rpx;
background: #F5F7FA;
border-radius: 8rpx;
}
.analysis-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
.analysis-title {
font-size: 32rpx;
color: #333;
font-weight: 500;
}
/* 你的答案:蓝色,与正确答案的绿色区分 */
.analysis-header-user .user-answer {
font-size: 28rpx;
color: #1890ff;
font-weight: 500;
}
.correct-answer {
font-size: 28rpx;
color: #52C41A;
}
.analysis-content {
font-size: 28rpx;
color: #666;
line-height: 1.6;
}
.bottom-spacing {
height: 40rpx;
}

View File

@ -0,0 +1,105 @@
Component({
properties: {
// 当前高度
height: {
type: Number,
value: 200
},
// 最小高度
minHeight: {
type: Number,
value: 100
},
// 最大高度
maxHeight: {
type: Number,
value: 400
},
// 预设高度点,用于自动吸附
presetHeights: {
type: Array,
value: [100, 150, 200, 250, 300, 350, 400]
},
showHandle: {
type: Boolean,
value: true
}
},
data: {
isResizing: false,
currentStyle: '',
currentHeight: 200
},
observers: {
'height': function (val) {
// 只有非拖动时才同步外部高度
if (!this.data.isResizing) {
this.setData({ currentHeight: val });
}
}
},
methods: {
startResize(e) {
const touch = e.touches[0];
this.startY = touch.clientY;
this.startHeight = this.data.currentHeight;
this.setData({
isResizing: true,
currentStyle: 'transition: none;'
});
// 触发开始事件
this.triggerEvent('resizestart', {
height: this.data.height
});
},
onResize(e) {
if (!this.data.isResizing) return;
const touch = e.touches[0];
const deltaY = touch.clientY - this.startY;
let newHeight = this.startHeight + deltaY;
// 限制高度范围
newHeight = Math.max(this.properties.minHeight,
Math.min(newHeight, this.properties.maxHeight));
this.setData({
currentHeight: newHeight
});
// 触发改变事件
this.triggerEvent('resize', {
height: newHeight
});
},
endResize() {
if (!this.data.isResizing) return;
const targetHeight = this.calculateTargetHeight(this.data.currentHeight);
this.setData({
isResizing: false,
currentStyle: 'transition: height 0.3s cubic-bezier(.4,0,.2,1);',
currentHeight: targetHeight
});
// 触发结束事件
this.triggerEvent('resizeend', {
height: targetHeight
});
},
calculateTargetHeight(currentHeight) {
return this.properties.presetHeights.reduce((prev, curr) =>
Math.abs(curr - currentHeight) < Math.abs(prev - currentHeight) ? curr : prev
);
}
}
});

View File

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

View File

@ -0,0 +1,13 @@
<view class="resize-box {{isResizing ? 'resizing' : ''}}"
style="height: {{currentHeight}}px; {{currentStyle}}">
<slot></slot>
<view wx:if="{{showHandle !== false && showHandle !== 'false'}}" class="resize-handle"
catch:touchstart="startResize"
catch:touchmove="onResize"
catch:touchend="endResize"
catch:touchcancel="endResize">
<view class="resize-line">
<view class="resize-dots"></view>
</view>
</view>
</view>

View File

@ -0,0 +1,48 @@
.resize-box {
position: relative;
width: 100%;
/* background: #fff; // 由外层控制 */
/* border-radius: 6px; // 由外层控制 */
/* border: 1px solid #eee; // 可选 */
will-change: height;
transform: translateZ(0);
-webkit-transform: translateZ(0);
overflow: hidden; /* 也可以加一层保险 */
}
.resize-box.resizing {
transition: none !important;
}
.resize-handle {
position: absolute;
bottom: -10px;
left: 50%;
transform: translateX(-50%);
width: 60px;
height: 20px;
display: flex;
justify-content: center;
align-items: center;
background: transparent;
z-index: 100;
touch-action: none;
}
.resize-line {
width: 20px;
height: 2px;
background: #D8D8D8;
border-radius: 1px;
position: relative;
}
.resize-dots {
position: absolute;
top: -4px;
left: 50%;
transform: translateX(-50%);
width: 10px;
height: 10px;
background: radial-gradient(circle, #999 1px, transparent 1px) 0 0 / 3px 3px;
}

6
config/api.js Normal file
View File

@ -0,0 +1,6 @@
//测试地址
const ApiRootUrl = 'https://ndnd.duiduiedu.com/addons/unishop';
module.exports={
IndexBanner: ApiRootUrl + 'Banner/List', //获取列表
IndexUrl: ApiRootUrl + 'News/GetNewsListByPageType', //首页数据接口
};

62
config/api_config.js Normal file
View File

@ -0,0 +1,62 @@
// API 域名配置
// 根据环境自动切换域名
// 判断是否为开发环境
// 可以通过以下方式切换:
// 1. 直接修改下面的 isDevMode 变量
// 2. 或者通过微信开发者工具的编译条件设置环境变量
const isDevMode = false; // 改为 true 使用本地开发环境127.0.0.1:8080
const isDev = () => {
return isDevMode;
};
// Fiber API 配置(新后端)
const FIBER_API_CONFIG = {
// 开发环境(本地调试)
dev: {
baseURL: 'http://127.0.0.1:8081/api/v1',
},
// 生产环境(线上部署)
prod: {
baseURL: 'https://api.duiduiedu.com/api/v1',
}
};
// PHP API 配置(旧后端,逐步迁移)
const PHP_API_CONFIG = {
// 开发环境
dev: {
baseURL: 'http://127.0.0.1:8006/addons/unishop',
},
// 生产环境
prod: {
baseURL: 'https://ndnd.duiduiedu.com/addons/unishop',
}
};
// 获取当前环境配置
const getFiberApiBaseURL = () => {
return isDev() ? FIBER_API_CONFIG.dev.baseURL : FIBER_API_CONFIG.prod.baseURL;
};
const getPhpApiBaseURL = () => {
return isDev() ? PHP_API_CONFIG.dev.baseURL : PHP_API_CONFIG.prod.baseURL;
};
export default {
// Fiber API新后端
fiberApiBaseURL: getFiberApiBaseURL(),
// PHP API旧后端
phpApiBaseURL: getPhpApiBaseURL(),
// 图片资源域名
imageBaseURL: 'https://ndnd.duiduiedu.com/',
// 工具方法
isDev,
getFiberApiBaseURL,
getPhpApiBaseURL,
};

544
config/camp_api.js Normal file
View File

@ -0,0 +1,544 @@
import request from '../utils/request';
/**
* 打卡营相关 API 接口
* 整合了打卡营任务订单支付等所有相关接口
*/
export const campApi = {
// ==================== 打卡营基础信息 ====================
/**
* 获取打卡营分类列表
*/
getCampCategories: () => {
const url = `/camp/categories?keyword=&page=1&page_size=10`;
return request({
url,
method: 'GET'
});
},
/**
* 获取打卡营列表
* @param {String} categoryId - 分类ID如果为 undefined/null/-1 则返回推荐打卡营
* @param {String} userId - 用户ID可选如果不传则从本地存储获取
*/
getCamps: (categoryId, userId) => {
const user_id = String(userId || wx.getStorageSync('wxuserid') || '');
// 已加入打卡营:只返回当前用户已加入的营
if (categoryId === 'joined') {
return request({
url: `/camp/camps?joined_only=1&page=1&page_size=50&user_id=${encodeURIComponent(user_id)}`,
method: 'GET'
});
}
// 推荐打卡营(与后端 RecommendFilter 约定only_true = 只返回推荐的)
if (!categoryId || categoryId === 'undefined' || categoryId === '-1') {
return request({
url: `/camp/camps?recommend_filter=only_true&page=1&page_size=20&user_id=${encodeURIComponent(user_id)}`,
method: 'GET'
});
}
// 按分类筛选
const url = `/camp/camps?category_id=${categoryId}&page=1&page_size=20&user_id=${encodeURIComponent(user_id)}`;
return request({
url,
method: 'GET'
});
},
/**
* 获取打卡营详情
* @param {String} campId - 打卡营ID
* @param {String} userId - 用户ID可选如果不传则从本地存储获取
*/
getCampDetail: (campId, userId) => {
const user_id = String(userId || wx.getStorageSync('wxuserid') || '');
// 根据 proto 定义,使用查询参数 id
return request({
url: `/camp/camps/detail?id=${campId}&user_id=${encodeURIComponent(user_id)}`,
method: 'GET'
});
},
/**
* 获取打卡营详情及状态聚合接口包含用户状态小节任务等完整信息
* @param {String} campId - 打卡营ID
* @param {String} userId - 用户ID
*/
getCampDetailWithUserStatus: (campId, userId) => {
return request({
url: `/camp/camp_detail_with_user_status`,
method: 'POST',
data: {
camp_id: String(campId),
user_id: String(userId || wx.getStorageSync('wxuserid') || '')
}
});
},
// ==================== 用户打卡营操作 ====================
/**
* 加入打卡营
* @param {String} campId - 打卡营ID
*/
joinCamp: (campId) => {
return request({
url: `/camp/user_camp/join`,
method: 'POST',
data: {
user_id: String(wx.getStorageSync('wxuserid') || ''), // 从本地存储获取用户ID
camp_id: campId
}
});
},
/**
* 检查用户是否加入打卡营
* @param {String} campId - 打卡营ID
*/
checkUserCampStatus: (campId) => {
return request({
url: `/camp/check_user_camp_status`,
method: 'POST',
data: {
user_id: String(wx.getStorageSync('wxuserid') || ''), // 从本地存储获取用户ID
camp_id: campId
}
});
},
/**
* 重置打卡营进度新接口
* @param {String} campId - 打卡营ID
* @param {String} userId - 用户ID
* @param {Boolean} confirm - 是否确认
*/
resetCampProgress: (campId, userId, confirm = true) => {
return request({
url: `/camp/user_camp/reset_progress`,
method: 'POST',
data: {
user_id: String(userId || wx.getStorageSync('wxuserid') || ''),
camp_id: String(campId),
confirm: confirm
}
});
},
/**
* 重启打卡营旧接口已废弃
* @deprecated 请使用 resetCampProgress
*/
restartCamp: (campId) => {
return request({
url: `/camp/${campId}/restart`,
method: 'POST'
});
},
// ==================== 小节相关 ====================
/**
* 获取打卡营的小节列表课程列表
* @param {String} campId - 打卡营ID
* @param {String} userId - 用户ID可选如果不传则从本地存储获取
*/
getCampCourses: (campId, userId) => {
const user_id = String(userId || wx.getStorageSync('wxuserid') || '');
// 根据 proto 定义,使用 /camp/sections 接口,通过 camp_id 查询参数
return request({
url: `/camp/sections?camp_id=${campId}&page=1&page_size=10&user_id=${encodeURIComponent(user_id)}`,
method: 'GET'
});
},
/**
* 检查是否可开启小节后端查库上一小节是否完成等
* @param {String} campId - 打卡营ID
* @param {String} sectionId - 小节ID
* @returns {Promise<{ success: boolean, can_unlock: boolean, message: string }>}
*/
canUnlockSection: (campId, sectionId) => {
return request({
url: `/camp/can_unlock_section`,
method: 'POST',
data: {
user_id: String(wx.getStorageSync('wxuserid') || ''),
camp_id: campId,
section_id: sectionId
}
});
},
/**
* 检查任务是否可以开始前置任务是否已完成
* @param {String} taskId - 任务ID
* @returns {Promise<{ success: boolean, can_start: boolean, reason: string }>}
*/
canStartTask: (taskId) => {
return request({
url: `/camp/can_start_task`,
method: 'POST',
data: {
user_id: String(wx.getStorageSync('wxuserid') || ''),
task_id: taskId
}
});
},
/**
* 购买小节开启第一小节
* @param {String} campId - 打卡营ID
* @param {String} sectionId - 小节ID
*/
purchaseSection: (campId, sectionId) => {
return request({
url: `/camp/purchase_section`,
method: 'POST',
data: {
user_id: String(wx.getStorageSync('wxuserid') || ''),
camp_id: campId,
section_id: sectionId
}
});
},
/**
* 获取用户在某营的小节可访问/已购列表
* @param {String} campId - 打卡营ID
* @param {Number} page - 页码
* @param {Number} page_size - 每页数量
*/
listUserSectionAccess: (campId, page = 1, page_size = 1000) => {
return request({
url: `/camp/list_user_section_access`,
method: 'POST',
data: {
user_id: String(wx.getStorageSync('wxuserid') || ''),
camp_id: campId,
page,
page_size
}
});
},
/**
* 获取每个小节的完成状态
* @param {String} campId - 打卡营ID
* @param {String} userId - 用户ID
*/
getSectionUserStatus: (campId, userId) => {
return request({
url: `/camp/section/user-status`,
method: 'POST',
data: {
camp_id: String(campId),
user_id: String(userId || wx.getStorageSync('wxuserid') || '')
}
});
},
/**
* 根据课程小节ID获取用户与课程小节的关联关系
* @param {String} courseIds - 课程ID列表逗号分隔
* @param {String} userId - 用户ID可选如果不传则从本地存储获取
*/
getCourseUserRelations: (courseIds, userId) => {
const user_id = String(userId || wx.getStorageSync('wxuserid') || '');
return request({
url: `/camp/course/user-course-relations?course_ids=${courseIds}&user_id=${encodeURIComponent(user_id)}`,
method: 'GET',
});
},
/**
* 获取课程完成状态
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
*/
getCourseCompleted: (campId, courseId) => {
return request({
url: `/camp/${campId}/course/${courseId}/completed`,
method: 'GET'
});
},
// ==================== 任务相关 ====================
/**
* 获取任务详情需要 campId courseId
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
* @param {String} taskId - 任务ID
* @param {String} taskType - 任务类型
*/
getTaskDetail: (campId, courseId, taskId, taskType) => {
return request({
url: `/camp/${campId}/course/${courseId}/tasks/${taskId}?task_type=${taskType.toUpperCase()}`,
method: 'GET',
});
},
/**
* 按任务ID直接获取任务详情无需 campId/courseId
* @param {String} taskId - 任务ID
* @param {String} userId - 用户ID可选如果不传则从本地存储获取
*/
getTaskDetailById: (taskId, userId) => {
const user_id = String(userId || wx.getStorageSync('wxuserid') || '');
return request({
url: `/camp/tasks/detail?id=${taskId}&user_id=${encodeURIComponent(user_id)}`,
method: 'GET',
});
},
/**
* 根据任务ID获取任务与用户的关联关系
* @param {String} taskIds - 任务ID列表逗号分隔
* @param {String} userId - 用户ID可选如果不传则从本地存储获取
*/
getCampTaskUserRelations: (taskIds, userId) => {
const user_id = String(userId || wx.getStorageSync('wxuserid') || '');
return request({
url: `/camp/task/user_task?task_ids=${taskIds}&user_id=${encodeURIComponent(user_id)}`,
method: 'GET',
});
},
// ==================== 任务进度相关 ====================
/**
* 获取用户任务进度详情
* @param {String} userId - 用户ID
* @param {String} taskId - 任务ID
*/
getProgressDetail: (userId, taskId) => {
// GET 请求的参数作为 query 参数传递(兼容微信小程序,不使用 URLSearchParams
const user_id = encodeURIComponent(String(userId));
const task_id = encodeURIComponent(String(taskId));
return request({
url: `/camp/progress/info?user_id=${user_id}&task_id=${task_id}`,
method: 'GET'
});
// 注意request.js 已处理,当 success=false 时不会显示错误提示(没有进度是正常情况)
},
/**
* 更新任务通用进度
* @param {Object} data - 进度数据
*/
updateCampProgress: (data) => {
return request({
url: `/camp/progress/update`,
method: 'POST',
data: data
});
},
/**
* 重置任务进度用户重新答题
* @param {Object} data - 重置数据
*/
resetTaskProgress: (data) => {
return request({
url: `/camp/reset_task_progress`,
method: 'POST',
data: data
});
},
// ==================== 任务类型特定接口 ====================
/**
* 更新视频任务进度
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
* @param {String} taskId - 任务ID
* @param {Object} data - 进度数据
*/
updateVideoProgress: (campId, courseId, taskId, data) => {
return request({
url: `/camp/${campId}/course/${courseId}/tasks/${taskId}/video`,
method: 'POST',
data: data
});
},
/**
* 更新文本图片任务进度
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
* @param {String} taskId - 任务ID
* @param {Object} data - 进度数据
*/
updateTextImageProgress: (campId, courseId, taskId, data) => {
return request({
url: `/camp/${campId}/course/${courseId}/tasks/${taskId}/text-image`,
method: 'POST',
data: data
});
},
/**
* 更新主观题任务进度
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
* @param {String} taskId - 任务ID
* @param {Object} data - 进度数据
*/
updateSubjectiveQuestionProgress: (campId, courseId, taskId, data) => {
return request({
url: `/camp/${campId}/course/${courseId}/tasks/${taskId}/subjective`,
method: 'POST',
data: data
});
},
/**
* 更新申论任务进度
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
* @param {String} taskId - 任务ID
* @param {Object} data - 进度数据
*/
updateEssayProgress: (campId, courseId, taskId, data) => {
return request({
url: `/camp/${campId}/course/${courseId}/tasks/${taskId}/essay-question/essay`,
method: 'POST',
data: data
});
},
/**
* 更新客观题任务进度
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
* @param {String} taskId - 任务ID
* @param {Object} data - 进度数据
*/
updateObjectiveQuestionProgress: (campId, courseId, taskId, data) => {
return request({
url: `/camp/${campId}/course/${courseId}/tasks/${taskId}/objective`,
method: 'POST',
data: data
});
},
// ==================== 任务答案相关 ====================
/**
* 获取主观题任务的用户答案
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
* @param {String} taskId - 任务ID
*/
getSubjectiveTaskUserAnswer: (campId, courseId, taskId) => {
return request({
url: `/camp/${campId}/course/${courseId}/tasks/${taskId}/subjective/user-answer`,
method: 'GET',
});
},
/**
* 获取申论题任务所有问题的用户答案
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
* @param {String} taskId - 任务ID
*/
getEssayQuestionUserAnswer: (campId, courseId, taskId) => {
return request({
url: `/camp/${campId}/course/${courseId}/tasks/${taskId}/essay-question/user-answer`,
method: 'GET',
});
},
/**
* 获取申论题任务是否需要审核
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
* @param {String} taskId - 任务ID
*/
getEssayTaskReviewStatus: (campId, courseId, taskId) => {
return request({
url: `/camp/${campId}/course/${courseId}/tasks/${taskId}/essay-question/need-audit`,
method: 'GET',
});
},
/**
* 获取客观题答题结算结果
* @param {String} campId - 打卡营ID
* @param {String} courseId - 课程ID
* @param {String} taskId - 任务ID
*/
getObjectiveQuestionSettlementResult: (campId, courseId, taskId) => {
return request({
url: `/camp/${campId}/course/${courseId}/tasks/${taskId}/objective/settlement-result`,
method: 'GET',
});
},
// ==================== 订单相关 ====================
/**
* 创建订单打卡营小节
* @param {Object} orderData - 订单数据
*/
createOrder: (orderData) => {
return request({
url: `/order/create`,
method: 'POST',
data: orderData
});
},
/**
* 取消订单
* @param {Object} orderData - 订单数据
*/
cancelOrder: (orderData) => {
return request({
url: `/order/cancel`,
method: 'POST',
data: orderData
});
},
// ==================== 支付相关 ====================
/**
* 创建支付获取预支付ID
* @param {Object} paymentData - 支付数据
*/
createPayment: (paymentData) => {
return request({
url: `/pay/create`,
method: 'POST',
data: paymentData
});
},
/**
* 创建打卡营小节支付请求订单已废弃使用 createOrder + createPayment
* @deprecated 请使用 createOrder + createPayment
*/
createCampPayment: (campId, courseId) => {
return request({
url: `/camp/${campId}/course/${courseId}/order`,
method: 'POST',
});
},
/**
* 取消支付
* @deprecated 请使用 cancelOrder
*/
cancelCampPayment: (campId, orderId) => {
return request({
url: `/camp/${campId}/order/${orderId}/cancel`,
method: 'POST',
});
},
};

144
config/question_api.js Normal file
View File

@ -0,0 +1,144 @@
import apiConfig from './api_config.js';
import request from '../utils/request.js';
// Fiber 后端请求函数
// 注意request 函数内部已经会拼接 baseURL所以这里只需要传入相对路径
function fiberRequest(options) {
return request({
url: options.url, // 只传入相对路径request 函数会拼接 baseURL
method: options.method || 'GET',
data: options.data,
header: options.header || {}
});
}
export const questionApi = {
/**
* 获取试卷详情使用 Fiber 后端
* @param {string} paperId 试卷ID
* @returns {Promise} 试卷数据
*/
getPaperDetail: (paperId) => {
return fiberRequest({
url: `/paper/detail?id=${paperId}`,
method: 'GET'
}).then(res => {
// 转换 Fiber 后端返回格式为前端期望的格式
if (res.success && res.paper) {
return {
success: true,
code: 200,
data: res.paper,
paper: res.paper // 兼容旧格式
};
}
return res;
});
},
/**
* 获取试卷兼容旧接口接受 paperId taskId
* @param {string} paperId 试卷ID
* @param {string} taskId 任务ID可选
* @returns {Promise} 试卷数据
*/
getExamPaper: (paperId, taskId) => {
return questionApi.getPaperDetail(paperId);
},
/**
* 获取试卷详情包含答案和解析用于答题结果页面
* @param {string} paperId 试卷ID
* @returns {Promise} 试卷数据包含答案和解析
*/
getPaperWithAnswers: (paperId) => {
return fiberRequest({
url: `/paper/result?id=${paperId}`,
method: 'GET'
}).then(res => {
// 转换 Fiber 后端返回格式为前端期望的格式
if (res.success && (res.paper || res.data)) {
const paper = res.paper || res.data;
return {
success: true,
code: 200,
data: paper,
paper: paper // 兼容旧格式
};
}
return res;
});
},
/**
* 创建答题记录使用 Fiber 后端
* @param {object} data 答题记录数据
* @param {string} data.user_id 用户ID
* @param {string} data.paper_id 试卷ID
* @param {number} data.start_time 开始时间Unix时间戳
* @param {number} data.end_time 结束时间Unix时间戳
* @param {array} data.answers 答案数组
* @returns {Promise} 创建结果
*/
createAnswerRecord: (data) => {
// 转换前端数据格式为 Fiber 后端期望的格式
const fiberData = {
user_id: String(data.user_id),
paper_id: String(data.paper_id),
task_id: data.task_id ? String(data.task_id) : '', // 打卡营任务ID用于不同打卡营的答题隔离
start_time: data.start_time || Math.floor(Date.now() / 1000),
end_time: data.end_time || Math.floor(Date.now() / 1000),
answers: (data.answers || []).map(answer => ({
question_id: String(answer.question_id),
user_answer: String(answer.user_answer || '')
}))
};
return fiberRequest({
url: `/answer_record/create`,
method: 'POST',
data: fiberData
}).then(res => {
// 转换 Fiber 后端返回格式为前端期望的格式
if (res.success) {
return {
success: true,
code: 200,
...res
};
}
return res;
});
},
/**
* 获取答题记录使用 Fiber 后端
* @param {string} userId 用户ID
* @param {string} paperId 试卷ID
* @param {number} page 页码
* @param {number} pageSize 每页数量
* @returns {Promise} 答题记录列表
*/
getAnswerRecord: (userId, paperId, page = 1, pageSize = 100, taskId = '') => {
let url = `/answer_record/detail?user_id=${userId}&paper_id=${paperId}&page=${page}&page_size=${pageSize}`;
if (taskId) {
url += `&task_id=${taskId}`;
}
return fiberRequest({
url: url,
method: 'GET'
}).then(res => {
// 转换 Fiber 后端返回格式为前端期望的格式
if (res.success) {
return {
success: true,
code: 200,
...res
};
}
return res;
});
}
};

59
config/util.js Normal file
View File

@ -0,0 +1,59 @@
/**
* GET请求封装
*/
function get(url, data = {}) {
return request(url, data, 'GET')
}
/**
* POST请求封装
*/
function post(url, data = {}) {
return request(url, data, 'POST')
}
/**
* 微信的request
*/
function request(url, data = {}, method = "GET") {
var contentType = 'application/json'
return new Promise(function(resolve, reject) {
wx.request({
url: url,
data: data,
method: method,
header: {
'Content-Type': contentType
},
success: function(res) {
console.log('===============================================================================================')
console.log('== 接口地址:' + url)
console.log('== 接口参数:' + JSON.stringify(data))
console.log('== 请求类型:' + method)
console.log("== 接口状态:" + res.statusCode);
console.log('===============================================================================================')
if (res.statusCode == 200) {
resolve(res.data);
} else {
//请求失败
reject("请求失败:" + res.statusCode)
}
},
fail: function(err) {
//服务器连接异常
console.log('===============================================================================================')
console.log('== 接口地址:' + url)
console.log('== 接口参数:' + JSON.stringify(data))
console.log('== 请求类型:' + method)
console.log("== 服务器连接异常")
console.log('===============================================================================================')
reject("服务器连接异常,请检查网络再试")
}
})
});
}
module.exports = {
request,
get,
post
}

BIN
img/cgz_03.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
img/cgz_05.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

BIN
img/cgz_07.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
img/cgz_09.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
img/footerpic.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

BIN
img/footerpic1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
img/footerpic2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

BIN
img/footerpic3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
img/minemainback.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

BIN
img/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
img/play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -0,0 +1,76 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var component_1 = require('../common/component');
var button_1 = require('../mixins/button');
component_1.VantComponent({
mixins: [button_1.button],
props: {
show: Boolean,
title: String,
cancelText: String,
description: String,
round: {
type: Boolean,
value: true,
},
zIndex: {
type: Number,
value: 100,
},
actions: {
type: Array,
value: [],
},
overlay: {
type: Boolean,
value: true,
},
closeOnClickOverlay: {
type: Boolean,
value: true,
},
closeOnClickAction: {
type: Boolean,
value: true,
},
safeAreaInsetBottom: {
type: Boolean,
value: true,
},
},
methods: {
onSelect: function (event) {
var _this = this;
var index = event.currentTarget.dataset.index;
var _a = this.data,
actions = _a.actions,
closeOnClickAction = _a.closeOnClickAction,
canIUseGetUserProfile = _a.canIUseGetUserProfile;
var item = actions[index];
if (item) {
this.$emit('select', item);
if (closeOnClickAction) {
this.onClose();
}
if (item.openType === 'getUserInfo' && canIUseGetUserProfile) {
wx.getUserProfile({
desc: item.getUserProfileDesc || ' ',
complete: function (userProfile) {
_this.$emit('getuserinfo', userProfile);
},
});
}
}
},
onCancel: function () {
this.$emit('cancel');
},
onClose: function () {
this.$emit('close');
},
onClickOverlay: function () {
this.$emit('click-overlay');
this.onClose();
},
},
});

View File

@ -0,0 +1,8 @@
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index",
"van-popup": "../popup/index",
"van-loading": "../loading/index"
}
}

View File

@ -0,0 +1,69 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<van-popup
show="{{ show }}"
position="bottom"
round="{{ round }}"
z-index="{{ zIndex }}"
overlay="{{ overlay }}"
custom-class="van-action-sheet"
safe-area-inset-bottom="{{ safeAreaInsetBottom }}"
close-on-click-overlay="{{ closeOnClickOverlay }}"
bind:close="onClickOverlay"
>
<view wx:if="{{ title }}" class="van-action-sheet__header">
{{ title }}
<van-icon
name="cross"
custom-class="van-action-sheet__close"
bind:click="onClose"
/>
</view>
<view wx:if="{{ description }}" class="van-action-sheet__description van-hairline--bottom">
{{ description }}
</view>
<view wx:if="{{ actions && actions.length }}">
<!-- button外包一层view防止actions动态变化导致渲染时button被打散 -->
<button
wx:for="{{ actions }}"
wx:key="index"
open-type="{{ item.disabled || item.loading || (canIUseGetUserProfile && item.openType === 'getUserInfo') ? '' : item.openType }}"
style="{{ item.color ? 'color: ' + item.color : '' }}"
class="{{ utils.bem('action-sheet__item', { disabled: item.disabled || item.loading }) }} {{ item.className || '' }}"
hover-class="van-action-sheet__item--hover"
data-index="{{ index }}"
bindtap="{{ item.disabled || item.loading ? '' : 'onSelect' }}"
bindgetuserinfo="onGetUserInfo"
bindcontact="onContact"
bindgetphonenumber="onGetPhoneNumber"
binderror="onError"
bindlaunchapp="onLaunchApp"
bindopensetting="onOpenSetting"
lang="{{ lang }}"
session-from="{{ sessionFrom }}"
send-message-title="{{ sendMessageTitle }}"
send-message-path="{{ sendMessagePath }}"
send-message-img="{{ sendMessageImg }}"
show-message-card="{{ showMessageCard }}"
app-parameter="{{ appParameter }}"
>
<block wx:if="{{ !item.loading }}">
{{ item.name }}
<view wx:if="{{ item.subname }}" class="van-action-sheet__subname" >{{ item.subname }}</view>
</block>
<van-loading wx:else custom-class="van-action-sheet__loading" size="22px" />
</button>
</view>
<slot />
<block wx:if="{{ cancelText }}">
<view class="van-action-sheet__gap" />
<view
class="van-action-sheet__cancel"
hover-class="van-action-sheet__cancel--hover"
hover-stay-time="70"
bind:tap="onCancel"
>
{{ cancelText }}
</view>
</block>
</van-popup>

View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-action-sheet{max-height:90%!important;max-height:var(--action-sheet-max-height,90%)!important;color:#323233;color:var(--action-sheet-item-text-color,#323233)}.van-action-sheet__cancel,.van-action-sheet__item{padding:14px 16px;text-align:center;font-size:16px;font-size:var(--action-sheet-item-font-size,16px);line-height:22px;line-height:var(--action-sheet-item-line-height,22px);background-color:#fff;background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__cancel--hover,.van-action-sheet__item--hover{background-color:#f2f3f5;background-color:var(--active-color,#f2f3f5)}.van-action-sheet__cancel:after,.van-action-sheet__item:after{border-width:0}.van-action-sheet__cancel{color:#646566;color:var(--action-sheet-cancel-text-color,#646566)}.van-action-sheet__gap{display:block;height:8px;height:var(--action-sheet-cancel-padding-top,8px);background-color:#f7f8fa;background-color:var(--action-sheet-cancel-padding-color,#f7f8fa)}.van-action-sheet__item--disabled{color:#c8c9cc;color:var(--action-sheet-item-disabled-text-color,#c8c9cc)}.van-action-sheet__item--disabled.van-action-sheet__item--hover{background-color:#fff;background-color:var(--action-sheet-item-background,#fff)}.van-action-sheet__subname{margin-top:8px;margin-top:var(--padding-xs,8px);font-size:12px;font-size:var(--action-sheet-subname-font-size,12px);color:#969799;color:var(--action-sheet-subname-color,#969799);line-height:20px;line-height:var(--action-sheet-subname-line-height,20px)}.van-action-sheet__header{text-align:center;font-weight:500;font-weight:var(--font-weight-bold,500);font-size:16px;font-size:var(--action-sheet-header-font-size,16px);line-height:48px;line-height:var(--action-sheet-header-height,48px)}.van-action-sheet__description{text-align:center;padding:20px 16px;padding:20px var(--padding-md,16px);color:#969799;color:var(--action-sheet-description-color,#969799);font-size:14px;font-size:var(--action-sheet-description-font-size,14px);line-height:20px;line-height:var(--action-sheet-description-line-height,20px)}.van-action-sheet__close{position:absolute!important;top:0;right:0;line-height:inherit!important;padding:0 16px;padding:var(--action-sheet-close-icon-padding,0 16px);font-size:22px!important;font-size:var(--action-sheet-close-icon-size,22px)!important;color:#c8c9cc;color:var(--action-sheet-close-icon-color,#c8c9cc)}.van-action-sheet__loading{display:flex!important}

View File

@ -0,0 +1,266 @@
'use strict';
var __assign =
(this && this.__assign) ||
function () {
__assign =
Object.assign ||
function (t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s)
if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, '__esModule', { value: true });
var component_1 = require('../common/component');
var shared_1 = require('../picker/shared');
var utils_1 = require('../common/utils');
var EMPTY_CODE = '000000';
component_1.VantComponent({
classes: ['active-class', 'toolbar-class', 'column-class'],
props: __assign(__assign({}, shared_1.pickerProps), {
value: {
type: String,
observer: function (value) {
this.code = value;
this.setValues();
},
},
areaList: {
type: Object,
value: {},
observer: 'setValues',
},
columnsNum: {
type: null,
value: 3,
},
columnsPlaceholder: {
type: Array,
observer: function (val) {
this.setData({
typeToColumnsPlaceholder: {
province: val[0] || '',
city: val[1] || '',
county: val[2] || '',
},
});
},
},
}),
data: {
columns: [{ values: [] }, { values: [] }, { values: [] }],
typeToColumnsPlaceholder: {},
},
mounted: function () {
var _this = this;
utils_1.requestAnimationFrame(function () {
_this.setValues();
});
},
methods: {
getPicker: function () {
if (this.picker == null) {
this.picker = this.selectComponent('.van-area__picker');
}
return this.picker;
},
onCancel: function (event) {
this.emit('cancel', event.detail);
},
onConfirm: function (event) {
var index = event.detail.index;
var value = event.detail.value;
value = this.parseValues(value);
this.emit('confirm', { value: value, index: index });
},
emit: function (type, detail) {
detail.values = detail.value;
delete detail.value;
this.$emit(type, detail);
},
parseValues: function (values) {
var columnsPlaceholder = this.data.columnsPlaceholder;
return values.map(function (value, index) {
if (
value &&
(!value.code || value.name === columnsPlaceholder[index])
) {
return __assign(__assign({}, value), { code: '', name: '' });
}
return value;
});
},
onChange: function (event) {
var _this = this;
var _a;
var _b = event.detail,
index = _b.index,
picker = _b.picker,
value = _b.value;
this.code = value[index].code;
(_a = this.setValues()) === null || _a === void 0
? void 0
: _a.then(function () {
_this.$emit('change', {
picker: picker,
values: _this.parseValues(picker.getValues()),
index: index,
});
});
},
getConfig: function (type) {
var areaList = this.data.areaList;
return (areaList && areaList[type + '_list']) || {};
},
getList: function (type, code) {
if (type !== 'province' && !code) {
return [];
}
var typeToColumnsPlaceholder = this.data.typeToColumnsPlaceholder;
var list = this.getConfig(type);
var result = Object.keys(list).map(function (code) {
return {
code: code,
name: list[code],
};
});
if (code != null) {
// oversea code
if (code[0] === '9' && type === 'city') {
code = '9';
}
result = result.filter(function (item) {
return item.code.indexOf(code) === 0;
});
}
if (typeToColumnsPlaceholder[type] && result.length) {
// set columns placeholder
var codeFill =
type === 'province'
? ''
: type === 'city'
? EMPTY_CODE.slice(2, 4)
: EMPTY_CODE.slice(4, 6);
result.unshift({
code: '' + code + codeFill,
name: typeToColumnsPlaceholder[type],
});
}
return result;
},
getIndex: function (type, code) {
var compareNum = type === 'province' ? 2 : type === 'city' ? 4 : 6;
var list = this.getList(type, code.slice(0, compareNum - 2));
// oversea code
if (code[0] === '9' && type === 'province') {
compareNum = 1;
}
code = code.slice(0, compareNum);
for (var i = 0; i < list.length; i++) {
if (list[i].code.slice(0, compareNum) === code) {
return i;
}
}
return 0;
},
setValues: function () {
var picker = this.getPicker();
if (!picker) {
return;
}
var code = this.code || this.getDefaultCode();
var provinceList = this.getList('province');
var cityList = this.getList('city', code.slice(0, 2));
var stack = [];
var indexes = [];
var columnsNum = this.data.columnsNum;
if (columnsNum >= 1) {
stack.push(picker.setColumnValues(0, provinceList, false));
indexes.push(this.getIndex('province', code));
}
if (columnsNum >= 2) {
stack.push(picker.setColumnValues(1, cityList, false));
indexes.push(this.getIndex('city', code));
if (cityList.length && code.slice(2, 4) === '00') {
code = cityList[0].code;
}
}
if (columnsNum === 3) {
stack.push(
picker.setColumnValues(
2,
this.getList('county', code.slice(0, 4)),
false
)
);
indexes.push(this.getIndex('county', code));
}
return Promise.all(stack)
.catch(function () {})
.then(function () {
return picker.setIndexes(indexes);
})
.catch(function () {});
},
getDefaultCode: function () {
var columnsPlaceholder = this.data.columnsPlaceholder;
if (columnsPlaceholder.length) {
return EMPTY_CODE;
}
var countyCodes = Object.keys(this.getConfig('county'));
if (countyCodes[0]) {
return countyCodes[0];
}
var cityCodes = Object.keys(this.getConfig('city'));
if (cityCodes[0]) {
return cityCodes[0];
}
return '';
},
getValues: function () {
var picker = this.getPicker();
if (!picker) {
return [];
}
return this.parseValues(
picker.getValues().filter(function (value) {
return !!value;
})
);
},
getDetail: function () {
var values = this.getValues();
var area = {
code: '',
country: '',
province: '',
city: '',
county: '',
};
if (!values.length) {
return area;
}
var names = values.map(function (item) {
return item.name;
});
area.code = values[values.length - 1].code;
if (area.code[0] === '9') {
area.country = names[1] || '';
area.province = names[2] || '';
} else {
area.province = names[0] || '';
area.city = names[1] || '';
area.county = names[2] || '';
}
return area;
},
reset: function (code) {
this.code = code || '';
return this.setValues();
},
},
});

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"van-picker": "../picker/index"
}
}

View File

@ -0,0 +1,20 @@
<wxs src="./index.wxs" module="computed" />
<van-picker
class="van-area__picker"
active-class="active-class"
toolbar-class="toolbar-class"
column-class="column-class"
show-toolbar
value-key="name"
title="{{ title }}"
loading="{{ loading }}"
columns="{{ computed.displayColumns(columns, columnsNum) }}"
item-height="{{ itemHeight }}"
visible-item-count="{{ visibleItemCount }}"
cancel-button-text="{{ cancelButtonText }}"
confirm-button-text="{{ confirmButtonText }}"
bind:change="onChange"
bind:confirm="onConfirm"
bind:cancel="onCancel"
/>

View File

@ -0,0 +1,8 @@
/* eslint-disable */
function displayColumns(columns, columnsNum) {
return columns.slice(0, +columnsNum);
}
module.exports = {
displayColumns: displayColumns,
};

View File

@ -0,0 +1 @@
@import '../common/index.wxss';

View File

@ -0,0 +1,71 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var component_1 = require('../common/component');
var button_1 = require('../mixins/button');
var version_1 = require('../common/version');
var mixins = [button_1.button];
if (version_1.canIUseFormFieldButton()) {
mixins.push('wx://form-field-button');
}
component_1.VantComponent({
mixins: mixins,
classes: ['hover-class', 'loading-class'],
data: {
baseStyle: '',
},
props: {
formType: String,
icon: String,
classPrefix: {
type: String,
value: 'van-icon',
},
plain: Boolean,
block: Boolean,
round: Boolean,
square: Boolean,
loading: Boolean,
hairline: Boolean,
disabled: Boolean,
loadingText: String,
customStyle: String,
loadingType: {
type: String,
value: 'circular',
},
type: {
type: String,
value: 'default',
},
dataset: null,
size: {
type: String,
value: 'normal',
},
loadingSize: {
type: String,
value: '20px',
},
color: String,
},
methods: {
onClick: function (event) {
var _this = this;
this.$emit('click', event);
var _a = this.data,
canIUseGetUserProfile = _a.canIUseGetUserProfile,
openType = _a.openType,
getUserProfileDesc = _a.getUserProfileDesc,
lang = _a.lang;
if (openType === 'getUserInfo' && canIUseGetUserProfile) {
wx.getUserProfile({
desc: getUserProfileDesc || ' ',
lang: lang || 'en',
complete: function (userProfile) {
_this.$emit('getuserinfo', userProfile);
},
});
}
},
},
});

View File

@ -0,0 +1,7 @@
{
"component": true,
"usingComponents": {
"van-icon": "../icon/index",
"van-loading": "../loading/index"
}
}

View File

@ -0,0 +1,53 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<wxs src="./index.wxs" module="computed" />
<button
id="{{ id }}"
data-detail="{{ dataset }}"
class="custom-class {{ utils.bem('button', [type, size, { block, round, plain, square, loading, disabled, hairline, unclickable: disabled || loading }]) }} {{ hairline ? 'van-hairline--surround' : '' }}"
hover-class="van-button--active hover-class"
lang="{{ lang }}"
form-type="{{ formType }}"
style="{{ computed.rootStyle({ plain, color, customStyle }) }}"
open-type="{{ disabled || loading || (canIUseGetUserProfile && openType === 'getUserInfo') ? '' : openType }}"
business-id="{{ businessId }}"
session-from="{{ sessionFrom }}"
send-message-title="{{ sendMessageTitle }}"
send-message-path="{{ sendMessagePath }}"
send-message-img="{{ sendMessageImg }}"
show-message-card="{{ showMessageCard }}"
app-parameter="{{ appParameter }}"
aria-label="{{ ariaLabel }}"
bindtap="{{ disabled || loading ? '' : 'onClick' }}"
bindgetuserinfo="onGetUserInfo"
bindcontact="onContact"
bindgetphonenumber="onGetPhoneNumber"
binderror="onError"
bindlaunchapp="onLaunchApp"
bindopensetting="onOpenSetting"
>
<block wx:if="{{ loading }}">
<van-loading
custom-class="loading-class"
size="{{ loadingSize }}"
type="{{ loadingType }}"
color="{{ computed.loadingColor({ type, color, plain }) }}"
/>
<view wx:if="{{ loadingText }}" class="van-button__loading-text">
{{ loadingText }}
</view>
</block>
<block wx:else>
<van-icon
wx:if="{{ icon }}"
size="1.2em"
name="{{ icon }}"
class-prefix="{{ classPrefix }}"
class="van-button__icon"
custom-style="line-height: inherit;"
/>
<view class="van-button__text">
<slot />
</view>
</block>
</button>

View File

@ -0,0 +1,39 @@
/* eslint-disable */
var style = require('../wxs/style.wxs');
function rootStyle(data) {
if (!data.color) {
return data.customStyle;
}
var properties = {
color: data.plain ? data.color : '#fff',
background: data.plain ? null : data.color,
};
// hide border when color is linear-gradient
if (data.color.indexOf('gradient') !== -1) {
properties.border = 0;
} else {
properties['border-color'] = data.color;
}
return style([properties, data.customStyle]);
}
function loadingColor(data) {
if (data.plain) {
return data.color ? data.color : '#c9c9c9';
}
if (data.type === 'default') {
return '#c9c9c9';
}
return '#fff';
}
module.exports = {
rootStyle: rootStyle,
loadingColor: loadingColor,
};

View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-button{position:relative;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;padding:0;text-align:center;vertical-align:middle;-webkit-appearance:none;-webkit-text-size-adjust:100%;height:44px;height:var(--button-default-height,44px);line-height:20px;line-height:var(--button-line-height,20px);font-size:16px;font-size:var(--button-default-font-size,16px);transition:opacity .2s;transition:opacity var(--animation-duration-fast,.2s);border-radius:2px;border-radius:var(--button-border-radius,2px)}.van-button:before{position:absolute;top:50%;left:50%;width:100%;height:100%;border:inherit;border-radius:inherit;transform:translate(-50%,-50%);opacity:0;content:" ";background-color:#000;background-color:var(--black,#000);border-color:#000;border-color:var(--black,#000)}.van-button:after{border-width:0}.van-button--active:before{opacity:.15}.van-button--unclickable:after{display:none}.van-button--default{color:#323233;color:var(--button-default-color,#323233);background:#fff;background:var(--button-default-background-color,#fff);border:1px solid #ebedf0;border:var(--button-border-width,1px) solid var(--button-default-border-color,#ebedf0)}.van-button--primary{color:#fff;color:var(--button-primary-color,#fff);background:#07c160;background:var(--button-primary-background-color,#07c160);border:1px solid #07c160;border:var(--button-border-width,1px) solid var(--button-primary-border-color,#07c160)}.van-button--info{color:#fff;color:var(--button-info-color,#fff);background:#1989fa;background:var(--button-info-background-color,#1989fa);border:1px solid #1989fa;border:var(--button-border-width,1px) solid var(--button-info-border-color,#1989fa)}.van-button--danger{color:#fff;color:var(--button-danger-color,#fff);background:#ee0a24;background:var(--button-danger-background-color,#ee0a24);border:1px solid #ee0a24;border:var(--button-border-width,1px) solid var(--button-danger-border-color,#ee0a24)}.van-button--warning{color:#fff;color:var(--button-warning-color,#fff);background:#ff976a;background:var(--button-warning-background-color,#ff976a);border:1px solid #ff976a;border:var(--button-border-width,1px) solid var(--button-warning-border-color,#ff976a)}.van-button--plain{background:#fff;background:var(--button-plain-background-color,#fff)}.van-button--plain.van-button--primary{color:#07c160;color:var(--button-primary-background-color,#07c160)}.van-button--plain.van-button--info{color:#1989fa;color:var(--button-info-background-color,#1989fa)}.van-button--plain.van-button--danger{color:#ee0a24;color:var(--button-danger-background-color,#ee0a24)}.van-button--plain.van-button--warning{color:#ff976a;color:var(--button-warning-background-color,#ff976a)}.van-button--large{width:100%;height:50px;height:var(--button-large-height,50px)}.van-button--normal{padding:0 15px;font-size:14px;font-size:var(--button-normal-font-size,14px)}.van-button--small{min-width:60px;min-width:var(--button-small-min-width,60px);height:30px;height:var(--button-small-height,30px);padding:0 8px;padding:0 var(--padding-xs,8px);font-size:12px;font-size:var(--button-small-font-size,12px)}.van-button--mini{display:inline-block;min-width:50px;min-width:var(--button-mini-min-width,50px);height:22px;height:var(--button-mini-height,22px);font-size:10px;font-size:var(--button-mini-font-size,10px)}.van-button--mini+.van-button--mini{margin-left:5px}.van-button--block{display:flex;width:100%}.van-button--round{border-radius:999px;border-radius:var(--button-round-border-radius,999px)}.van-button--square{border-radius:0}.van-button--disabled{opacity:.5;opacity:var(--button-disabled-opacity,.5)}.van-button__text{display:inline}.van-button__icon+.van-button__text:not(:empty),.van-button__loading-text{margin-left:4px}.van-button__icon{min-width:1em;line-height:inherit!important;vertical-align:top}.van-button--hairline{padding-top:1px;border-width:0}.van-button--hairline:after{border-color:inherit;border-width:1px;border-radius:4px;border-radius:calc(var(--button-border-radius, 2px)*2)}.van-button--hairline.van-button--round:after{border-radius:999px;border-radius:var(--button-round-border-radius,999px)}.van-button--hairline.van-button--square:after{border-radius:0}

View File

@ -0,0 +1,68 @@
<view class="van-calendar">
<header
title="{{ title }}"
showTitle="{{ showTitle }}"
subtitle="{{ subtitle }}"
showSubtitle="{{ showSubtitle }}"
firstDayOfWeek="{{ firstDayOfWeek }}"
bind:click-subtitle="onClickSubtitle"
>
<slot name="title" slot="title"></slot>
</header>
<scroll-view
class="van-calendar__body"
scroll-y
scroll-into-view="{{ scrollIntoView }}"
>
<month
wx:for="{{ computed.getMonths(minDate, maxDate) }}"
wx:key="index"
id="month{{ index }}"
class="month"
data-date="{{ item }}"
date="{{ item }}"
type="{{ type }}"
color="{{ color }}"
minDate="{{ minDate }}"
maxDate="{{ maxDate }}"
showMark="{{ showMark }}"
formatter="{{ formatter }}"
rowHeight="{{ rowHeight }}"
currentDate="{{ currentDate }}"
showSubtitle="{{ showSubtitle }}"
allowSameDay="{{ allowSameDay }}"
showMonthTitle="{{ index !== 0 || !showSubtitle }}"
firstDayOfWeek="{{ firstDayOfWeek }}"
bind:click="onClickDay"
/>
</scroll-view>
<view
class="{{ utils.bem('calendar__footer', { safeAreaInsetBottom }) }}"
>
<slot name="footer"></slot>
</view>
<view
class="{{ utils.bem('calendar__footer', { safeAreaInsetBottom }) }}"
>
<van-button
wx:if="{{ showConfirm }}"
round
block
type="danger"
color="{{ color }}"
custom-class="van-calendar__confirm"
disabled="{{ computed.getButtonDisabled(type, currentDate) }}"
nativeType="text"
bind:click="onConfirm"
>
{{
computed.getButtonDisabled(type, currentDate)
? confirmDisabledText
: confirmText
}}
</van-button>
</view>
</view>

View File

@ -0,0 +1,46 @@
'use strict';
var __spreadArray =
(this && this.__spreadArray) ||
function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
Object.defineProperty(exports, '__esModule', { value: true });
var component_1 = require('../../../common/component');
component_1.VantComponent({
props: {
title: {
type: String,
value: '日期选择',
},
subtitle: String,
showTitle: Boolean,
showSubtitle: Boolean,
firstDayOfWeek: {
type: Number,
observer: 'initWeekDay',
},
},
data: {
weekdays: [],
},
created: function () {
this.initWeekDay();
},
methods: {
initWeekDay: function () {
var defaultWeeks = ['日', '一', '二', '三', '四', '五', '六'];
var firstDayOfWeek = this.data.firstDayOfWeek || 0;
this.setData({
weekdays: __spreadArray(
__spreadArray([], defaultWeeks.slice(firstDayOfWeek, 7)),
defaultWeeks.slice(0, firstDayOfWeek)
),
});
},
onClickSubtitle: function (event) {
this.$emit('click-subtitle', event);
},
},
});

View File

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

View File

@ -0,0 +1,16 @@
<view class="van-calendar__header">
<block wx:if="{{ showTitle }}">
<view class="van-calendar__header-title"><slot name="title"></slot></view>
<view class="van-calendar__header-title">{{ title }}</view>
</block>
<view wx:if="{{ showSubtitle }}" class="van-calendar__header-subtitle" bind:tap="onClickSubtitle">
{{ subtitle }}
</view>
<view class="van-calendar__weekdays">
<view wx:for="{{ weekdays }}" wx:key="index" class="van-calendar__weekday">
{{ item }}
</view>
</view>
</view>

View File

@ -0,0 +1 @@
@import '../../../common/index.wxss';.van-calendar__header{flex-shrink:0;box-shadow:0 2px 10px rgba(125,126,128,.16);box-shadow:var(--calendar-header-box-shadow,0 2px 10px rgba(125,126,128,.16))}.van-calendar__header-subtitle,.van-calendar__header-title{text-align:center;height:44px;height:var(--calendar-header-title-height,44px);font-weight:500;font-weight:var(--font-weight-bold,500);line-height:44px;line-height:var(--calendar-header-title-height,44px)}.van-calendar__header-title+.van-calendar__header-title,.van-calendar__header-title:empty{display:none}.van-calendar__header-title:empty+.van-calendar__header-title{display:block!important}.van-calendar__weekdays{display:flex}.van-calendar__weekday{flex:1;text-align:center;font-size:12px;font-size:var(--calendar-weekdays-font-size,12px);line-height:30px;line-height:var(--calendar-weekdays-height,30px)}

View File

@ -0,0 +1,173 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var component_1 = require('../../../common/component');
var utils_1 = require('../../utils');
component_1.VantComponent({
props: {
date: {
type: null,
observer: 'setDays',
},
type: {
type: String,
observer: 'setDays',
},
color: String,
minDate: {
type: null,
observer: 'setDays',
},
maxDate: {
type: null,
observer: 'setDays',
},
showMark: Boolean,
rowHeight: null,
formatter: {
type: null,
observer: 'setDays',
},
currentDate: {
type: null,
observer: 'setDays',
},
firstDayOfWeek: {
type: Number,
observer: 'setDays',
},
allowSameDay: Boolean,
showSubtitle: Boolean,
showMonthTitle: Boolean,
},
data: {
visible: true,
days: [],
},
methods: {
onClick: function (event) {
var index = event.currentTarget.dataset.index;
var item = this.data.days[index];
if (item.type !== 'disabled') {
this.$emit('click', item);
}
},
setDays: function () {
var days = [];
var startDate = new Date(this.data.date);
var year = startDate.getFullYear();
var month = startDate.getMonth();
var totalDay = utils_1.getMonthEndDay(
startDate.getFullYear(),
startDate.getMonth() + 1
);
for (var day = 1; day <= totalDay; day++) {
var date = new Date(year, month, day);
var type = this.getDayType(date);
var config = {
date: date,
type: type,
text: day,
bottomInfo: this.getBottomInfo(type),
};
if (this.data.formatter) {
config = this.data.formatter(config);
}
days.push(config);
}
this.setData({ days: days });
},
getMultipleDayType: function (day) {
var currentDate = this.data.currentDate;
if (!Array.isArray(currentDate)) {
return '';
}
var isSelected = function (date) {
return currentDate.some(function (item) {
return utils_1.compareDay(item, date) === 0;
});
};
if (isSelected(day)) {
var prevDay = utils_1.getPrevDay(day);
var nextDay = utils_1.getNextDay(day);
var prevSelected = isSelected(prevDay);
var nextSelected = isSelected(nextDay);
if (prevSelected && nextSelected) {
return 'multiple-middle';
}
if (prevSelected) {
return 'end';
}
return nextSelected ? 'start' : 'multiple-selected';
}
return '';
},
getRangeDayType: function (day) {
var _a = this.data,
currentDate = _a.currentDate,
allowSameDay = _a.allowSameDay;
if (!Array.isArray(currentDate)) {
return '';
}
var startDay = currentDate[0],
endDay = currentDate[1];
if (!startDay) {
return '';
}
var compareToStart = utils_1.compareDay(day, startDay);
if (!endDay) {
return compareToStart === 0 ? 'start' : '';
}
var compareToEnd = utils_1.compareDay(day, endDay);
if (compareToStart === 0 && compareToEnd === 0 && allowSameDay) {
return 'start-end';
}
if (compareToStart === 0) {
return 'start';
}
if (compareToEnd === 0) {
return 'end';
}
if (compareToStart > 0 && compareToEnd < 0) {
return 'middle';
}
return '';
},
getDayType: function (day) {
var _a = this.data,
type = _a.type,
minDate = _a.minDate,
maxDate = _a.maxDate,
currentDate = _a.currentDate;
if (
utils_1.compareDay(day, minDate) < 0 ||
utils_1.compareDay(day, maxDate) > 0
) {
return 'disabled';
}
if (type === 'single') {
return utils_1.compareDay(day, currentDate) === 0 ? 'selected' : '';
}
if (type === 'multiple') {
return this.getMultipleDayType(day);
}
/* istanbul ignore else */
if (type === 'range') {
return this.getRangeDayType(day);
}
return '';
},
getBottomInfo: function (type) {
if (this.data.type === 'range') {
if (type === 'start') {
return '开始';
}
if (type === 'end') {
return '结束';
}
if (type === 'start-end') {
return '开始/结束';
}
}
},
},
});

View File

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

View File

@ -0,0 +1,39 @@
<wxs src="./index.wxs" module="computed"></wxs>
<wxs src="../../../wxs/utils.wxs" module="utils" />
<view class="van-calendar__month" style="{{ computed.getMonthStyle(visible, date, rowHeight) }}">
<view wx:if="{{ showMonthTitle }}" class="van-calendar__month-title">
{{ computed.formatMonthTitle(date) }}
</view>
<view wx:if="{{ visible }}" class="van-calendar__days">
<view wx:if="{{ showMark }}" class="van-calendar__month-mark">
{{ computed.getMark(date) }}
</view>
<view
wx:for="{{ days }}"
wx:key="index"
style="{{ computed.getDayStyle(item.type, index, date, rowHeight, color, firstDayOfWeek) }}"
class="{{ utils.bem('calendar__day', [item.type]) }} {{ item.className }}"
data-index="{{ index }}"
bindtap="onClick"
>
<view wx:if="{{ item.type === 'selected' }}" class="van-calendar__selected-day" style="background: {{ color }}">
<view wx:if="{{ item.topInfo }}" class="van-calendar__top-info">{{ item.topInfo }}</view>
{{ item.text }}
<view wx:if="{{ item.bottomInfo }}" class="van-calendar__bottom-info">
{{ item.bottomInfo }}
</view>
</view>
<view wx:else>
<view wx:if="{{ item.topInfo }}" class="van-calendar__top-info">{{ item.topInfo }}</view>
{{ item.text }}
<view wx:if="{{ item.bottomInfo }}" class="van-calendar__bottom-info">
{{ item.bottomInfo }}
</view>
</view>
</view>
</view>
</view>

View File

@ -0,0 +1,71 @@
/* eslint-disable */
var utils = require('../../utils.wxs');
function getMark(date) {
return getDate(date).getMonth() + 1;
}
var ROW_HEIGHT = 64;
function getDayStyle(type, index, date, rowHeight, color, firstDayOfWeek) {
var style = [];
var current = getDate(date).getDay() || 7;
var offset = current < firstDayOfWeek ? (7 - firstDayOfWeek + current) :
current === 7 && firstDayOfWeek === 0 ? 0 :
(current - firstDayOfWeek);
if (index === 0) {
style.push(['margin-left', (100 * offset) / 7 + '%']);
}
if (rowHeight !== ROW_HEIGHT) {
style.push(['height', rowHeight + 'px']);
}
if (color) {
if (
type === 'start' ||
type === 'end' ||
type === 'start-end' ||
type === 'multiple-selected' ||
type === 'multiple-middle'
) {
style.push(['background', color]);
} else if (type === 'middle') {
style.push(['color', color]);
}
}
return style
.map(function(item) {
return item.join(':');
})
.join(';');
}
function formatMonthTitle(date) {
date = getDate(date);
return date.getFullYear() + '年' + (date.getMonth() + 1) + '月';
}
function getMonthStyle(visible, date, rowHeight) {
if (!visible) {
date = getDate(date);
var totalDay = utils.getMonthEndDay(
date.getFullYear(),
date.getMonth() + 1
);
var offset = getDate(date).getDay();
var padding = Math.ceil((totalDay + offset) / 7) * rowHeight;
return 'padding-bottom:' + padding + 'px';
}
}
module.exports = {
getMark: getMark,
getDayStyle: getDayStyle,
formatMonthTitle: formatMonthTitle,
getMonthStyle: getMonthStyle
};

View File

@ -0,0 +1 @@
@import '../../../common/index.wxss';.van-calendar{display:flex;flex-direction:column;height:100%;background-color:#fff;background-color:var(--calendar-background-color,#fff)}.van-calendar__month-title{text-align:center;height:44px;height:var(--calendar-header-title-height,44px);font-weight:500;font-weight:var(--font-weight-bold,500);font-size:14px;font-size:var(--calendar-month-title-font-size,14px);line-height:44px;line-height:var(--calendar-header-title-height,44px)}.van-calendar__days{position:relative;display:flex;flex-wrap:wrap;-webkit-user-select:none;user-select:none}.van-calendar__month-mark{position:absolute;top:50%;left:50%;z-index:0;transform:translate(-50%,-50%);pointer-events:none;color:rgba(242,243,245,.8);color:var(--calendar-month-mark-color,rgba(242,243,245,.8));font-size:160px;font-size:var(--calendar-month-mark-font-size,160px)}.van-calendar__day,.van-calendar__selected-day{display:flex;align-items:center;justify-content:center;text-align:center}.van-calendar__day{position:relative;width:14.285%;height:64px;height:var(--calendar-day-height,64px);font-size:16px;font-size:var(--calendar-day-font-size,16px)}.van-calendar__day--end,.van-calendar__day--multiple-middle,.van-calendar__day--multiple-selected,.van-calendar__day--start,.van-calendar__day--start-end{color:#fff;color:var(--calendar-range-edge-color,#fff);background-color:#ee0a24;background-color:var(--calendar-range-edge-background-color,#ee0a24)}.van-calendar__day--start{border-radius:4px 0 0 4px;border-radius:var(--border-radius-md,4px) 0 0 var(--border-radius-md,4px)}.van-calendar__day--end{border-radius:0 4px 4px 0;border-radius:0 var(--border-radius-md,4px) var(--border-radius-md,4px) 0}.van-calendar__day--multiple-selected,.van-calendar__day--start-end{border-radius:4px;border-radius:var(--border-radius-md,4px)}.van-calendar__day--middle{color:#ee0a24;color:var(--calendar-range-middle-color,#ee0a24)}.van-calendar__day--middle:after{position:absolute;top:0;right:0;bottom:0;left:0;background-color:currentColor;content:"";opacity:.1;opacity:var(--calendar-range-middle-background-opacity,.1)}.van-calendar__day--disabled{cursor:default;color:#c8c9cc;color:var(--calendar-day-disabled-color,#c8c9cc)}.van-calendar__bottom-info,.van-calendar__top-info{position:absolute;right:0;left:0;font-size:10px;font-size:var(--calendar-info-font-size,10px);line-height:14px;line-height:var(--calendar-info-line-height,14px)}@media (max-width:350px){.van-calendar__bottom-info,.van-calendar__top-info{font-size:9px}}.van-calendar__top-info{top:6px}.van-calendar__bottom-info{bottom:6px}.van-calendar__selected-day{width:54px;width:var(--calendar-selected-day-size,54px);height:54px;height:var(--calendar-selected-day-size,54px);color:#fff;color:var(--calendar-selected-day-color,#fff);background-color:#ee0a24;background-color:var(--calendar-selected-day-background-color,#ee0a24);border-radius:4px;border-radius:var(--border-radius-md,4px)}

View File

@ -0,0 +1,382 @@
'use strict';
var __spreadArray =
(this && this.__spreadArray) ||
function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
var __importDefault =
(this && this.__importDefault) ||
function (mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, '__esModule', { value: true });
var component_1 = require('../common/component');
var utils_1 = require('./utils');
var toast_1 = __importDefault(require('../toast/toast'));
var utils_2 = require('../common/utils');
var initialMinDate = utils_1.getToday().getTime();
var initialMaxDate = (function () {
var now = utils_1.getToday();
return new Date(
now.getFullYear(),
now.getMonth() + 6,
now.getDate()
).getTime();
})();
component_1.VantComponent({
props: {
title: {
type: String,
value: '日期选择',
},
color: String,
show: {
type: Boolean,
observer: function (val) {
if (val) {
this.initRect();
this.scrollIntoView();
}
},
},
formatter: null,
confirmText: {
type: String,
value: '确定',
},
rangePrompt: String,
showRangePrompt: {
type: Boolean,
value: true,
},
defaultDate: {
type: null,
observer: function (val) {
this.setData({ currentDate: val });
this.scrollIntoView();
},
},
allowSameDay: Boolean,
confirmDisabledText: String,
type: {
type: String,
value: 'single',
observer: 'reset',
},
minDate: {
type: null,
value: initialMinDate,
},
maxDate: {
type: null,
value: initialMaxDate,
},
position: {
type: String,
value: 'bottom',
},
rowHeight: {
type: null,
value: utils_1.ROW_HEIGHT,
},
round: {
type: Boolean,
value: true,
},
poppable: {
type: Boolean,
value: true,
},
showMark: {
type: Boolean,
value: true,
},
showTitle: {
type: Boolean,
value: true,
},
showConfirm: {
type: Boolean,
value: true,
},
showSubtitle: {
type: Boolean,
value: true,
},
safeAreaInsetBottom: {
type: Boolean,
value: true,
},
closeOnClickOverlay: {
type: Boolean,
value: true,
},
maxRange: {
type: null,
value: null,
},
firstDayOfWeek: {
type: Number,
value: 0,
},
},
data: {
subtitle: '',
currentDate: null,
scrollIntoView: '',
},
created: function () {
this.setData({
currentDate: this.getInitialDate(),
});
},
mounted: function () {
if (this.data.show || !this.data.poppable) {
this.initRect();
this.scrollIntoView();
}
},
methods: {
reset: function () {
this.setData({ currentDate: this.getInitialDate() });
this.scrollIntoView();
},
initRect: function () {
var _this = this;
if (this.contentObserver != null) {
this.contentObserver.disconnect();
}
var contentObserver = this.createIntersectionObserver({
thresholds: [0, 0.1, 0.9, 1],
observeAll: true,
});
this.contentObserver = contentObserver;
contentObserver.relativeTo('.van-calendar__body');
contentObserver.observe('.month', function (res) {
if (res.boundingClientRect.top <= res.relativeRect.top) {
// @ts-ignore
_this.setData({
subtitle: utils_1.formatMonthTitle(res.dataset.date),
});
}
});
},
limitDateRange: function (date, minDate, maxDate) {
if (minDate === void 0) {
minDate = null;
}
if (maxDate === void 0) {
maxDate = null;
}
minDate = minDate || this.data.minDate;
maxDate = maxDate || this.data.maxDate;
if (utils_1.compareDay(date, minDate) === -1) {
return minDate;
}
if (utils_1.compareDay(date, maxDate) === 1) {
return maxDate;
}
return date;
},
getInitialDate: function (defaultDate) {
var _this = this;
if (defaultDate === void 0) {
defaultDate = null;
}
var _a = this.data,
type = _a.type,
minDate = _a.minDate,
maxDate = _a.maxDate;
var now = utils_1.getToday().getTime();
if (type === 'range') {
if (!Array.isArray(defaultDate)) {
defaultDate = [];
}
var _b = defaultDate || [],
startDay = _b[0],
endDay = _b[1];
var start = this.limitDateRange(
startDay || now,
minDate,
utils_1.getPrevDay(maxDate).getTime()
);
var end = this.limitDateRange(
endDay || now,
utils_1.getNextDay(minDate).getTime()
);
return [start, end];
}
if (type === 'multiple') {
if (Array.isArray(defaultDate)) {
return defaultDate.map(function (date) {
return _this.limitDateRange(date);
});
}
return [this.limitDateRange(now)];
}
if (!defaultDate || Array.isArray(defaultDate)) {
defaultDate = now;
}
return this.limitDateRange(defaultDate);
},
scrollIntoView: function () {
var _this = this;
utils_2.requestAnimationFrame(function () {
var _a = _this.data,
currentDate = _a.currentDate,
type = _a.type,
show = _a.show,
poppable = _a.poppable,
minDate = _a.minDate,
maxDate = _a.maxDate;
// @ts-ignore
var targetDate = type === 'single' ? currentDate : currentDate[0];
var displayed = show || !poppable;
if (!targetDate || !displayed) {
return;
}
var months = utils_1.getMonths(minDate, maxDate);
months.some(function (month, index) {
if (utils_1.compareMonth(month, targetDate) === 0) {
_this.setData({ scrollIntoView: 'month' + index });
return true;
}
return false;
});
});
},
onOpen: function () {
this.$emit('open');
},
onOpened: function () {
this.$emit('opened');
},
onClose: function () {
this.$emit('close');
},
onClosed: function () {
this.$emit('closed');
},
onClickDay: function (event) {
var date = event.detail.date;
var _a = this.data,
type = _a.type,
currentDate = _a.currentDate,
allowSameDay = _a.allowSameDay;
if (type === 'range') {
// @ts-ignore
var startDay = currentDate[0],
endDay = currentDate[1];
if (startDay && !endDay) {
var compareToStart = utils_1.compareDay(date, startDay);
if (compareToStart === 1) {
this.select([startDay, date], true);
} else if (compareToStart === -1) {
this.select([date, null]);
} else if (allowSameDay) {
this.select([date, date]);
}
} else {
this.select([date, null]);
}
} else if (type === 'multiple') {
var selectedIndex_1;
// @ts-ignore
var selected = currentDate.some(function (dateItem, index) {
var equal = utils_1.compareDay(dateItem, date) === 0;
if (equal) {
selectedIndex_1 = index;
}
return equal;
});
if (selected) {
// @ts-ignore
var cancelDate = currentDate.splice(selectedIndex_1, 1);
this.setData({ currentDate: currentDate });
this.unselect(cancelDate);
} else {
// @ts-ignore
this.select(__spreadArray(__spreadArray([], currentDate), [date]));
}
} else {
this.select(date, true);
}
},
unselect: function (dateArray) {
var date = dateArray[0];
if (date) {
this.$emit('unselect', utils_1.copyDates(date));
}
},
select: function (date, complete) {
if (complete && this.data.type === 'range') {
var valid = this.checkRange(date);
if (!valid) {
// auto selected to max range if showConfirm
if (this.data.showConfirm) {
this.emit([
date[0],
utils_1.getDayByOffset(date[0], this.data.maxRange - 1),
]);
} else {
this.emit(date);
}
return;
}
}
this.emit(date);
if (complete && !this.data.showConfirm) {
this.onConfirm();
}
},
emit: function (date) {
var getTime = function (date) {
return date instanceof Date ? date.getTime() : date;
};
this.setData({
currentDate: Array.isArray(date) ? date.map(getTime) : getTime(date),
});
this.$emit('select', utils_1.copyDates(date));
},
checkRange: function (date) {
var _a = this.data,
maxRange = _a.maxRange,
rangePrompt = _a.rangePrompt,
showRangePrompt = _a.showRangePrompt;
if (maxRange && utils_1.calcDateNum(date) > maxRange) {
if (showRangePrompt) {
toast_1.default({
duration: 0,
context: this,
message:
rangePrompt ||
'\u9009\u62E9\u5929\u6570\u4E0D\u80FD\u8D85\u8FC7 ' +
maxRange +
' \u5929',
});
}
this.$emit('over-range');
return false;
}
return true;
},
onConfirm: function () {
var _this = this;
if (
this.data.type === 'range' &&
!this.checkRange(this.data.currentDate)
) {
return;
}
wx.nextTick(function () {
// @ts-ignore
_this.$emit('confirm', utils_1.copyDates(_this.data.currentDate));
});
},
onClickSubtitle: function (event) {
this.$emit('click-subtitle', event);
},
},
});

View File

@ -0,0 +1,10 @@
{
"component": true,
"usingComponents": {
"header": "./components/header/index",
"month": "./components/month/index",
"van-button": "../button/index",
"van-popup": "../popup/index",
"van-toast": "../toast/index"
}
}

View File

@ -0,0 +1,25 @@
<wxs src="./index.wxs" module="computed" />
<wxs src="../wxs/utils.wxs" module="utils" />
<import src="./calendar.wxml" />
<van-popup
wx:if="{{ poppable }}"
custom-class="van-calendar__popup--{{ position }}"
close-icon-class="van-calendar__close-icon"
show="{{ show }}"
round="{{ round }}"
position="{{ position }}"
closeable="{{ showTitle || showSubtitle }}"
close-on-click-overlay="{{ closeOnClickOverlay }}"
bind:enter="onOpen"
bind:close="onClose"
bind:after-enter="onOpened"
bind:after-leave="onClosed"
>
<include src="./calendar.wxml" />
</van-popup>
<include wx:else src="./calendar.wxml" />
<van-toast id="van-toast" />

View File

@ -0,0 +1,37 @@
/* eslint-disable */
var utils = require('./utils.wxs');
function getMonths(minDate, maxDate) {
var months = [];
var cursor = getDate(minDate);
cursor.setDate(1);
do {
months.push(cursor.getTime());
cursor.setMonth(cursor.getMonth() + 1);
} while (utils.compareMonth(cursor, getDate(maxDate)) !== 1);
return months;
}
function getButtonDisabled(type, currentDate) {
if (currentDate == null) {
return true;
}
if (type === 'range') {
return !currentDate[0] || !currentDate[1];
}
if (type === 'multiple') {
return !currentDate.length;
}
return !currentDate;
}
module.exports = {
getMonths: getMonths,
getButtonDisabled: getButtonDisabled
};

View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-calendar{display:flex;flex-direction:column;height:100%;height:var(--calendar-height,100%);background-color:#fff;background-color:var(--calendar-background-color,#fff)}.van-calendar__close-icon{top:11px}.van-calendar__popup--bottom,.van-calendar__popup--top{height:80%;height:var(--calendar-popup-height,80%)}.van-calendar__popup--left,.van-calendar__popup--right{height:100%}.van-calendar__body{flex:1;overflow:auto;-webkit-overflow-scrolling:touch}.van-calendar__footer{flex-shrink:0;padding:0 16px;padding:0 var(--padding-md,16px)}.van-calendar__footer--safe-area-inset-bottom{padding-bottom:env(safe-area-inset-bottom)}.van-calendar__footer+.van-calendar__footer,.van-calendar__footer:empty{display:none}.van-calendar__footer:empty+.van-calendar__footer{display:block!important}.van-calendar__confirm{height:36px!important;height:var(--calendar-confirm-button-height,36px)!important;margin:7px 0!important;margin:var(--calendar-confirm-button-margin,7px 0)!important;line-height:34px!important;line-height:var(--calendar-confirm-button-line-height,34px)!important}

View File

@ -0,0 +1,97 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.getMonths = exports.getMonthEndDay = exports.copyDates = exports.calcDateNum = exports.getToday = exports.getNextDay = exports.getPrevDay = exports.getDayByOffset = exports.compareDay = exports.compareMonth = exports.formatMonthTitle = exports.ROW_HEIGHT = void 0;
exports.ROW_HEIGHT = 64;
function formatMonthTitle(date) {
if (!(date instanceof Date)) {
date = new Date(date);
}
return date.getFullYear() + '\u5E74' + (date.getMonth() + 1) + '\u6708';
}
exports.formatMonthTitle = formatMonthTitle;
function compareMonth(date1, date2) {
if (!(date1 instanceof Date)) {
date1 = new Date(date1);
}
if (!(date2 instanceof Date)) {
date2 = new Date(date2);
}
var year1 = date1.getFullYear();
var year2 = date2.getFullYear();
var month1 = date1.getMonth();
var month2 = date2.getMonth();
if (year1 === year2) {
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1;
}
return year1 > year2 ? 1 : -1;
}
exports.compareMonth = compareMonth;
function compareDay(day1, day2) {
if (!(day1 instanceof Date)) {
day1 = new Date(day1);
}
if (!(day2 instanceof Date)) {
day2 = new Date(day2);
}
var compareMonthResult = compareMonth(day1, day2);
if (compareMonthResult === 0) {
var date1 = day1.getDate();
var date2 = day2.getDate();
return date1 === date2 ? 0 : date1 > date2 ? 1 : -1;
}
return compareMonthResult;
}
exports.compareDay = compareDay;
function getDayByOffset(date, offset) {
date = new Date(date);
date.setDate(date.getDate() + offset);
return date;
}
exports.getDayByOffset = getDayByOffset;
function getPrevDay(date) {
return getDayByOffset(date, -1);
}
exports.getPrevDay = getPrevDay;
function getNextDay(date) {
return getDayByOffset(date, 1);
}
exports.getNextDay = getNextDay;
function getToday() {
var today = new Date();
today.setHours(0, 0, 0, 0);
return today;
}
exports.getToday = getToday;
function calcDateNum(date) {
var day1 = new Date(date[0]).getTime();
var day2 = new Date(date[1]).getTime();
return (day2 - day1) / (1000 * 60 * 60 * 24) + 1;
}
exports.calcDateNum = calcDateNum;
function copyDates(dates) {
if (Array.isArray(dates)) {
return dates.map(function (date) {
if (date === null) {
return date;
}
return new Date(date);
});
}
return new Date(dates);
}
exports.copyDates = copyDates;
function getMonthEndDay(year, month) {
return 32 - new Date(year, month - 1, 32).getDate();
}
exports.getMonthEndDay = getMonthEndDay;
function getMonths(minDate, maxDate) {
var months = [];
var cursor = new Date(minDate);
cursor.setDate(1);
do {
months.push(cursor.getTime());
cursor.setMonth(cursor.getMonth() + 1);
} while (compareMonth(cursor, maxDate) !== 1);
return months;
}
exports.getMonths = getMonths;

View File

@ -0,0 +1,25 @@
/* eslint-disable */
function getMonthEndDay(year, month) {
return 32 - getDate(year, month - 1, 32).getDate();
}
function compareMonth(date1, date2) {
date1 = getDate(date1);
date2 = getDate(date2);
var year1 = date1.getFullYear();
var year2 = date2.getFullYear();
var month1 = date1.getMonth();
var month2 = date2.getMonth();
if (year1 === year2) {
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1;
}
return year1 > year2 ? 1 : -1;
}
module.exports = {
getMonthEndDay: getMonthEndDay,
compareMonth: compareMonth
};

View File

@ -0,0 +1,51 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var link_1 = require('../mixins/link');
var component_1 = require('../common/component');
component_1.VantComponent({
classes: [
'num-class',
'desc-class',
'thumb-class',
'title-class',
'price-class',
'origin-price-class',
],
mixins: [link_1.link],
props: {
tag: String,
num: String,
desc: String,
thumb: String,
title: String,
price: {
type: String,
observer: 'updatePrice',
},
centered: Boolean,
lazyLoad: Boolean,
thumbLink: String,
originPrice: String,
thumbMode: {
type: String,
value: 'aspectFit',
},
currency: {
type: String,
value: '¥',
},
},
methods: {
updatePrice: function () {
var price = this.data.price;
var priceArr = price.toString().split('.');
this.setData({
integerStr: priceArr[0],
decimalStr: priceArr[1] ? '.' + priceArr[1] : '',
});
},
onClickThumb: function () {
this.jumpLink('thumbLink');
},
},
});

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"van-tag": "../tag/index"
}
}

View File

@ -0,0 +1,56 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view class="custom-class van-card">
<view class="{{ utils.bem('card__header', { center: centered }) }}">
<view class="van-card__thumb" bind:tap="onClickThumb">
<image
wx:if="{{ thumb }}"
src="{{ thumb }}"
mode="{{ thumbMode }}"
lazy-load="{{ lazyLoad }}"
class="van-card__img thumb-class"
/>
<slot wx:else name="thumb" />
<van-tag
wx:if="{{ tag }}"
mark
type="danger"
custom-class="van-card__tag"
>
{{ tag }}
</van-tag>
<slot wx:else name="tag" />
</view>
<view class="van-card__content {{ utils.bem('card__content', { center: centered }) }}">
<view>
<view wx:if="{{ title }}" class="van-card__title title-class">{{ title }}</view>
<slot wx:else name="title" />
<view wx:if="{{ desc }}" class="van-card__desc desc-class">{{ desc }}</view>
<slot wx:else name="desc" />
<slot name="tags" />
</view>
<view class="van-card__bottom">
<slot name="price-top" />
<view wx:if="{{ price || price === 0 }}" class="van-card__price price-class">
<text>{{ currency }}</text>
<text class="van-card__price-integer">{{ integerStr }}</text>
<text class="van-card__price-decimal">{{ decimalStr }}</text>
</view>
<slot wx:else name="price" />
<view wx:if="{{ originPrice || originPrice === 0 }}" class="van-card__origin-price origin-price-class">{{ currency }} {{ originPrice }}</view>
<slot wx:else name="origin-price" />
<view wx:if="{{ num }}" class="van-card__num num-class">x {{ num }}</view>
<slot wx:else name="num" />
<slot name="bottom" />
</view>
</view>
</view>
<view class="van-card__footer">
<slot name="footer" />
</view>
</view>

View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-card{position:relative;box-sizing:border-box;padding:8px 16px;padding:var(--card-padding,8px 16px);font-size:12px;font-size:var(--card-font-size,12px);color:#323233;color:var(--card-text-color,#323233);background-color:#fafafa;background-color:var(--card-background-color,#fafafa)}.van-card__header{display:flex}.van-card__header--center{align-items:center;justify-content:center}.van-card__thumb{position:relative;flex:none;width:88px;width:var(--card-thumb-size,88px);height:88px;height:var(--card-thumb-size,88px);margin-right:8px;margin-right:var(--padding-xs,8px)}.van-card__thumb:empty{display:none}.van-card__img{width:100%;height:100%;border-radius:8px;border-radius:var(--border-radius-lg,8px)}.van-card__content{position:relative;display:flex;flex:1;flex-direction:column;justify-content:space-between;min-width:0;min-height:88px;min-height:var(--card-thumb-size,88px)}.van-card__content--center{justify-content:center}.van-card__desc,.van-card__title{word-wrap:break-word}.van-card__title{font-weight:700;line-height:16px;line-height:var(--card-title-line-height,16px)}.van-card__desc{line-height:20px;line-height:var(--card-desc-line-height,20px);color:#646566;color:var(--card-desc-color,#646566)}.van-card__bottom{line-height:20px}.van-card__price{display:inline-block;font-weight:700;color:#ee0a24;color:var(--card-price-color,#ee0a24);font-size:12px;font-size:var(--card-price-font-size,12px)}.van-card__price-integer{font-size:16px;font-size:var(--card-price-integer-font-size,16px)}.van-card__price-decimal,.van-card__price-integer{font-family:Avenir-Heavy,PingFang SC,Helvetica Neue,Arial,sans-serif;font-family:var(--card-price-font-family,Avenir-Heavy,PingFang SC,Helvetica Neue,Arial,sans-serif)}.van-card__origin-price{display:inline-block;margin-left:5px;text-decoration:line-through;font-size:10px;font-size:var(--card-origin-price-font-size,10px);color:#646566;color:var(--card-origin-price-color,#646566)}.van-card__num{float:right}.van-card__tag{position:absolute!important;top:2px;left:0}.van-card__footer{flex:none;width:100%;text-align:right}

View File

@ -0,0 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var component_1 = require('../common/component');
component_1.VantComponent({
props: {
title: String,
border: {
type: Boolean,
value: true,
},
inset: Boolean,
},
});

View File

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

View File

@ -0,0 +1,11 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view
wx:if="{{ title }}"
class="{{ utils.bem('cell-group__title', { inset }) }}"
>
{{ title }}
</view>
<view class="custom-class {{ utils.bem('cell-group', { inset }) }} {{ border ? 'van-hairline--top-bottom' : '' }}">
<slot />
</view>

View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-cell-group--inset{margin:0 16px;margin:var(--cell-group-inset-padding,0 16px);border-radius:8px;border-radius:var(--cell-group-inset-border-radius,8px);overflow:hidden}.van-cell-group__title{padding:16px 16px 8px;padding:var(--cell-group-title-padding,16px 16px 8px);font-size:14px;font-size:var(--cell-group-title-font-size,14px);line-height:16px;line-height:var(--cell-group-title-line-height,16px);color:#969799;color:var(--cell-group-title-color,#969799)}.van-cell-group__title--inset{padding:16px 16px 8px 32px;padding:var(--cell-group-inset-title-padding,16px 16px 8px 32px)}

View File

@ -0,0 +1,40 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var link_1 = require('../mixins/link');
var component_1 = require('../common/component');
component_1.VantComponent({
classes: [
'title-class',
'label-class',
'value-class',
'right-icon-class',
'hover-class',
],
mixins: [link_1.link],
props: {
title: null,
value: null,
icon: String,
size: String,
label: String,
center: Boolean,
isLink: Boolean,
required: Boolean,
clickable: Boolean,
titleWidth: String,
customStyle: String,
arrowDirection: String,
useLabelSlot: Boolean,
border: {
type: Boolean,
value: true,
},
titleStyle: String,
},
methods: {
onClick: function (event) {
this.$emit('click', event.detail);
this.jumpLink();
},
},
});

View File

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

View File

@ -0,0 +1,47 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<wxs src="./index.wxs" module="computed" />
<view
class="custom-class {{ utils.bem('cell', [size, { center, required, borderless: !border, clickable: isLink || clickable }]) }}"
hover-class="van-cell--hover hover-class"
hover-stay-time="70"
style="{{ customStyle }}"
bind:tap="onClick"
>
<van-icon
wx:if="{{ icon }}"
name="{{ icon }}"
class="van-cell__left-icon-wrap"
custom-class="van-cell__left-icon"
/>
<slot wx:else name="icon" />
<view
style="{{ computed.titleStyle({ titleWidth, titleStyle }) }}"
class="van-cell__title title-class"
>
<block wx:if="{{ title }}">{{ title }}</block>
<slot wx:else name="title" />
<view wx:if="{{ label || useLabelSlot }}" class="van-cell__label label-class">
<slot wx:if="{{ useLabelSlot }}" name="label" />
<block wx:elif="{{ label }}">{{ label }}</block>
</view>
</view>
<view class="van-cell__value value-class">
<block wx:if="{{ value || value === 0 }}">{{ value }}</block>
<slot wx:else />
</view>
<van-icon
wx:if="{{ isLink }}"
name="{{ arrowDirection ? 'arrow' + '-' + arrowDirection : 'arrow' }}"
class="van-cell__right-icon-wrap right-icon-class"
custom-class="van-cell__right-icon"
/>
<slot wx:else name="right-icon" />
<slot name="extra" />
</view>

View File

@ -0,0 +1,17 @@
/* eslint-disable */
var style = require('../wxs/style.wxs');
var addUnit = require('../wxs/add-unit.wxs');
function titleStyle(data) {
return style([
{
'max-width': addUnit(data.titleWidth),
'min-width': addUnit(data.titleWidth),
},
data.titleStyle,
]);
}
module.exports = {
titleStyle: titleStyle,
};

View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-cell{position:relative;display:flex;box-sizing:border-box;width:100%;padding:10px 16px;padding:var(--cell-vertical-padding,10px) var(--cell-horizontal-padding,16px);font-size:14px;font-size:var(--cell-font-size,14px);line-height:24px;line-height:var(--cell-line-height,24px);color:#323233;color:var(--cell-text-color,#323233);background-color:#fff;background-color:var(--cell-background-color,#fff)}.van-cell:after{position:absolute;box-sizing:border-box;transform-origin:center;content:" ";pointer-events:none;right:16px;bottom:0;left:16px;border-bottom:1px solid #ebedf0;transform:scaleY(.5)}.van-cell--borderless:after{display:none}.van-cell-group{background-color:#fff;background-color:var(--cell-background-color,#fff)}.van-cell__label{margin-top:3px;margin-top:var(--cell-label-margin-top,3px);font-size:12px;font-size:var(--cell-label-font-size,12px);line-height:18px;line-height:var(--cell-label-line-height,18px);color:#969799;color:var(--cell-label-color,#969799)}.van-cell__value{overflow:hidden;text-align:right;vertical-align:middle;color:#969799;color:var(--cell-value-color,#969799)}.van-cell__title,.van-cell__value{flex:1}.van-cell__title:empty,.van-cell__value:empty{display:none}.van-cell__left-icon-wrap,.van-cell__right-icon-wrap{display:flex;align-items:center;height:24px;height:var(--cell-line-height,24px);font-size:16px;font-size:var(--cell-icon-size,16px)}.van-cell__left-icon-wrap{margin-right:4px;margin-right:var(--padding-base,4px)}.van-cell__right-icon-wrap{margin-left:4px;margin-left:var(--padding-base,4px);color:#969799;color:var(--cell-right-icon-color,#969799)}.van-cell__left-icon{vertical-align:middle}.van-cell__left-icon,.van-cell__right-icon{line-height:24px;line-height:var(--cell-line-height,24px)}.van-cell--clickable.van-cell--hover{background-color:#f2f3f5;background-color:var(--cell-active-color,#f2f3f5)}.van-cell--required{overflow:visible}.van-cell--required:before{position:absolute;content:"*";left:8px;left:var(--padding-xs,8px);font-size:14px;font-size:var(--cell-font-size,14px);color:#ee0a24;color:var(--cell-required-color,#ee0a24)}.van-cell--center{align-items:center}.van-cell--large{padding-top:12px;padding-top:var(--cell-large-vertical-padding,12px);padding-bottom:12px;padding-bottom:var(--cell-large-vertical-padding,12px)}.van-cell--large .van-cell__title{font-size:16px;font-size:var(--cell-large-title-font-size,16px)}.van-cell--large .van-cell__value{font-size:16px;font-size:var(--cell-large-value-font-size,16px)}.van-cell--large .van-cell__label{font-size:14px;font-size:var(--cell-large-label-font-size,14px)}

View File

@ -0,0 +1,44 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var relation_1 = require('../common/relation');
var component_1 = require('../common/component');
component_1.VantComponent({
field: true,
relation: relation_1.useChildren('checkbox', function (target) {
this.updateChild(target);
}),
props: {
max: Number,
value: {
type: Array,
observer: 'updateChildren',
},
disabled: {
type: Boolean,
observer: 'updateChildren',
},
direction: {
type: String,
value: 'vertical',
},
},
methods: {
updateChildren: function () {
var _this = this;
this.children.forEach(function (child) {
return _this.updateChild(child);
});
},
updateChild: function (child) {
var _a = this.data,
value = _a.value,
disabled = _a.disabled,
direction = _a.direction;
child.setData({
value: value.indexOf(child.data.name) !== -1,
parentDisabled: disabled,
direction: direction,
});
},
},
});

View File

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

View File

@ -0,0 +1,5 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<view class="{{ utils.bem('checkbox-group', [{ horizontal: direction === 'horizontal' }]) }}">
<slot />
</view>

View File

@ -0,0 +1 @@
@import '../common/index.wxss';.van-checkbox-group--horizontal{display:flex;flex-wrap:wrap}

View File

@ -0,0 +1,84 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var relation_1 = require('../common/relation');
var component_1 = require('../common/component');
function emit(target, value) {
target.$emit('input', value);
target.$emit('change', value);
}
component_1.VantComponent({
field: true,
relation: relation_1.useParent('checkbox-group'),
classes: ['icon-class', 'label-class'],
props: {
value: Boolean,
disabled: Boolean,
useIconSlot: Boolean,
checkedColor: String,
labelPosition: {
type: String,
value: 'right',
},
labelDisabled: Boolean,
shape: {
type: String,
value: 'round',
},
iconSize: {
type: null,
value: 20,
},
},
data: {
parentDisabled: false,
direction: 'vertical',
},
methods: {
emitChange: function (value) {
if (this.parent) {
this.setParentValue(this.parent, value);
} else {
emit(this, value);
}
},
toggle: function () {
var _a = this.data,
parentDisabled = _a.parentDisabled,
disabled = _a.disabled,
value = _a.value;
if (!disabled && !parentDisabled) {
this.emitChange(!value);
}
},
onClickLabel: function () {
var _a = this.data,
labelDisabled = _a.labelDisabled,
parentDisabled = _a.parentDisabled,
disabled = _a.disabled,
value = _a.value;
if (!disabled && !labelDisabled && !parentDisabled) {
this.emitChange(!value);
}
},
setParentValue: function (parent, value) {
var parentValue = parent.data.value.slice();
var name = this.data.name;
var max = parent.data.max;
if (value) {
if (max && parentValue.length >= max) {
return;
}
if (parentValue.indexOf(name) === -1) {
parentValue.push(name);
emit(parent, parentValue);
}
} else {
var index = parentValue.indexOf(name);
if (index !== -1) {
parentValue.splice(index, 1);
emit(parent, parentValue);
}
}
},
},
});

View File

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

View File

@ -0,0 +1,31 @@
<wxs src="../wxs/utils.wxs" module="utils" />
<wxs src="./index.wxs" module="computed" />
<view class="{{ utils.bem('checkbox', [{ horizontal: direction === 'horizontal' }]) }} custom-class">
<view
wx:if="{{ labelPosition === 'left' }}"
class="label-class {{ utils.bem('checkbox__label', [labelPosition, { disabled: disabled || parentDisabled }]) }}"
bindtap="onClickLabel"
>
<slot />
</view>
<view class="van-checkbox__icon-wrap" bindtap="toggle">
<slot wx:if="{{ useIconSlot }}" name="icon" />
<van-icon
wx:else
name="success"
size="0.8em"
class="{{ utils.bem('checkbox__icon', [shape, { disabled: disabled || parentDisabled, checked: value }]) }}"
style="{{ computed.iconStyle(checkedColor, value, disabled, parentDisabled, iconSize) }}"
custom-class="icon-class"
custom-style="line-height: 1.25em;"
/>
</view>
<view
wx:if="{{ labelPosition === 'right' }}"
class="label-class {{ utils.bem('checkbox__label', [labelPosition, { disabled: disabled || parentDisabled }]) }}"
bindtap="onClickLabel"
>
<slot />
</view>
</view>

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