开开发消息页

This commit is contained in:
田岩
2025-08-19 20:23:12 +08:00
parent 76bcb91480
commit 5a874ae9b3
19 changed files with 893 additions and 333 deletions
-1
View File
@@ -7,7 +7,6 @@ const ENV = import.meta.env
export const get_base_url = (url = '') => {
if (ENV.MODE === 'development') { // 开发环境
// H5必须用非https,手机端必须用https
// #ifdef H5
if (url) {
let _str = (url.split('/')[0] || url.split('/')[1])?.toUpperCase()
@@ -0,0 +1,64 @@
<template>
<uv-input
v-model="inputValue"
:customStyle="fixedCustomStyles"
placeholderStyle="color:#999999;font-size:26rpx"
:placeholder="placeholder"
:adjustPosition="false"
:confirmType="confirmType"
:maxlength="20"
@confirm="search"
>
<template #suffix><uv-icon name="search" color="#2c8ef2" size="24" @click="search(inputValue)"></uv-icon></template>
</uv-input>
</template>
<script setup>
import { ref, reactive, onMounted, computed, watch } from 'vue';
const fixedCustomStyles = {
backgroundColor: '#F1F5FA',
paddingLeft: '40rpx',
paddingTop: '5px',
paddingBottom: '5px',
border: 'none'
};
// 定义props
const props = defineProps({
modelValue: {
type: String, // 输入框通常是字符串类型,这里修改为String更合理
default: ''
},
placeholder: {
type: String,
default: ''
},
confirmType: {
type: String,
default: 'search'
},
});
// 定义emits
const emits = defineEmits(['update:modelValue', 'search']);
// 定义组件内部的inputValue,并与props.modelValue关联
const inputValue = ref(props.modelValue);
// 监听inputValue变化,同步到父组件
watch(inputValue, (newVal) => {
emits('update:modelValue', newVal);
});
// 监听父组件传来的modelValue变化,同步到组件内部
watch(
() => props.modelValue,
(newVal) => {
inputValue.value = newVal;
}
);
const search = () => {
emits('search', inputValue.value);
};
</script>
<style scoped lang="scss"></style>
@@ -128,7 +128,6 @@
const props = defineProps({
crsId: String,
crsNum: String,
imgId: String
})
const click_reply = (item, parentBbsId, index) => {
+70 -21
View File
@@ -15,24 +15,46 @@
</view>
<view class="title-num">
<view class="num-item">
<image class="title-icon" src="/src/static/images/courseDetail/zhishidian.png" mode="heightFix"></image>
<image
class="title-icon"
src="/src/static/images/courseDetail/zhishidian.png"
mode="heightFix"
></image>
<view class="mr-10">知识点</view>
<view class="c-000">{{ form.pgrphNum || 0 }}</view>
</view>
<view class="num-item">
<image class="title-icon" src="/src/static/images/courseDetail/yixue.png" mode="heightFix"></image>
<image
class="title-icon"
src="/src/static/images/courseDetail/yixue.png"
mode="heightFix"
></image>
<view class="mr-10">已学</view>
<view class="c-000">{{ form.styParaGraphNum || 0 }}</view>
</view>
<view class="num-item examination">
<image class="title-icon" src="/src/static/images/courseDetail/charts.png" mode="heightFix"></image>
<image
class="title-icon"
src="/src/static/images/courseDetail/charts.png"
mode="heightFix"
></image>
<view>考试排行榜</view>
<view class="back-icon"></view>
</view>
<view class="fl1"></view>
<view class="num-item" @click="collect_click(form.collectId)">
<image v-if="form.collectId" class="collect-icon" src="/src/static/images/courseDetail/out_collect.png" mode="widthFix"></image>
<image v-else class="collect-icon" src="/src/static/images/courseDetail/in_collect.png" mode="widthFix"></image>
<image
v-if="form.collectId"
class="collect-icon"
src="/src/static/images/courseDetail/out_collect.png"
mode="widthFix"
></image>
<image
v-else
class="collect-icon"
src="/src/static/images/courseDetail/in_collect.png"
mode="widthFix"
></image>
</view>
</view>
</view>
@@ -61,7 +83,7 @@
</view>
<!--</swiper-item><swiper-item>-->
<view class="evaluate" v-if="tabAct == 2 && form">
<comment ref="commentRef" :crsNum="form.crsNum" :crsId="form.crsId" :imgId="form.imgId"></comment>
<comment ref="commentRef" :crsId="crsId" :imgId="form.imgId"></comment>
</view>
<!--</swiper-item></swiper>-->
</view>
@@ -69,12 +91,21 @@
</scroll-view>
<view class="btn-box btn-box-height font_pf">
<template v-if="[0, 1].includes(tabAct)">
<uv-button type="primary" @click="common.navigateTo('/pages/course/study?crsNum=' + form.crsNum + '&crsId=' + crsId + '&imgId=' + form.imgId)">去学习</uv-button>
<uv-button
type="primary"
@click="common.navigateTo('/pages/course/study?crsNum=' + form.crsNum + '&crsId=' + crsId + '&imgId=' + form.imgId)"
>
去学习
</uv-button>
<uv-button type="primary">去练习</uv-button>
<uv-button type="primary" @click="goto_examination()">去考试</uv-button>
</template>
<template v-if="tabAct == 2">
<uv-button type="primary" class="send_evaluate" @click="common.navigateTo('/pages/courseDetail/submit?crsNum=' + form.crsNum + '&imgId=' + form.imgId)">
<uv-button
type="primary"
class="send_evaluate"
@click="common.navigateTo('/pages/courseDetail/submit?crsNum=' + form.crsNum + '&imgId=' + form.imgId)"
>
发布评价
</uv-button>
</template>
@@ -120,7 +151,16 @@
form.value = body;
};
const toStudyPrgh = (info) => {
common.navigateTo('/pages/course/study?crsNum=' + form.value.crsNum + '&crsId=' + crsId.value + '&pgrphId=' + info.pgrphId + '&imgId=' + form.imgId);
common.navigateTo(
'/pages/course/study?crsNum=' +
form.value.crsNum +
'&crsId=' +
crsId.value +
'&pgrphId=' +
info.pgrphId +
'&imgId=' +
form.imgId
);
};
const bgOpacity = computed(() => {
@@ -141,8 +181,8 @@
const goto_examination = async () => {
common.loading();
startExamByCrs({
// crsId : crsId.value
crsId: 'CRS0250181220722025070408313900000018729'
crsId : crsId.value
// crsId: 'CRS0250181220722025070408313900000018729'
})
.then((res) => {
setPageCache('examination', {
@@ -157,16 +197,25 @@
};
const collect_click = async (collectId) => {
console.log(collectId);
if (!collectId) {
await insertTraPersonalCollectionTask({
collectTyp: '01',
collectBusId: crsId.value
});
} else {
await deleteTraPersonalCollectionById({
collectId: collectId
});
try {
if (!collectId) {
common.loading('收藏中');
form.value.collectId = await insertTraPersonalCollectionTask({
collectTyp: '01',
collectBusId: crsId.value
});
common.msg('收藏成功');
} else {
common.loading('取消收藏中');
await deleteTraPersonalCollectionById({
collectId: collectId
});
form.value.collectId = null;
common.msg('取消成功');
}
} catch (e) {
common.hideLoading();
}
};
onMounted(async () => {
@@ -1,16 +1,16 @@
<template>
<view class="scroll_div">
<scroll-view scroll-y="true" class="scroll-Y" @scrolltolower="scrolltolower" :show-scrollbar='false'>
<view class="item" :class="getStatusClass(index)" v-for="(item,index) in data_list">
<view class="item" :class="getStatusClass(item.isFinish)" v-for="(item,index) in data_list">
<view class="img_div">
<image class="img" src="@/static/images/test/4.png" mode="scaleToFill"></image>
<view class="subscript" v-if="index % 3==0">
<image-preview class="img" :src="item.ossAddr" mode="scaleToFill"></image-preview>
<view class="subscript" v-if="item.isFinish==='00'">
进行中
</view>
<view class="subscript" v-if="index % 3==1">
<view class="subscript" v-if="item.isFinish==='01'">
已完成
</view>
<view class="subscript" v-if="index % 3==2">
<view class="subscript" v-if="item.isFinish==='02'">
已超时
</view>
</view>
@@ -26,11 +26,12 @@
完成人数<text class="">{{item.taskFinishSums ?? 0}}/{{item.taskSums ?? 0}}</text>
</view>
<view>
进度<text class="">2/4门课程</text>
进度<text class="">{{item.sumCrs ?? 0}}/{{item.sumCrs ?? 0}}门课程</text>
</view>
</view>
</view>
</view>
<list-no-data v-if="total == 0 && status=='nomore'"></list-no-data>
<uv-load-more v-if="total != 0" :status="status" loadmore-text="轻轻上拉加载" :height="30"></uv-load-more>
</scroll-view>
</view>
@@ -47,11 +48,18 @@
onMounted,
nextTick
} from 'vue'
import {
queryAllTraTaskInfoByUserId,
} from '@/api/learningTasks.js';
const getData = (from = '') => {
const props = defineProps({
state: {
type: String,
required: true,
},
});
const getData = (from = '', searchText='') => {
if (from == 'first') {
if (total.value !== -1) {
return
@@ -67,9 +75,10 @@
}
setTimeout(() => {
queryAllTraTaskInfoByUserId({
state: '01',
state: props.state,
page: page.value,
limit: limit
limit: limit,
taskName:searchText
}).then(res => {
total.value = res.total
data_list.push(...res.body)
@@ -83,17 +92,23 @@
})
}, 200)
}
const getStatusClass = (index) => {
const remainder = index % 3;
if (remainder === 0) return 'in_progress';
if (remainder === 1) return 'completed';
const getStatusClass = (isFinish) => {
// 00进行中、01已完成、02已超时
if (isFinish === '00') return 'in_progress';
if (isFinish === '01') return 'completed';
return 'expired';
};
const scrolltolower = (item) => {
getData()
};
const search = (value) => {
total.value = -1
console.log('value', value);
getData('first', value)
}
defineExpose({
getData
getData, search
})
</script>
+61 -58
View File
@@ -8,29 +8,32 @@
<view class="title font_pf">学习任务</view>
</view>
<view class="fixed_search_input_div">
<uv-input v-model="inputValue" shape="" :customStyle="fixedCustomStyles"
placeholderStyle='color:#999999;font-size:26rpx' placeholder="请输入任务名" suffixIcon="search"
:suffixIconStyle="suffixIconStyle">
</uv-input>
<search-input placeholder="请输入任务名" @search="search"></search-input>
</view>
<view class="detail-body">
<view class="body-tab">
<uv-tabs class="font_pf my_tabs" :current="tabAct" :list="tabList" @change="tabChange"
:scrollable="false" line-color="#0066FF"
:inactive-style="{ color: '#333333', fontSize: '30rpx', fontWeight:'600'}"
:activeStyle="{color:'#0066FF',fontSize:'30rpx', fontWeight:'600'}"
:lineColor="`url(${LineBg}) 10% 10%`"></uv-tabs>
<uv-tabs
class="font_pf my_tabs"
:current="tabAct"
:list="tabList"
@change="tabChange"
:scrollable="false"
line-color="#0066FF"
:inactive-style="{ color: '#333333', fontSize: '30rpx', fontWeight: '600' }"
:activeStyle="{ color: '#0066FF', fontSize: '30rpx', fontWeight: '600' }"
:lineColor="`url(${LineBg}) 10% 10%`"
></uv-tabs>
</view>
<view class="uni-margin-wrap no-overflow">
<swiper class="swiper" :current="tabAct" :indicator-dots="false" @change="swiperChange">
<swiper-item>
<listItem :ref="el => listItemRefs[0] = el" status="01"></listItem>
<listItem :ref="(el) => (listItemRefs[0] = el)" state="01"></listItem>
</swiper-item>
<swiper-item>
<listItem :ref="el => listItemRefs[1] = el" status="01"></listItem>
<listItem :ref="(el) => (listItemRefs[1] = el)" state="02"></listItem>
</swiper-item>
<swiper-item>
<listItem :ref="el => listItemRefs[2] = el" status="01"></listItem>
<listItem :ref="(el) => (listItemRefs[2] = el)" state="03"></listItem>
</swiper-item>
</swiper>
</view>
@@ -39,44 +42,38 @@
</template>
<script setup>
import {
LineBg
} from '@/enum.js'
import listItem from './components/list-item.vue'
import { LineBg } from '@/enum.js';
import listItem from './components/list-item.vue';
// 我的收藏
import {
reactive,
ref,
computed,
nextTick,
onMounted,
watch
} from 'vue';
import common from '@/common/common';
import { reactive, ref, computed, nextTick, onMounted, watch } from 'vue';
import common from '@/common/common.js';
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight;
// 静态样式配置
const fixedCustomStyles = {
backgroundColor: "#F1F5FA",
paddingLeft: "40rpx",
paddingTop: "5px",
paddingBottom: "5px",
border: "none"
}
backgroundColor: '#F1F5FA',
paddingLeft: '40rpx',
paddingTop: '5px',
paddingBottom: '5px',
border: 'none'
};
const suffixIconStyle = {
color: "#2c8ef2",
fontSize: "28px"
}
color: '#2c8ef2',
fontSize: '28px'
};
const listItemRefs = ref([]);
const taskRef = ref(null);
const tabAct = ref(0);
const inputValue = ref('');
const tabList = ref([{
name: '全 部'
}, {
name: '已完成'
}, {
name: '未完成'
}]);
const tabList = ref([
{
name: '全 部'
},
{
name: '已完成'
},
{
name: '未完成'
}
]);
const tabChange = (item) => {
tabAct.value = item.index;
@@ -84,21 +81,28 @@
const swiperChange = (item) => {
tabAct.value = item.detail.current;
};
const search = (value) => {
listItemRefs.value[tabAct.value]?.search(value);
};
onMounted(() => {
watch(tabAct, (newValue, oldValue) => {
typeof listItemRefs.value[newValue]?.getData === 'function' && listItemRefs.value[newValue]
?.getData('first')
}, {
immediate: true
}) // 这里的immediate会在onMounted之后执行
})
watch(
tabAct,
(newValue, oldValue) => {
typeof listItemRefs.value[newValue]?.getData === 'function' &&
listItemRefs.value[newValue]?.getData('first');
},
{
immediate: true
}
); // 这里的immediate会在onMounted之后执行
});
</script>
<style lang="scss" scoped>
$bg-margin-left: 50rpx;
.my_tabs {
// 解决这个圆角的图片,开穿透
:deep(.uv-tabs__wrapper__nav__line) {
height: 26rpx !important;
@@ -116,7 +120,7 @@
tab切换栏高度88rpx
下方滑动区域上下边距各10共20rpx
**/
height: calc(100vh - var(--status-bar-height) - 88rpx - 80rpx - 88rpx - 20rpx);
}
@@ -139,7 +143,7 @@
}
.detail-main {
background-color: #F6F8FF;
background-color: #f6f8ff;
overflow: hidden;
}
@@ -150,15 +154,14 @@
font-weight: 600;
line-height: 34rpx;
}
.fixed_search_input_div{
.fixed_search_input_div {
width: 100%;
height: 80rpx;
padding: 0 22rpx;
// background-color: red;
background-color: #fff;
:deep(.uv-input.uv-input--radius) {
border-radius:16rpx !important;
border-radius: 16rpx !important;
}
}
.fixed_search_div {
@@ -171,11 +174,11 @@
// background-color: red;
// height: 180rpx;
position: relative;
.back_div {
position: absolute;
left: 20rpx;
top: var(--status-bar-height);
top: var(--status-bar-height);
padding: 10rpx;
.back-icon {
@@ -205,4 +208,4 @@
}
}
}
</style>
</style>
-4
View File
@@ -366,10 +366,6 @@
<style scoped lang="scss">
$bg-margin-left: 50rpx;
// 下方单元格
.cell_div {
margin: 30rpx $bg-margin-left 0 $bg-margin-left;
@@ -0,0 +1,355 @@
<template>
<view class="main_div max_page">
<scroll-view
ref="scrollRef"
:scroll-y="true"
class="scroll-Y"
:refresher-enabled="false"
:show-scrollbar="false"
@scrolltolower="scrolltolower"
@refresherrefresh="onRefresh"
@refresherrestore="triggered = 'restore'"
:refresher-triggered="triggered"
refresher-default-style="none"
>
<view class="content">
<view
style="
position: absolute;
top: -90rpx;
width: 100%;
height: 90rpx;
display: flex;
align-items: center;
justify-content: center;
"
></view>
<view class="item" v-for="(item, index) in data_list" @click="read">
<view class="icon">
<image
v-if="item.noticeTyp == '01'"
class="img_100"
src="@/static/images/messageNotification/type_01.png"
mode="widthFix"
></image>
<image
v-if="item.noticeTyp == '02'"
class="img_100"
src="@/static/images/messageNotification/type_02.png"
mode="widthFix"
></image>
<image
v-if="item.noticeTyp == '03'"
class="img_100"
src="@/static/images/messageNotification/type_03.png"
mode="widthFix"
></image>
</view>
<view class="right">
<view class="top">
<view class="title">
{{ item.noticeTitle }}
</view>
<view class="time">
{{ item.ctTime?.substr(0, 16) }}
</view>
</view>
<view class="bottom">
<view class="note ellipsis-text">
{{ item.noticeContent }}
</view>
<!-- <view class="num_div"></view> -->
<view class="read_div" v-if="item.isRead"></view>
</view>
</view>
</view>
<uv-load-more v-if="total != 0" :status="status" loadmore-text="轻轻上拉加载" :height="30"></uv-load-more>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, reactive, nextTick, onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { queryTraPersonalMessageNoticePaging } from '@/api/messageNotification.js';
const customStyle = {
backgroundColor: '#ffffff',
paddingLeft: '40rpx',
height: '78rpx',
paddingTop: '5px',
paddingBottom: '5px',
border: 'none'
};
const suffixIconStyle = {
color: '#2c8ef2',
fontSize: '50rpx'
};
const options = [
{
text: '删除',
style: {
backgroundColor: '#f56c6c'
}
}
];
const status = ref('loadmore'); // loadmore - 加载前,loading - 加载中,nomore - 没有数据
const limit = 15;
const total = ref(-1);
const page = ref(0);
const data_list = reactive([]);
const triggered = ref(false);
const _freshing = ref(false);
const offset = ref(0);
const scrollRef = ref(null);
// 下拉过程中触发
const onPulling = (e) => {
page.value = 1;
total.value = -1;
page.data_list.length = 0;
getData();
};
// 刷新处理函数
const onRefresh = () => {
if (_freshing.value) return;
_freshing.value = true;
setTimeout(() => {
triggered.value = false;
_freshing.value = false;
}, 1000);
};
const getData = (from = '') => {
if (from == 'first') {
if (total.value !== -1) {
return;
}
status.value = 'loading';
total.value = -1;
page.value = 1;
data_list.length = 0;
} else {
if (status.value !== 'loadmore' && status.value !== '') return;
status.value = 'loading';
page.value++;
}
console.log(status.value, '阿斯顿撒');
setTimeout(() => {
queryTraPersonalMessageNoticePaging({
page: page.value,
limit: limit
})
.then((res) => {
total.value = res.total;
data_list.push(...res.body);
})
.finally(() => {
if (data_list.length >= total.value) {
status.value = 'nomore';
} else {
status.value = 'loadmore';
}
});
}, 200);
};
const scrolltolower = (item) => {
getData();
};
onMounted(() => {
// triggered.value = true;
getData();
// setTimeout(() => {
// triggered.value = true
// message_list.value.push(...[1, 2, 3, 4, 5])
// }, 1000)
console.log(scrollRef.value);
});
</script>
<style scoped lang="scss">
.pulldown-loading-box {
position: fixed;
left: 0;
right: 0;
z-index: 3;
transform: translateY(-100%);
transition: transform 0.3s;
z-index: 1;
}
.scroll-Y {
height: calc(100vh - 70rpx - var(--status-bar-height) - 78rpx - 40rpx);
position: relative;
overflow: hidden;
border-radius: 20rpx 20rpx 0 0;
.content {
width: 100%;
background-color: #fff;
box-shadow: 0 0 6rpx #b3d6ff;
position: relative;
.item {
height: 154rpx;
padding: 38rpx 0 38rpx 0;
margin: 0 38rpx;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 2rpx solid #efefef;
.icon {
width: 78rpx;
height: 78rpx;
}
.right {
margin-left: 16rpx;
flex: 1;
.top {
display: flex;
justify-content: space-between;
.title {
font-family: PingFangSC;
font-weight: 600;
font-size: 30rpx;
color: #000000;
line-height: 46rpx;
text-align: left;
font-style: normal;
}
.time {
font-size: 23rpx;
color: #999999;
line-height: 30rpx;
text-align: right;
font-style: normal;
}
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
width: 100%;
.note {
font-family: PingFangSC;
font-weight: 400;
font-size: 26rpx;
color: #666666;
line-height: 35rpx;
text-align: left;
font-style: normal;
flex: 1;
}
.num_div {
padding: 0 8rpx;
height: 31rpx;
background: #ff6c75;
border-radius: 15rpx;
display: flex;
align-items: center;
justify-content: center;
font-family: ArialMT;
font-size: 22rpx;
color: #ffffff;
line-height: 26px;
min-width: 40rpx;
}
.read_div {
width: 16rpx;
height: 16rpx;
background-color: #d70c18;
border-radius: 100%;
}
}
}
}
}
}
.main_div {
display: flex;
flex-direction: column;
align-items: center;
background: linear-gradient(0deg, rgba(234, 246, 255, 0) 0%, #c3e6ff 100%);
// background-size: 100% 300px;
// background-repeat: no-repeat; /* 防止渐变重复平铺 */
padding-top: var(--status-bar-height);
overflow: hidden;
}
.body-title {
width: 100%;
height: 70rpx;
font-size: 33rpx;
padding-top: 10rpx;
font-weight: 500;
color: #000;
position: relative;
text-align: center;
.delete_div {
position: absolute;
right: 20rpx;
top: 17rpx;
width: 50rpx;
height: 50rpx;
.img {
width: 34rpx;
height: 34rpx;
}
}
.back_div {
position: absolute;
left: 26rpx;
height: 34rpx;
top: 17rpx;
.back-icon {
position: relative;
width: 50rpx;
height: 50rpx;
cursor: pointer;
display: flex;
align-items: center;
}
.back-icon::before,
.back-icon::after {
content: '';
position: absolute;
transition: all 0.3s ease;
}
.back-icon::after {
top: 25%;
left: 25%;
width: 40%;
height: 40%;
border-top: 4rpx solid #2b2c2e;
border-left: 4rpx solid #2b2c2e;
transform: rotate(-45deg);
}
}
}
.input-view {
width: 90%;
margin: 20rpx auto;
height: 78rpx;
}
</style>
+291 -198
View File
@@ -1,256 +1,349 @@
<template>
<view class="main_div max_page">
<view class="body-title">
<view class="back_div" @click="common.navigateBack()">
<view class="back_div">
<view class="back-icon"></view>
</view>
<view>消息</view>
<view class="delete_div" @click="common.navigateBack()">
<image class="img" src="@/static/images/messageNotification/delete_icon.png" mode="aspectFit">
</image>
<view class="delete_div">
<image class="img" src="@/static/images/messageNotification/delete_icon.png" mode="aspectFit"></image>
</view>
</view>
<view class="input-view">
<uv-input shape="circle" placeholderStyle='color:#999999;font-size:28rpx' placeholder="请输入关键词"
suffixIcon="search" :customStyle="customStyle" :suffixIconStyle="suffixIconStyle">
</uv-input>
<uv-input
shape="circle"
placeholderStyle="color:#999999;font-size:28rpx"
placeholder="请输入关键词"
suffixIcon="search"
:customStyle="customStyle"
:suffixIconStyle="suffixIconStyle"
></uv-input>
</view>
<scroll-view ref="scrollRef" scroll-y="true" class="scroll-Y" :refresher-enabled="true"
@refresherrefresh="onRefresh" @refresherrestore="triggered = 'restore'" :refresher-triggered="triggered"
refresher-default-style="none">
<!-- 主体 -->
<view class="content">
<view style="position: absolute;top: -90rpx;width: 100%;height: 90rpx;"> </view>
<uv-swipe-action>
<uv-swipe-action-item :options="options" :threshold="40" :index="index"
v-for="(item, index) in data_list">
<view class="item">
<view class="icon">
<image class="img_100" :src="`@/static/images/messageNotification/type_${item.noticeTyp}.png`" mode="widthFix"></image>
</view>
<view class="right">
<view class="top">
<view class="title">
{{item.noticeTitle}}
</view>
<view class="time">
{{item.ctTime.substr(0, 16)}}
</view>
</view>
<view class="bottom">
<view class="note ellipsis-text">
{{item.noticeContent}}
</view>
<view class="num_div">
</view>
</view>
</view>
<scroll-view
ref="scrollRef"
:scroll-y="true"
class="scroll-Y"
:refresher-enabled="false"
:show-scrollbar="false"
@scrolltolower="scrolltolower"
@refresherrefresh="onRefresh"
@refresherrestore="triggered = 'restore'"
:refresher-triggered="triggered"
refresher-default-style="none"
>
<view class="item" v-for="(item, index) in data_list" @click="readMessage(item)">
<view class="icon">
<image
v-if="item.noticeTyp == '01'"
class="img_100"
src="@/static/images/messageNotification/type_01.png"
mode="widthFix"
></image>
<image
v-if="item.noticeTyp == '02'"
class="img_100"
src="@/static/images/messageNotification/type_02.png"
mode="widthFix"
></image>
<image
v-if="item.noticeTyp == '03'"
class="img_100"
src="@/static/images/messageNotification/type_03.png"
mode="widthFix"
></image>
</view>
<view class="right">
<view class="top">
<view class="title">
{{ item.noticeTitle }}
</view>
</uv-swipe-action-item>
</uv-swipe-action>
<uv-load-more v-if="total != 0" :status="status" loadmore-text="轻轻上拉加载" :height="30"></uv-load-more>
<view class="time">
{{ item.ctTime?.substr(0, 16) }}
</view>
</view>
<view class="bottom">
<view class="note ellipsis-text">
{{ item.noticeContent }}
</view>
<!-- <view class="num_div"></view> -->
<view class="read_div" v-if="item.isRead"></view>
</view>
</view>
</view>
<list-no-data v-if="total == 0 && status == 'nomore'"></list-no-data>
<uv-load-more v-if="total != 0" :status="status" loadmore-text="轻轻上拉加载" :height="30"></uv-load-more>
</scroll-view>
<uni-popup ref="popup" type="bottom">
<view class="popup" @click.stop="getCode">
<view class="message_popup_div">
<view class="title">
{{ popup_info.title }}
</view>
<view class="text">消正息内容正文消息内容正文</view>
<view class="button_div" @click.stop="getCode">
<uv-button class="button">我知道了</uv-button>
</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script setup>
import {
ref,
reactive,
nextTick,
onMounted
} from 'vue'
import {
onLoad
} from '@dcloudio/uni-app'
import {
queryTraPersonalMessageNoticePaging
} from '@/api/messageNotification.js';
import { ref, reactive, nextTick, onMounted } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { queryTraPersonalMessageNoticePaging } from '@/api/messageNotification.js';
const customStyle = {
backgroundColor: "#ffffff",
paddingLeft: "40rpx",
backgroundColor: '#ffffff',
paddingLeft: '40rpx',
height: '78rpx',
paddingTop: "5px",
paddingBottom: "5px",
border: "none"
}
paddingTop: '5px',
paddingBottom: '5px',
border: 'none'
};
const suffixIconStyle = {
color: "#2c8ef2",
fontSize: "50rpx"
}
const options = [{
text: '删除',
style: {
backgroundColor: '#f56c6c'
color: '#2c8ef2',
fontSize: '50rpx'
};
const options = [
{
text: '删除',
style: {
backgroundColor: '#f56c6c'
}
}
}]
const status = ref('loadmore') // loadmore - 加载前,loading - 加载中,nomore - 没有数据
const limit = 15
const total = ref(-1)
const page = ref(0)
const data_list = reactive([])
const triggered = ref(false)
const _freshing = ref(false)
const offset = ref(0)
const scrollRef = ref(null)
];
const status = ref('loadmore'); // loadmore - 加载前,loading - 加载中,nomore - 没有数据
const limit = 15;
const total = ref(-1);
const page = ref(0);
const data_list = reactive([]);
const triggered = ref(false);
const _freshing = ref(false);
const offset = ref(0);
const scrollRef = ref(null);
const popup_info = reactive({
id: '',
title: '',
text: ''
});
const popup = ref(null);
// 下拉过程中触发
const onPulling = (e) => {
console.log("onpulling", e)
}
page.value = 1;
total.value = -1;
page.data_list.length = 0;
getData();
};
// 刷新处理函数
const onRefresh = () => {
if (_freshing.value) return
_freshing.value = true
if (_freshing.value) return;
_freshing.value = true;
setTimeout(() => {
triggered.value = false
_freshing.value = false
}, 1000)
}
triggered.value = false;
_freshing.value = false;
}, 1000);
};
const getData = (from = '') => {
if (from == 'first') {
if (total.value !== -1) {
return
return;
}
status.value = 'loading'
total.value = -1
page.value = 1
data_list.length = 0
status.value = 'loading';
total.value = -1;
page.value = 1;
data_list.length = 0;
} else {
if (status.value !== 'loadmore' && status.value !== '') return
status.value = 'loading'
page.value++
if (status.value !== 'loadmore' && status.value !== '') return;
status.value = 'loading';
page.value++;
}
console.log(status.value, '阿斯顿撒');
setTimeout(() => {
queryTraPersonalMessageNoticePaging({
page: page.value,
limit: limit
}).then(res => {
total.value = res.total
data_list.push(...res.body)
}).finally(() => {
if (data_list.length >= total.value) {
status.value = 'nomore'
} else {
status.value = 'loadmore'
}
queryTraPersonalMessageNoticePaging({
page: page.value,
limit: limit
})
.then((res) => {
total.value = res.total;
data_list.push(...res.body);
})
}, 200)
}
.finally(() => {
if (data_list.length >= total.value) {
status.value = 'nomore';
} else {
status.value = 'loadmore';
}
});
};
// 读取消息
const readMessage = (item) => {
console.log('readMessage', item);
popup_info.id = item.noticeId;
popup_info.title = item.noticeTitle;
popup_info.text = item.noticeContent;
// popup_info.id = '';
// popup_info.title = '课程提醒';
// popup_info.text = '这里是水水哈斯滴撒的撒嗲是对赛道';
popup.value.open();
};
const scrolltolower = (item) => {
getData();
};
onMounted(() => {
triggered.value = true
getData()
// triggered.value = true;
getData();
// setTimeout(() => {
// triggered.value = true
// message_list.value.push(...[1, 2, 3, 4, 5])
// }, 1000)
console.log(scrollRef.value);
})
});
</script>
<style scoped lang="scss">
.pulldown-loading-box {
position: fixed;
left: 0;
right: 0;
z-index: 3;
transform: translateY(-100%);
transition: transform .3s;
z-index: 1;
.popup{
width: 100vw;
height: 100vh;
position: relative;
}
.message_popup_div {
width: 580rpx;
border-radius: 38px;
background: #ffffff url('@/static/images/messageNotification/popup_bg.png') no-repeat center -4rpx;
background-size: auto 50%;
background-color: #ffffff;
margin: 0 auto;
overflow: hidden;
top: 30%;
position: absolute;
left: calc(50% - 290rpx);
.title {
padding: 0 40rpx;
width: 100%;
height: 90rpx;
line-height: 90rpx;
font-weight: 700;
text-align: center;
}
.text {
padding: 16rpx 40rpx;
font-family: PingFangSC;
font-size: 30rpx;
color: #333333;
line-height: 48rpx;
text-align: left;
font-style: normal;
min-height: 240rpx;
max-height: 650rpx;
overflow: auto;
}
.button_div {
overflow: hidden;
.button {
width: 100%;
height: 100%;
:deep(.uv-button) {
height: 100rpx;
font-family: PingFangSC;
font-weight: 500;
font-size: 36rpx;
color: #0066ff;
}
}
}
}
.scroll-Y {
height: calc(100vh - 70rpx - var(--status-bar-height) - 78rpx - 40rpx);
position: relative;
overflow: hidden;
border-radius: 20rpx 20rpx 0 0;
position: relative;
background-color: #fff;
box-shadow: 0 0 6rpx #b3d6ff;
.content {
width: 100%;
height: 100%;
border-radius: 20rpx 20rpx 0 0;
background-color: #fff;
box-shadow: 0 0 6rpx #B3D6FF;
position: relative;
.item {
width: 100%;
height: 154rpx;
padding: 38rpx 38rpx 38rpx 38rpx;
display: flex;
justify-content: space-between;
align-items: center;
.item {
height: 154rpx;
padding: 38rpx 0 38rpx 0;
margin: 0 38rpx;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 2rpx solid #efefef;
.icon {
width: 78rpx;
height: 78rpx;
}
.icon {
width: 78rpx;
height: 78rpx;
}
.right {
margin-left: 16rpx;
flex: 1;
.right {
margin-left: 16rpx;
flex: 1;
.top {
display: flex;
justify-content: space-between;
.top {
display: flex;
justify-content: space-between;
.title {
font-family: PingFangSC;
font-weight: 600;
font-size: 30rpx;
color: #000000;
line-height: 46rpx;
text-align: left;
font-style: normal;
}
.time {
font-size: 23rpx;
color: #999999;
line-height: 30rpx;
text-align: right;
font-style: normal;
}
.title {
font-family: PingFangSC;
font-weight: 600;
font-size: 30rpx;
color: #000000;
line-height: 46rpx;
text-align: left;
font-style: normal;
}
.bottom {
.time {
font-size: 23rpx;
color: #999999;
line-height: 30rpx;
text-align: right;
font-style: normal;
}
}
.bottom {
display: flex;
justify-content: space-between;
align-items: center;
overflow: hidden;
width: 100%;
.note {
font-family: PingFangSC;
font-weight: 400;
font-size: 26rpx;
color: #666666;
line-height: 35rpx;
text-align: left;
font-style: normal;
flex: 1;
}
.num_div {
padding: 0 8rpx;
height: 31rpx;
background: #ff6c75;
border-radius: 15rpx;
display: flex;
justify-content: space-between;
.note {
font-family: PingFangSC;
font-weight: 400;
font-size: 26rpx;
color: #999999;
line-height: 34rpx;
text-align: left;
font-style: normal;
}
.num_div {
padding: 0 8rpx;
height: 31rpx;
background: #FF6C75;
border-radius: 15rpx;
display: flex;
align-items: center;
justify-content: center;
font-family: ArialMT;
font-size: 22rpx;
color: #FFFFFF;
line-height: 26px;
min-width: 40rpx;
}
align-items: center;
justify-content: center;
font-family: ArialMT;
font-size: 22rpx;
color: #ffffff;
line-height: 26px;
min-width: 40rpx;
}
.read_div {
width: 16rpx;
height: 16rpx;
background-color: #d70c18;
border-radius: 100%;
}
}
}
@@ -261,10 +354,11 @@
display: flex;
flex-direction: column;
align-items: center;
background: linear-gradient(0deg, rgba(234, 246, 255, 0) 0%, #C3E6FF 100%);
// background-size: 100% 300px;
// background-repeat: no-repeat; /* 防止渐变重复平铺 */
background: linear-gradient(0deg, rgba(195, 219, 255, 0) 0%, #c3dbff 100%);
background-size: 100% 300px;
background-repeat: no-repeat; /* 防止渐变重复平铺 */
padding-top: var(--status-bar-height);
overflow: hidden;
}
.body-title {
@@ -328,6 +422,5 @@
width: 90%;
margin: 20rpx auto;
height: 78rpx;
}
</style>
+10 -10
View File
@@ -51,12 +51,8 @@
const _freshing = ref(false)
const offset = ref(0)
const scrollRef = ref(null)
const props = defineProps({
searchText: {
type: String,
default: ''
},
index: {
type: Number,
default: 0
@@ -75,8 +71,8 @@
}, 1000)
}
const getData = (from = '') => {
console.log('getDatagetDatagetDatagetDatagetDatagetDatagetData');
const getData = (from = '', searchText='') => {
if (from == 'first') {
if (total.value !== -1) return;
status.value = 'loading'
@@ -91,7 +87,7 @@
setTimeout(() => {
let params = {
papersName: props.searchText,
papersName: searchText,
page: page.value,
limit: limit,
}
@@ -119,9 +115,13 @@
const scrolltolower = () => {
getData()
};
const search = (value) => {
console.log('searchvalue', value);
total.value = -1
getData('first', value)
}
defineExpose({
getData
getData, search
})
</script>
+9 -13
View File
@@ -7,11 +7,8 @@
<view>考试中心</view>
</view>
<view class="input-view">
<uv-input shape="circle" placeholderStyle='color:#999999;font-size:28rpx' placeholder="请输入关键词"
suffixIcon="search" :customStyle="customStyle" :suffixIconStyle="suffixIconStyle" confirmType="search"
v-model="searchText" @confirm="search">
</uv-input>
<view class="search_div" @click="search"></view>
<search-input placeholder="请输入考试名" @search="search"></search-input>
<!-- <view class="search_div" @click="search"></view> -->
</view>
<view class="body-tab">
<uv-tabs class="font_pf my_tabs" :current="tabAct" :list="tabList" @change="tabChange" :scrollable="false"
@@ -22,15 +19,15 @@
<swiper class="swiper" :current="tabAct" :indicator-dots="false" @change="swiperChange">
<swiper-item>
<Content :ref="el => contentRefs[0] = el" :index="tabAct" :searchText="searchText"
<Content :ref="el => contentRefs[0] = el" :index="tabAct"
@gotoDetails="gotoDetails"></Content>
</swiper-item>
<swiper-item>
<Content :ref="el => contentRefs[1] = el" :index="tabAct" :searchText="searchText"
<Content :ref="el => contentRefs[1] = el" :index="tabAct"
@gotoDetails="gotoDetails"></Content>
</swiper-item>
<swiper-item>
<Content :ref="el => contentRefs[2] = el" :index="tabAct" :searchText="searchText"
<Content :ref="el => contentRefs[2] = el" :index="tabAct"
@gotoDetails="gotoDetails"></Content>
</swiper-item>
</swiper>
@@ -72,7 +69,7 @@
} from '@/enum.js'
const contentRef = ref(null);
const tabAct = ref(0);
const searchText = ref('');
const tabList = ref([{
name: '全 部'
}, {
@@ -96,16 +93,15 @@
const swiperChange = (item) => {
tabAct.value = item.detail.current;
};
const search = () => {
if (searchText.value === '') return;
console.log('搜索', searchText.value);
const search = (value) => {
console.log('value', value);
contentRefs.value[tabAct.value]?.search(value);
}
const gotoDetails = (item) => {
setPageCache('testing_hall_details', item)
common.navigateTo('/pages/testingHall/details');
}
onMounted(() => {
triggered.value = true
watch(tabAct, (newValue, oldValue) => {
typeof contentRefs.value[newValue]?.getData === 'function' && contentRefs.value[newValue]
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB