代码提交

feature/v-xuexi
wangdong 10 months ago
parent 1016002c43
commit a3d92d0421
  1. 3
      api/index.js
  2. 12
      api/user.js
  3. 98
      components/Message/index.vue
  4. 7
      manifest.json
  5. 18
      pages.json
  6. 28
      pages/course/special_cate.vue
  7. 59
      pages/index/index.vue
  8. 185
      pages/index/position.vue
  9. 14
      pages/learning/index.vue
  10. 181
      pages/learningCenter/clockRecord.vue
  11. 335
      pages/learningCenter/components/calendar.vue
  12. 34
      pages/mine/index.vue
  13. 12
      pages/my/noticeDetail.vue
  14. 69
      pages/my/noticeList.vue
  15. 10
      pages/special/details.vue
  16. 104
      pages/special/offlineCourseList.vue
  17. 10
      pages/special/search.vue
  18. 14
      pages/special/specialCateCourse.vue
  19. BIN
      static/images/learning/record-bg.png
  20. BIN
      static/images/message.png

@ -38,3 +38,6 @@ export function agreeMa(params) {
return http.get("/index/agreeMa",params);
}
export function city_list(params) {
return http.get("/index/city_list",params);
}

@ -205,3 +205,15 @@ export function helpCenter(){
export function addFeedback(){
return http.post("/my/addfeedback");
}
export function unReadMsgNum(params) {
return http.get("/my/unReadMsgNum",params);
}
export function setReaded(params) {
return http.get("/my/setReaded",params);
}
export function messageList(params) {
return http.get("/my/messageList",params);
}

@ -0,0 +1,98 @@
<template>
<view v-if="show" class="message-mask">
<view class="message-box">
<image src="@/static/images/message.png" mode="aspectFill"></image>
<view class="box-title">{{ title }}</view>
<view class="box-content">{{ title }}</view>
<view class="box-footer flex">
<view class="btn cancel" @click="show = false">取消</view>
<view class="btn submit" @click="$emit('submit')">确定</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
title: {
type: String,
default: () => '提示',
},
content: {
type: String,
default: () => '请确认当前订单已收货',
},
},
data() {
return {
show: true,
};
},
};
</script>
<style lang="scss" scoped>
.message-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 99;
.message-box {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%);
z-index: 100;
padding: 100rpx 30rpx 60rpx;
background: linear-gradient(to bottom, #BED3FE 0%, #fff 100%);
box-shadow: 0rpx 3rpx 2rpx 0rpx rgba(255,255,255,0.69);
border-radius: 50rpx;
border: 1px solid #FFFFFF;
width: 610rpx;
>image {
position: absolute;
top: -72rpx;
left: 50%;
transform: translateX(-50%);
width: 145rpx;
height: 144rpx;
z-index: 101;
}
.box-title {
color: #333333;
font-size: 34rpx;
text-align: center;
font-weight: bold;
margin-bottom: 30rpx;
}
.box-content {
color: #666;
font-size: 32rpx;
margin-bottom: 40rpx;
text-align: center;
}
.box-footer {
justify-content: space-between;
>view {
width: 230rpx;
height: 88rpx;
background: #EEEEEE;
border-radius: 44rpx;
color: #666;
font-size: 32rpx;
text-align: center;
line-height: 88rpx;
&.submit {
background: linear-gradient(0deg, #0F74BB 0%, #3293FF 100%);
box-shadow: -1rpx -2rpx 0rpx 0rpx rgba(255,255,255,0.51), -1rpx -2rpx 5rpx 0rpx rgba(52,121,253,0.56), 1rpx 3rpx 0rpx 0rpx rgba(250,253,255,0.88);
color: #fff;
}
}
}
}
}
</style>

@ -123,7 +123,12 @@
"minified" : true
},
"usingComponents" : true,
"libVersion" : "latest"
"libVersion" : "latest",
"permission" : {
"scope.userLocation" : {
"desc" : "用于小程序首页位置展示"
}
}
},
"mp-alipay" : {
"usingComponents" : true

@ -96,6 +96,12 @@
"style": {
"navigationBarTitleText": "购物车"
}
},
{
"path": "pages/index/position",
"style": {
"navigationBarTitleText": "城市列表"
}
}
],
"subPackages": [
@ -278,6 +284,12 @@
"style": {
"navigationBarTitleText": "赠送礼物"
}
},
{
"path": "offlineCourseList",
"style": {
"navigationBarTitleText": "线下课堂"
}
}
]
},
@ -514,6 +526,12 @@
"style": {
"navigationBarTitleText": "刷题过关"
}
},
{
"path": "clockRecord",
"style": {
"navigationBarTitleText": "打卡记录"
}
}
]
},

@ -29,17 +29,15 @@
</view>
<!-- 广告 -->
<view class="advert">
<image :src="advertList[0].banner" mode="aspectFill"></image>
</view>
<advert />
<template v-for="(item, index) in indexMenu">
<view v-if="specialData[item.key] && specialData[item.key].length > 0" :key="index" class="special-content">
<view class="special-content-title">
{{ item.menuName }}
<text v-if="item.menuName !== '线下课堂'" class="more-special" @click="getsearch(3)">更多 ></text>
<text class="more-special" @click="getsearch(item.key)">更多 ></text>
</view>
<line-style-course v-if="item.menuName === '我的课程'" :specialList="specialData[item.key]" @detail="handleSpecialClick"></line-style-course>
<line-style-course v-if="item.menuName === '我的课程'" :specialList="specialData[item.key]" @detail="(item) => { handleSpecialClick(item, 'my'); }"></line-style-course>
<square-style-course v-if="item.menuName === '热门课程'" :specialList="specialData[item.key]" @detail="handleSpecialClick"></square-style-course>
<offline-style-course v-if="item.menuName === '线下课堂'" :specialList="specialData[item.key]" @detail="handleSpecialClick"></offline-style-course>
</view>
@ -95,6 +93,7 @@ import RecommendPoster from "@/components/RecommendPoster/index.vue";
import LineStyleCourse from '@/components/Course/lineStyleCourse.vue';
import SquareStyleCourse from '@/components/Course/squareStyleCourse.vue';
import OfflineStyleCourse from '@/components/Course/offlineStyleCourse.vue';
import Advert from '@/components/Advert/index.vue';
const app = getApp();
export default {
@ -104,6 +103,7 @@ import OfflineStyleCourse from '@/components/Course/offlineStyleCourse.vue';
LineStyleCourse,
SquareStyleCourse,
OfflineStyleCourse,
Advert,
},
data() {
return {
@ -167,9 +167,15 @@ import OfflineStyleCourse from '@/components/Course/offlineStyleCourse.vue';
},
methods: {
getsearch(key){
uni.navigateTo({
url: `/pages/special/search?specialType=${key || ''}`
})
if (key === 'offline_courses') {
uni.navigateTo({
url: `/pages/special/offlineCourseList?specialType=${key || ''}`
});
} else {
uni.navigateTo({
url: `/pages/special/search?specialType=${key || ''}`
});
}
},
showCateCourse(item) {
if (item.name === '全部分类') {
@ -183,10 +189,10 @@ import OfflineStyleCourse from '@/components/Course/offlineStyleCourse.vue';
showLoginPage() {
this.$util.jumpLogin(this)
},
handleSpecialClick(item) {
handleSpecialClick(item, type) {
const url = item.is_light
? '/pages/special/single_details?id=' + item.id
: '/pages/special/details?id=' + item.id;
? '/pages/special/single_details?id=' + (type ? item.s_id : item.id)
: '/pages/special/details?id=' + (type ? item.s_id : item.id);
// this.$util.checkLogin(() => {
uni.navigateTo({

@ -4,7 +4,7 @@
<view class="TaberList" :style="{ background: `linear-gradient(180deg, rgb(${color_one}) 0%, #FFF 100%)` }">
<view class="header" :style="{background: scrollTop > 10 ? '#f5f5f5' : 'transparent'}">
<view class="flex">
<view class="position header-info">
<view class="position header-info" @click="toPosition">
<image src="@/static/images/position.png" mode="aspectfill"></image>
<text>南京</text>
</view>
@ -14,9 +14,9 @@
搜索你想要的课程名称
</view>
</view>
<view class="notice header-info">
<view class="notice header-info" @click="toNoticeList">
<image src="@/static/images/notice.png" mode="aspectfill"></image>
<text class="notice-num">6</text>
<text v-if="unReadMsgNum > 0" class="notice-num">{{ unReadMsgNum }}</text>
</view>
</view>
</view>
@ -555,6 +555,7 @@
import { getNews, getIndexData } from "@/api/index";
import { groupWorks, getSpecialList } from "@/api/special";
import { getGoodsList } from "@/api/store";
import { unReadMsgNum } from '@/api/user';
import RecommendMaterial from "@/components/RecommendMaterial/index.vue";
import RecommendPoster from "@/components/RecommendPoster/index.vue";
import RecommendProblem from "@/components/RecommendProblem/index.vue";
@ -600,6 +601,7 @@ export default {
specialList: [],
goodsList: [],
scrollTop: 0,
unReadMsgNum: 0,
};
},
onShow() {
@ -617,17 +619,23 @@ export default {
this.getGoodsList();
this.getNewsList();
this.getgroupWork();
this.getUnReadMsgNum();
// console.log('=====');
// uni.getLocation({
// type: 'gcj02',
// geocode: true,
// success: (res) => {
// console.log(res);
// },
// fail: (e) => {
// console.log(e);
// }
// })
// try{
// uni.getLocation({
// type: 'gcj02',
// geocode: true,
// success: (res) => {
// console.log(res);
// },
// fail: (e) => {
// console.log(e);
// }
// })
// }catch(e){
// console.log(e);
// //TODO handle the exception
// }
},
created() {
//#ifdef MP-WEIXIN
@ -661,6 +669,14 @@ export default {
console.log(err);
}
},
async getUnReadMsgNum() {
try {
const { data } = await unReadMsgNum({});
this.unReadMsgNum = data.unReadMsgNum;
} catch (err) {
console.log(err);
}
},
handleSpecialClick(item) {
const url = item.is_light
? '/pages/special/single_details?id=' + item.id
@ -860,6 +876,23 @@ export default {
})
}
},
toNoticeList() {
this.$util.checkLogin(
() => {
uni.navigateTo({
url: "/pages/my/noticeList",
});
},
() => {
this.$util.showMsg("请登录后再进行访问!");
}
);
},
toPosition() {
uni.navigateTo({
url: "/pages/index/position",
});
},
},
};
</script>

@ -0,0 +1,185 @@
<template>
<BaseContainer class="position flex">
<NavBar title="城市列表" />
<view class="position-box" id="position">
<view class="search-box flex flex-center-x" :style="scrollTop > 50 ? 'position: fixed; top: calc(88rpx + var(--safe-top)); left: 0;width: 100%;background: #fff;box-shadow: 0rpx 2rpx 0rpx 0rpx rgba(68,68,68,0.4);' : ''">
<i class="iconfont2 iconsousuo"></i>
<input v-model.trim="search" confirm-type="search" @input="onSearch(search)" placeholder="搜入城市名、拼音或首字母查询" placeholder-class="input-placeholder"/>
<i v-show="search" class="iconfont iconguanbi2" @click="search = ''"></i>
</view>
<view class="now-position p-box">
<view class="now-title p-title">你所在地区</view>
<view class="p-list flex">
<view class="now-value p-value">{{ position }}</view>
</view>
</view>
<!-- <view class="history-position p-box">
<view class="history-title p-title">历史访问目的地</view>
<view class="p-list flex">
<view v-for="(item, index) in historyList" :key="index" class="history-value p-value">{{ item }}</view>
</view>
</view> -->
<view class="hot-position p-box">
<view class="hot-title p-title">热门城市</view>
<view class="p-list flex">
<view v-for="(item, index) in hotList" :key="index" class="hot-value p-value" @click="position = item.name">{{ item.name }}</view>
</view>
</view>
<view class="city-list">
<view v-for="(item, index) in Object.keys(cityList)" :key="index" class="city-item" :id="item">
<view class="city-label">{{ item }}</view>
<view v-for="(city, k) in cityList[item]" class="city" @click="position = city.name">
{{ city.name }}
</view>
</view>
</view>
<view class="city-filter">
<view v-for="(item, index) in Object.keys(cityList)" :key="index" class="city-Upper" @click="scrollItem(item)">{{ item }}</view>
</view>
</view>
</BaseContainer>
</template>
<script>
import { city_list } from '@/api/index';
export default {
data() {
return {
search: '',
position: '南京',
// historyList: ['', '', ''],
hotList: [],
cityList: [],
scrollTop: 0,
cityUpper: '',
};
},
onLoad() {
this.getCityList();
},
onPageScroll(e) {
// this.scrollTop = e.scrollTop;
},
methods: {
onSearch() {},
async getCityList() {
try{
const { data } = await city_list();
console.log(data);
this.hotList = data.hotList;
this.cityList = data.cityList;
}catch(e){
//TODO handle the exception
}
},
scrollItem(item) {
this.cityUpper = item;
const query = uni.createSelectorQuery().in(this);
uni.createSelectorQuery().select("#position").boundingClientRect(data=>{
console.log(data);
  uni.createSelectorQuery().select(`#${item}`).boundingClientRect((res)=>{
console.log(res);
    uni.pageScrollTo({
      duration:100,
      scrollTop:res.top - data.top,//
    })
  }).exec()
}).exec();
},
},
};
</script>
<style lang="scss" scoped>
.position {
flex-direction: column;
.position-box {
flex: 1;
margin-top: 18rpx;
background: #fff;
padding: 30rpx 55rpx 30rpx 35rpx;
.search-box {
width: 660rpx;
background: #F2F2F2;
height: 54rpx;
border-radius: 27rpx;
padding: 0 30rpx;
margin-bottom: 44rpx;
.input-placeholder {
color: #999999;
font-size: 24rpx;
}
input {
flex: 1;
margin-left: 20rpx;
color: #333;
font-size: 24rpx;
}
}
.p-box {
margin-top: 24rpx;
&.now-position {
margin-top: 0;
}
.p-title {
color: #666666;
font-size: 28rpx;
line-height: 28rpx;
margin-bottom: 40rpx;
}
.p-list {
flex-wrap: wrap;
.p-value {
width: 194rpx;
height: 68rpx;
border-radius: 3rpx;
border: 1px solid #ECECEC;
font-size: 28rpx;
color: #222222;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0 16rpx;
line-height: 68rpx;
text-align: center;
margin-right: 20rpx;
margin-bottom: 18rpx;
}
}
}
.city-list {
margin-top: 32rpx;
.city-item {
.city-label {
color: #666666;
font-size: 28rpx;
margin: 30rpx 0;
}
.city {
height: 90rpx;
line-height: 90rpx;
color: #222222;
font-size: 28rpx;
border-bottom: 1px solid #F4F4F4;
}
}
}
.city-filter {
position: fixed;
top: 50%;
transform: translateY(-50%);
right: 35rpx;
width: 23rpx;
font-size: 24rpx;
color: #0082D4;
font-weight: bold;
.city-upper {
margin-bottom: 10rpx;
&:last-child {
margin-bottom: 0;
}
}
}
}
}
</style>

@ -44,7 +44,7 @@
<view class="sign-record">
<view class="record-title content-title">
打卡记录
<text class="more-content">查看 ></text>
<text class="more-content" @click="checkRecord">查看 ></text>
</view>
<view class="record-content flex">
<view class="content-left">
@ -74,7 +74,7 @@
</view>
</view>
</view>
<advert :img="'/static/frontend/learning-advert.png'" />
<advert :img="'/static/frontend/learning-advert.png'" :height="140"/>
<view class="tab-container">
<view class="content-title">
视频课
@ -87,7 +87,7 @@
</view>
</view>
</view>
<advert :img="'/static/frontend/learning-advert.png'" />
<advert :img="'/static/frontend/learning-advert.png'" :height="140"/>
<template v-for="(item, index) in indexMenu">
<view v-if="specialData[item.key] && specialData[item.key].length > 0" :key="index" class="special-content">
<view class="content-title">
@ -99,6 +99,7 @@
</view>
</template>
</view>
<!-- <message-box title="确认收货?" @submit="console.log('提交')"></message-box> -->
</BaseContainer>
</template>
@ -108,12 +109,14 @@ import { getSpecialIndexData } from "@/api/special";
import Advert from '@/components/Advert/index.vue';
import SquareStyleCourse from '@/components/Course/squareStyleCourse.vue';
import OfflineStyleCourse from '@/components/Course/offlineStyleCourse.vue';
import MessageBox from '@/components/Message/index.vue';
export default {
components: {
Advert,
SquareStyleCourse,
OfflineStyleCourse,
MessageBox,
},
data() {
return {
@ -227,6 +230,11 @@ import OfflineStyleCourse from '@/components/Course/offlineStyleCourse.vue';
url: `/pages/special/offline_details?id=${item.id}`,
});
},
checkRecord() {
uni.navigateTo({
url: '/pages/learningCenter/clockRecord',
})
},
},
};
</script>

@ -0,0 +1,181 @@
<template>
<BaseContainer class="record flex">
<NavBar title="打卡记录" />
<image src="@/static/images/learning/record-bg.png" mode="aspectFill" class="bg"></image>
<view class="record-container">
<view class="record-info flex">
<view class="total">
<view>累计打卡</view>
<view><text>{{ totalClock }}</text><text></text></view>
</view>
<view class="line"></view>
<view class="today">
<view>今日打卡</view>
<view :style="{ color: todayClock ? '#52C794' : '' }">{{ todayClock ? '已打卡' : '暂未打卡' }}</view>
</view>
</view>
<view class="calendar-box">
<calendar />
</view>
<view class="record-list">
<view class="list-title">
打卡记录
</view>
<view v-for="(item, index) in recordList" :key="index" class="list-item">
<view class="item-top flex flex-center-x">
<view>{{ item.name }}</view>
<view>{{ item.score }}</view>
</view>
<view class="item-bottom flex flex-center-x">
<view>用时{{ item.time }}</view>
<view>{{ item.date }}</view>
</view>
</view>
</view>
</view>
</BaseContainer>
</template>
<script>
import Calendar from './components/calendar.vue';
export default {
components: {
Calendar,
},
data() {
return {
totalClock: 50,
todayClock: false,
recordList: [
{ name: '英语四级考试专项训练', time: '01:23:52', score: '98', date: '2023-10-20' },
{ name: '英语四级考试专项训练', time: '01:23:52', score: '98', date: '2023-10-20' },
{ name: '英语四级考试专项训练', time: '01:23:52', score: '98', date: '2023-10-20' },
{ name: '英语四级考试专项训练', time: '01:23:52', score: '98', date: '2023-10-20' },
{ name: '英语四级考试专项训练', time: '01:23:52', score: '98', date: '2023-10-20' },
]
};
},
methods: {
},
};
</script>
<style lang="scss" scoped>
.record {
flex-direction: column;
.bg {
position: absolute;
top: 0;
left: 0;
width: 750rpx;
height: 743rpx;
z-index: 0;
}
.record-container {
flex: 1;
padding-top: 60rpx;
.record-info {
justify-content: space-between;
margin-bottom: 50rpx;
padding: 0 150rpx;
>view {
color: #333;
font-size: 30rpx;
line-height: 30rpx;
&.line {
width: 2rpx;
height: 76rpx;
background: #EEEEEE;
}
>view:last-child {
height: 70rpx;
font-size: 38rpx;
color: #666;
margin-top: 27rpx;
>text {
font-size: 24rpx;
color: #999;
&:first-child {
font-size: 70rpx;
color: #3293FF;
}
}
}
}
}
.calendar-box {
width: 690rpx;
// height: 630rpx;
background: #fff;
border-radius: 10rpx;
margin: 0 auto;
position: relative;
padding: 0 35rpx;
&:before {
content: '';
width: 12rpx;
height: 36rpx;
background: linear-gradient(0deg, #DCEBF4 0%, #3293FF 100%);
border-radius: 6rpx;
position: absolute;
top: -18rpx;
left: 100rpx;
}
&:after {
content: '';
width: 12rpx;
height: 36rpx;
background: linear-gradient(0deg, #DCEBF4 0%, #3293FF 100%);
border-radius: 6rpx;
position: absolute;
top: -18rpx;
right: 100rpx;
}
}
.record-list {
background: #fff;
border-radius: 10rpx;
padding: 40rpx 30rpx;
width: 690rpx;
margin: 20rpx auto 0;
.list-title {
text-align: center;
color: #333333;
font-size: 34rpx;
margin-bottom: 20rpx;
}
.list-item {
border-bottom: 1rpx solid #F0F0F0;
padding: 30rpx 0;
>view {
justify-content: space-between;
&.item-top {
color: #333333;
font-size: 30rpx;
line-height: 30rpx;
margin-bottom: 15rpx;
>view:last-child {
color: #3293FF;
font-size: 32rpx;
}
}
&.item-bottom {
font-size: 22rpx;
color: #999797;
line-height: 22rpx;
}
>view {
&:first-child {
width: 400rpx;
}
&:last-child {
margin-left: auto;
}
}
}
}
}
}
}
</style>

@ -0,0 +1,335 @@
<template>
<view class="calendar">
<view class="calendar-title flex flex-center-x">
<view class="pre-month operate" @click="gotoPreMonth">
<view class="iconfont iconxiangyou" style="transform: rotate(180deg);"></view>
</view>
{{ monthYear }}
<view class="next-month operate" @click="gotoNextMonth">
<view class="iconfont iconxiangyou"></view>
</view>
</view>
<view class='showData'>
<view class="title"></view>
<view class="title"></view>
<view class="title"></view>
<view class="title"></view>
<view class="title"></view>
<view class="title"></view>
<view class="title"></view>
</view>
<view class='content'>
<view
v-for="(item, index) in allArr"
:key="index"
:class="['itemData']"
class="flex flex-center-x"
@click="chooseDay(item)"
>
<view
:class="['date', {
'nowDay': item.month === 'current' && nowYear === currentYear && nowMonth === currentMonth && nowDate === item.date,
'hasPlan': item.month === 'current' && dateList.includes(`${currentYear}-${formatterNum(currentMonth)}-${formatterNum(item.date)}`),
'isClock': item.month === 'current' && dateList.includes(`${currentYear}-${formatterNum(currentMonth)}-${formatterNum(item.date)}`)
}]"
>{{ item.month === 'current' ? item.date : '' }}</view>
</view>
</view>
</view>
</template>
<script>
// import { queryMemorandumMonth } from '../api';
export default {
props: {
calendarData: {
type: Array,
require: true,
},
type: {
type: String,
require: true,
},
},
data() {
return {
currentMonthDateLen: 0, //
preMonthDateLen: 0, //
currentYear: new Date().getFullYear(), //
currentMonth: new Date().getMonth() + 1, //
// eslint-disable-next-line prefer-template
monthYear: new Date().getFullYear() + '年' + (new Date().getMonth() + 1 < 10 ? '0' + (new Date().getMonth() + 1) : (new Date().getMonth() + 1)) + '月', //
nowYear: new Date().getFullYear(), //
nowMonth: new Date().getMonth() + 1, //
nowDate: new Date().getDate(), //
allArr: [],
dateList: [],
};
},
mounted() {
this.getAllArr();
// this.getDateList();
},
methods: {
// async getDateList() {
// const res = await queryMemorandumMonth({ datetime: this.monthYear });
// if (Number(res.status === 200) && res.data.success) {
// if (res.data.result.length > 0) {
// // eslint-disable-next-line arrow-parens
// res.data.result.forEach(v => {
// if (!this.dateList.includes(v)) {
// this.dateList.push(v);
// }
// });
// }
// } else {
// this.$util.showMsg(res.data.message || res.data.msg);
// }
// },
//
getDateLen(year, month) {
let actualMonth = month - 1;
let timeDistance = +new Date(year, month) - +new Date(year, actualMonth);
return timeDistance / (1000 * 60 * 60 * 24);
},
// 1
getFirstDateWeek(year, month) {
return new Date(year, month - 1, 1).getDay();
},
//
preMonth(year, month) {
if (month == 1) {
return {
year: --year,
month: 12
};
} else {
return {
year: year,
month: --month
};
}
},
//
nextMonth(year, month) {
if (month == 12) {
return {
year: ++year,
month: 1
};
} else {
return {
year: year,
month: ++month
};
}
},
//
getCurrentArr(){
let currentMonthDateLen = this.getDateLen(this.currentYear, this.currentMonth); //
let currentMonthDateArr = []; //
if (currentMonthDateLen > 0) {
for (let i = 1; i <= currentMonthDateLen; i++) {
currentMonthDateArr.push({
month: 'current', //
date: i
});
}
}
this.currentMonthDateLen = currentMonthDateLen;
return currentMonthDateArr;
},
//
getPreArr(){
let preMonthDateLen = this.getFirstDateWeek(this.currentYear, this.currentMonth); // 1 ==
let preMonthDateArr = []; //
if (preMonthDateLen > 0) {
let { year, month } = this.preMonth(this.currentYear, this.currentMonth); //
let date = this.getDateLen(year, month); //
for (let i = 0; i < preMonthDateLen; i++) {
preMonthDateArr.unshift({ //
month: 'pre', //
date: date
});
date--;
}
}
this.preMonthDateLen = preMonthDateLen;
return preMonthDateArr;
},
//
getNextArr() {
let nextMonthDateLen = 35 - this.preMonthDateLen - this.currentMonthDateLen; //
let nextMonthDateArr = []; //
if (nextMonthDateLen > 0) {
for (let i = 1; i <= nextMonthDateLen; i++) {
nextMonthDateArr.push({
month: 'next',//
date: i
});
}
}
return nextMonthDateArr;
},
//
getAllArr(){
let preArr = this.getPreArr();
let currentArr = this.getCurrentArr();
let nextArr = this.getNextArr();
let allArr = [...preArr, ...currentArr, ...nextArr];
this.allArr = allArr;
let sendObj = {
currentYear: this.currentYear,
currentMonth: this.currentMonth,
monthYear: this.currentYear + '年' + (this.currentMonth < 10 ? '0' + this.currentMonth : this.currentMonth) + '月',
nowYear: this.nowYear,
nowMonth: this.nowMonth,
nowDate: this.nowDate,
fullDate: this.nowYear + '-' + this.nowMonth + '-' + this.nowDate,
allArr: allArr
};
this.$emit('sendObj', sendObj);
},
//
gotoPreMonth() {
let { year, month } = this.preMonth(this.currentYear, this.currentMonth);
this.currentYear = year;
this.currentMonth = month;
this.monthYear = year + '年' + (month < 10 ? '0' + month : month) + '月';
this.getAllArr();
// this.getDateList();
},
//
gotoNextMonth() {
let { year, month } = this.nextMonth(this.currentYear, this.currentMonth);
this.currentYear = year;
this.currentMonth = month;
this.monthYear = year + '年' + (month < 10 ? '0' + month : month) + '月';
this.getAllArr();
// this.getDateList();
},
clockPreTask(id) {
this.$emit('clock', id);
},
chooseDay(item) {
if (item.month === 'current') {
this.nowYear = this.currentYear;
this.nowMonth = this.currentMonth;
this.nowDate = item.date;
// this.$emit('change');
}
},
formatterNum(num) {
return Number(num) < 10 ? `0${num}` : num;
},
}
};
</script>
<style lang="scss" scoped>
.calendar{
width: 100%;
padding-bottom: 70rpx;
.calendar-title {
font-size: 30rpx;
color: #333;
font-weight: bold;
color: #333;
height: 102rpx;
border-bottom: 1rpx solid #e6e6e6;
justify-content: center;
.operate {
>view {
color: #b0b0b0;
}
&.pre-month {
margin-right: 35rpx;
}
&.next-month {
margin-left: 35rpx;
}
}
}
}
.showData{
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
}
.showData .title{
width: calc(100% / 7);
height: 78rpx;
line-height: 48rpx;
text-align: center;
flex-shrink: 0;
font-size: 24rpx;
color: #B3B3B3;
padding: 15rpx 0;
}
.calendar .tit{
display: flex;
justify-content: center;
align-items: center;
}
.calendar .content{
display: flex;
flex-wrap: wrap;
box-sizing: border-box;
position: relative;
}
.calendar .content .itemData{
width: calc(100% / 7);
height: 78rpx;
flex-shrink: 0;
font-size: 14px;
justify-content: center;
&.week-hidden {
display: none;
}
.date {
color: #333;
font-size: 24rpx;
line-height: 48rpx;
position: relative;
width: 48rpx;
height: 48rpx;
text-align: center;
&.nowDay {
background: #027DFF;
border-radius: 50%;
color: #fff;
}
&.hasPlan {
&:after {
content: '';
position: absolute;
width: 7rpx;
height: 7rpx;
border-radius: 50%;
left: 50%;
bottom: -8rpx;
transform: translateX(-50%);
background: #FF0327;
white-space: nowrap;
line-height: 0;
font-weight: bold;
}
}
&.isClock {
&:after {
content: '√';
position: absolute;
width: 12rpx;
height: 8rpx;
left: 50%;
bottom: 0rpx;
font-size: 20rpx;
color: #FF0327;
transform: translateX(-50%);
}
}
}
}
</style>

@ -20,9 +20,9 @@
</view>
<view class="iconfont iconxiangyou"></view>
</view>
<view class="notice header-info">
<view v-if="isLogin" class="notice header-info" @click="toNoticeList">
<image src="@/static/images/notice.png" mode="aspectfill"></image>
<text class="notice-num">6</text>
<text v-if="unReadMsgNum > 0" class="notice-num">{{ unReadMsgNum }}</text>
</view>
</view>
@ -132,7 +132,8 @@
getMenus,
getCopyrightInfo,
getUserBaseData,
saveUserInfo
saveUserInfo,
unReadMsgNum
} from "@/api/user";
import { VALID_LOGIN_STATUS } from "@/store/types/action-types";
import { getMerchantApplyStatus } from "@/api/merchant";
@ -182,7 +183,8 @@
userid: 0,
teacherInfo: null,
TOUTIAO_STATUS:false,
imId:''
imId:'',
unReadMsgNum: 0,
};
},
computed: {
@ -196,6 +198,7 @@
this.getQuestion();
this.getMenu();
this.get_copyright();
this.getUnReadMsgNum();
if (uni.getUserProfile) {
this.canUseGetUserProfile = true
}
@ -206,10 +209,19 @@
watch: {
isLogin() {
this.getMenu();
this.getUserBaseData();
this.getUserBaseData();
this.getUnReadMsgNum();
}
},
methods: {
async getUnReadMsgNum() {
try {
const { data } = await unReadMsgNum({});
this.unReadMsgNum = data.unReadMsgNum;
} catch (err) {
console.log(err);
}
},
async childClick(e) {
console.log(e)
const result = await saveUserInfo({
@ -344,6 +356,18 @@
}
);
},
toNoticeList() {
this.$util.checkLogin(
() => {
uni.navigateTo({
url: "/pages/my/noticeList",
});
},
() => {
this.$util.showMsg("请登录后再进行访问!");
}
);
},
//
changeVal: function (opt) {
if (typeof opt != "object") opt = {};

@ -21,6 +21,7 @@
</template>
<script>
import { setReaded } from '@/api/user';
import mpHtml from "mp-html/dist/uni-app/components/mp-html/mp-html.vue";
export default {
@ -36,8 +37,19 @@ export default {
console.log(options);
this.info = options.info ? JSON.parse(options.info) : {};
console.log(this.info);
this.setReaded();
},
methods: {
async setReaded() {
if (this.info.is_read === 1) {
return;
}
try{
await setReaded({ id: info.id});
}catch(e){
//TODO handle the exception
}
},
},
};
</script>

@ -3,32 +3,65 @@
<NavBar title="消息中心" />
<view class="notice-list">
<view v-for="(item, index) in noticeList" class="notice-item flex flex-center-x" @click="toDetail(item)">
<image :src="item.pic" mode="aspectFill"></image>
<image :src="item.message_types.pic" mode="aspectFill"></image>
<view class="item-info">
<view>{{ item.title }}</view>
<view>{{ item.message_types.name }}</view>
<view>{{ item.content }}</view>
</view>
<view class="item-right">
<view>{{ item.time }}</view>
<view v-if="num > 1" class="num">{{ item.num }}</view>
<view v-if="item.is_read === 0" class="num">{{ item.count }}</view>
</view>
</view>
<view v-if="noticeList.length && !loading" class="finished">{{ loadTitle }}</view>
<view v-if="finished && !noticeList.length" class="empty">
<image mode="aspectFill" :src="getImgPath('/wap/first/zsff/images/empty.png')" alt="暂无课程" />
<view>暂无消息</view>
</view>
</view>
</BaseContainer>
</template>
<script>
import { messageList } from '@/api/user';
export default {
data() {
return {
noticeList: [
{ pic: '', title: '梦航课程', content: '您预约报名的课程即将开始,请及时您预约报名的课程即将开始,请及时关注', time: '11:16', num: 6},
{ pic: '', title: '通知消息', content: '您的退款已申请通过,请您及时查收账户您的退款已申请通过,请您及时查收账户', time: '2023-12-30', num: 1},
{ pic: '', title: '通知消息', content: '您的退款已申请通过,请您及时查收账户您的退款已申请通过,请您及时查收账户', time: '2023-12-30', num: 1},
]
{ pic: '', title: '梦航课程', content: '您预约报名的课程即将开始,请及时您预约报名的课程即将开始,请及时关注', time: '11:16', is_read: 0, count: 1, message_types: { pic: '', name: '梦航课程'}, },
{ pic: '', title: '通知消息', content: '您的退款已申请通过,请您及时查收账户您的退款已申请通过,请您及时查收账户', time: '2023-12-30', is_read: 1, count: 0, message_types: { pic: '', name: '通知消息'}, },
{ pic: '', title: '通知消息', content: '您的退款已申请通过,请您及时查收账户您的退款已申请通过,请您及时查收账户', time: '2023-12-30', is_read: 0, count: 1, message_types: { pic: '', name: '通知消息'}, },
],
page: 1,
limit: 10,
loading: false,
finished: false,
};
},
onLoad() {
this.getNoticeList();
},
onReachBottom() {
this.getNoticeList();
},
methods: {
async getNoticeList() {
if (this.loading || this.finished) {
return;
}
uni.showLoading();
const { data } = await messageList(
{
page: this.page++,
limit: this.limit,
}
);
uni.hideLoading();
this.noticeList = this.noticeList.concat(data);
console.log(this.noticeList);
this.finished = data.length < this.limit;
this.loadTitle = this.finished ? "已全部加载完" : "上拉加载更多";
},
toDetail(item) {
uni.navigateTo({
url: `/pages/my/noticeDetail?info=${JSON.stringify(item)}`
@ -95,6 +128,28 @@
}
}
}
.finished,
.loading {
font-size: 28rpx;
line-height: 100rpx;
text-align: center;
color: #bbb;
}
.empty {
margin-top: 100rpx;
font-size: 28rpx;
text-align: center;
color: #bbb;
}
.empty image {
display: block;
width: 414rpx;
height: 305rpx;
margin: 0 auto;
pointer-events: none;
}
}
}
</style>

@ -222,26 +222,26 @@
<!-- 导航栏 -->
<view ref="list" class="swiper-nav">
<view class="navCon acea-row row-middle">
<!-- <template v-if="special.type === 4">
<template v-if="special.type === 4">
<view v-for="nav in liveNavlist" :key="nav.value" :class="{ on: active === nav.value }" class="item"
@click="active = nav.value">
{{ nav.title }}
</view>
</template>
<template v-else-if="special.type === 5">
<!-- <template v-else-if="special.type === 5">
<view v-for="nav in cloumnNavlist" :key="nav.value" :class="{ on: active === nav.value }" class="item"
@click="active = nav.value">
{{ nav.title
}}<text v-if="nav.value === 5">({{ evaluateWhole }})</text>
</view>
</template>
<template v-else> -->
</template> -->
<template v-else>
<view v-for="nav in otherNavlist" :key="nav.value" :class="{ on: active === nav.value }" class="item"
@click="active = nav.value">
{{ nav.title
}}<text v-if="nav.value === 5">({{ evaluateWhole }})</text>
</view>
<!-- </template> -->
</template>
</view>
</view>

@ -0,0 +1,104 @@
<template>
<BaseContainer class="offline-course-list flex">
<NavBar title="线下课堂" />
<view class="list-box">
<offline-style-course :specialList="specialList" @detail="handleSpecialClick"></offline-style-course>
<view v-if="specialList.length && !loading" class="finished">{{ loadTitle }}</view>
<view v-if="finished && !specialList.length" class="empty">
<image mode="aspectFill" :src="getImgPath('/wap/first/zsff/images/empty.png')" alt="暂无课程" />
<view>暂无课程</view>
</view>
</view>
</BaseContainer>
</template>
<script>
import OfflineStyleCourse from '@/components/Course/offlineStyleCourse.vue';
import {
getSpecialList,
} from "@/api/special";
export default {
components: {
OfflineStyleCourse,
},
data() {
return {
specialList: [],
page: 1,
limit: 10,
loading: false,
finished: false,
};
},
onReachBottom() {
// this.getSpecialList();
},
onLoad(options) {
this.grade_id = options.gradeId || '';
this.subject_id = options.subjectId || '';
this.special_type = options.specialType || '';
// this.getSpecialList();
},
methods: {
async getSpecialList() {
if (this.loading || this.finished) {
return;
}
this.loadTitle = "";
this.loading = true;
try {
const { data } = await getSpecialList({
grade_id: this.grade_id,
subject_id: this.subject_id,
special_type: this.special_type,
page: this.page++,
limit: this.limit,
});
this.specialList = this.specialList.concat(data);
console.log(this.specialList);
this.finished = data.length < this.limit;
this.loadTitle = this.finished ? "已全部加载完" : "上拉加载更多";
} catch (err) {
console.log(err);
}
this.loading = false;
},
},
};
</script>
<style lang="scss" scoped>
.offline-course-list {
flex-direction: column;
.list-box {
flex: 1;
width: 690rpx;
margin: 20rpx auto 0;
.finished,
.loading {
font-size: 28rpx;
line-height: 100rpx;
text-align: center;
color: #bbb;
}
.empty {
margin-top: 100rpx;
font-size: 28rpx;
text-align: center;
color: #bbb;
}
.empty image {
display: block;
width: 414rpx;
height: 305rpx;
margin: 0 auto;
pointer-events: none;
}
}
}
</style>

@ -62,14 +62,8 @@ export default {
finished: false,
singleDetailsURL: "/pages/special/single_details",
detailsURL: "/pages/special/details",
isEmpty: false,
};
},
watch: {
specialList(val) {
this.isEmpty = !val.length;
},
},
onShareAppMessage() {
return {};
},
@ -82,6 +76,10 @@ export default {
this.special_type = options.specialType || '';
this.getSpecialList();
},
onReachBottom() {
this.getSpecialList();
},
methods: {
getJumpUrl(item) {
return item.is_light ? this.singleDetailsURL : this.detailsURL + "?id=" + item.id;

@ -9,7 +9,7 @@
</view>
<square-style-course v-if="item.menuName === '视频课程' || item.menuName === '热门课程'" :specialList="specialData[item.key]" @detail="handleSpecialClick"></square-style-course>
<offline-style-course v-if="item.menuName === '线下课堂'" :specialList="specialData[item.key]" @detail="handleSpecialClick"></offline-style-course>
<view v-if="item.menuName !== '线下课堂'" class="showMore flex" @click="loadMore(3)">加载更多<text class="more"></text> </view>
<view class="showMore flex" @click="loadMore(item.key)">加载更多<text class="more"></text> </view>
</view>
</template>
</view>
@ -49,9 +49,15 @@
},
methods: {
loadMore(key) {
uni.navigateTo({
url: `/pages/special/search?gradeId=${this.gradeId}&subjectId=${this.subjectId}&specialCate=${key}`
})
if (key === 'offline_courses') {
uni.navigateTo({
url: `/pages/special/offlineCourseList?gradeId=${this.gradeId}&subjectId=${this.subjectId}&specialCate=${key}`
})
} else {
uni.navigateTo({
url: `/pages/special/search?gradeId=${this.gradeId}&subjectId=${this.subjectId}&specialCate=${key}`
})
}
},
handleSpecialClick(item) {
const url = item.is_light

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Loading…
Cancel
Save