反馈修改

dev
lion 12 months ago
parent 54a55adc08
commit d4d6363bd3

@ -4,7 +4,7 @@
<view class="nav-btn" @tap="prevMonth"></view>
<text class="month-text">{{ displayYear }}{{ displayMonthText }}</text>
<view class="nav-btn" @tap="nextMonth"></view>
<text class="back-today" @tap="backToday"></text>
<!-- <text class="back-today" @tap="backToday"></text> -->
</view>
<view class="weekdays">
@ -16,8 +16,8 @@
<view class="row" v-for="(row, rIdx) in weeks" :key="rIdx">
<view class="cell" v-for="cell in row" :key="cell.fullDate" :style="'height:'+cellHeight+'rpx'" @tap="onDayClick(cell.fullDate)">
<text class="date-num" :class="{ dim: !cell.inMonth }">{{ cell.date }}</text>
<view class="cell-events">
<view v-for="ev in eventsForDate(cell.fullDate)" :key="ev.id" class="event-chip" :class="'event-type-' + (ev.type || 'default')" :style="ev && ev.color ? ('background:'+ev.color+';') : ''" @tap="onEventClick(ev)">
<view class="cell-events" :style="'padding-top:'+getCellPadding(cell.fullDate)+'rpx'">
<view v-for="ev in eventsForDate(cell.fullDate)" :key="ev.id" class="event-chip" :class="['event-type-' + (ev.type || 'default'), { 'single-line-open': isSingleEvent(cell.fullDate), 'conflict': hasSpanConflict(cell.fullDate) }]" :style="'background:' + ((ev && ev.color) ? ev.color : '#ddba99') + ';'+ (hasSpanConflict(cell.fullDate) ? 'margin-top:6rpx;' : '')" @tap="onEventClick(ev)">
{{ formatTitle(ev.title) }}
</view>
</view>
@ -26,7 +26,7 @@
<!-- 跨天覆盖层 -->
<view class="overlay">
<view v-for="(seg, si) in continuousSegments" :key="si" class="continuous-bar" :style="'left:'+seg._style.left+';width:'+seg._style.width+';top:'+seg._style.top+';height:'+seg._style.height+';line-height:'+seg._style.height+';'+(seg.color?('background:'+seg.color+';'):'')" :class="'event-type-' + (seg.type || 'default')" @tap="onSegmentClick(seg)">
<view v-for="(seg, si) in continuousSegments" :key="si" class="continuous-bar" :style="'left:'+seg._style.left+';width:'+seg._style.width+';top:'+seg._style.top+';height:'+seg._style.height+';'+(seg._isOnlyOne ? '' : ('line-height:'+seg._style.height+';'))+(seg.color?('background:'+seg.color+';'):'background:#ddba99;')" :class="['event-type-' + (seg.type || 'default'), { 'nobreak': seg._isOnlyOne } ]" @tap="onSegmentClick(seg)">
{{ formatTitle(seg.title) }}
</view>
</view>
@ -43,6 +43,7 @@ export default {
type: String,
required: true
},
events: { // [{ id, title, type, start_time, end_time }]
type: Array,
default: () => []
@ -137,7 +138,7 @@ export default {
return ['日','一','二','三','四','五','六']
},
weeks() {
// 6x7
//
const firstDay = new Date(this.baseDate)
if (!(firstDay instanceof Date) || isNaN(firstDay.getTime())) return []
const startDow = firstDay.getDay()
@ -145,8 +146,16 @@ export default {
const gridStart = new Date(firstDay)
gridStart.setDate(1 - offset)
//
const lastDay = new Date(this.baseDate.getFullYear(), this.baseDate.getMonth() + 1, 0)
const lastDayOfMonth = lastDay.getDate()
//
const totalDays = offset + lastDayOfMonth
const neededWeeks = Math.ceil(totalDays / 7)
const weeks = []
for (let w = 0; w < 6; w += 1) {
for (let w = 0; w < neededWeeks; w += 1) {
const row = []
for (let d = 0; d < 7; d += 1) {
const cur = new Date(gridStart)
@ -164,8 +173,9 @@ export default {
return weeks
},
gridHeightPx() {
// rpx
return this.headerHeight + this.weekHeaderHeight + this.cellHeight * 6
// rpx
const actualWeeks = this.weeks.length
return this.headerHeight + this.weekHeaderHeight + this.cellHeight * actualWeeks
},
continuousSegments() {
//
@ -226,8 +236,23 @@ export default {
}
})
//
const segCountByDate = {}
const addDateKey = (ms) => {
const d = new Date(ms)
d.setHours(0,0,0,0)
const key = `${d.getFullYear()}-${this.pad2(d.getMonth()+1)}-${this.pad2(d.getDate())}`
segCountByDate[key] = (segCountByDate[key] || 0) + 1
}
segs.forEach(seg => {
for (let t = seg.segStartMs; t <= seg.segEndMs; t += 86400000) {
addDateKey(t)
}
})
// lane,
const byWeek = {}
const laneCountByDate = {}
segs.forEach(s => {
const key = s.weekStartISO
if (!byWeek[key]) byWeek[key] = []
@ -251,6 +276,12 @@ export default {
seg.laneIndex = laneEnd.length
laneEnd.push(seg.endCol)
}
//
for (let t = seg.segStartMs; t <= seg.segEndMs; t += 86400000) {
const d = new Date(t)
const key = `${d.getFullYear()}-${this.pad2(d.getMonth()+1)}-${this.pad2(d.getDate())}`
laneCountByDate[key] = Math.max(laneCountByDate[key] || 0, seg.laneIndex + 1)
}
})
})
@ -289,20 +320,58 @@ export default {
const widthPct = seg.spanCols * cellWidthPct
const vOffset = (seg.laneIndex || 0) * (this.barHeight + this.barSpacing)
const innerTopPadding = 8 // ,
const topRpx = (row * this.cellHeight) + this.dateNumberHeight + innerTopPadding + vOffset - 10
const topRpx = (row * this.cellHeight) + this.dateNumberHeight + innerTopPadding + vOffset - 3
//
const maxLeftPct = 100 - widthPct
const finalLeftPct = Math.min(leftPct, maxLeftPct)
seg._style = {
left: leftPct + '%',
left: finalLeftPct + '%',
width: widthPct + '%',
top: topRpx + 'rpx',
height: heightRpx + 'rpx'
}
//
let onlyOne = true
for (let t = seg.segStartMs; t <= seg.segEndMs; t += 86400000) {
const d = new Date(t)
const key = `${d.getFullYear()}-${this.pad2(d.getMonth()+1)}-${this.pad2(d.getDate())}`
const segCnt = segCountByDate[key] || 0
const singleCnt = (this.eventsForDate(key) || []).length //
if (!(segCnt === 1 && singleCnt === 0)) { onlyOne = false; break }
}
seg._isOnlyOne = onlyOne
})
// &
this.laneCountByDate = laneCountByDate
this.segCountByDate = segCountByDate
return segs
}
},
methods: {
getCellPadding(fullDate) {
//
const lanes = this.laneCountByDate && this.laneCountByDate[fullDate] ? this.laneCountByDate[fullDate] : 0
if (!lanes) return 0
return lanes * (this.barHeight + this.barSpacing)
},
isSingleEvent(fullDate) {
try {
const list = this.eventsForDate(fullDate) || []
return list.length === 1
} catch (_) {
return false
}
},
hasSpanConflict(fullDate) {
//
const hasMulti = !!(this.segCountByDate && this.segCountByDate[fullDate] > 0)
const hasSingle = (this.eventsForDate(fullDate) || []).length > 0
return hasMulti && hasSingle
},
onEventClick(ev) {
this.$emit('eventClick', ev)
},
@ -413,30 +482,33 @@ export default {
<style scoped>
.calendar-grid {
background: #fff;
// border-radius: 18rpx;
/* border-radius: 18rpx; */
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
border-radius: 0 0 20rpx 20rpx;
/* margin: 20rpx;
padding: 10rpx 0 20rpx 0; */
}
.calendar-header {
position: relative;
display: flex;
justify-content: center;
justify-content: space-between;
align-items: center;
height: 46px;
border-bottom: 1px solid #ededed;
background:#eaf3fb;
color:#0d0398;
font-size:34rpx;
}
.nav-btn {
width: 40px;
text-align: center;
font-size: 20px;
color: #666;
font-size: 50rpx;
color: #333;
}
.month-text {
width: 140px;
text-align: center;
font-size: 15px;
color: #333;
font-size: 34rpx;
color:#0d0398;
}
.back-today {
position: absolute;
@ -452,15 +524,21 @@ export default {
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 6px 10px;
height: 32px;
height: 40px;
box-sizing: border-box;
color: #0d0398;
font-size: 28rpx;
}
.weekday {
width: 14.2857%;
text-align: center;
font-size: 12px;
color: #666;
font-size: 28rpx;
line-height: 40px;
color: #0d0398;
border-right: 1px solid #f2eae2;
}
.weekday:last-child {
border-right:none
}
.grid {
position: relative;
@ -472,46 +550,76 @@ export default {
.cell {
width: 14.2857%;
height: 120rpx;
border-bottom: 1px solid #f5f5f5;
border-top: 1px solid #f5f5f5;
border-right: 1px solid #f5f5f5;
border-top: 1px solid #f2eae2;
border-right: 1px solid #f2eae2;
position: relative;
padding: 2px 2px 2px 2px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
}
.row .cell:first-child {
border-left: 1px solid #f5f5f5;
.row .cell:last-child {
border-right:none
}
.date-num {
font-size: 12px;
font-size: 28rpx;
font-weight: 600;
color: #333;
position: relative;
z-index: 3;
text-align: center;
width: 100%;
margin-bottom: 4px;
}
.date-num.dim {
color: #bfbfbf;
}
.cell-events {
position: relative;
z-index: 3;
z-index: 2; /* 让跨天条位于其上方 */
width: 100%;
overflow: hidden;
}
.event-chip {
font-size: 11px;
line-height: 14px;
padding: 1px 3px;
padding: 2rpx 10rpx;
margin: 1px 0;
color: #fff;
border-radius: 3px;
border-radius: 16rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 100%;
box-sizing: border-box;
}
.event-chip.event-type-1 { background: #67C23A; }
.event-chip.event-type-2 { background: #409EFF; }
.event-chip.event-type-3 { background: #E6A23C; }
.event-chip.event-type-4 { background: #F56C6C; }
.event-chip.event-type-5 { background: #909399; }
.event-chip.event-type-default { background: #409EFF; }
.event-chip.event-type-default { background: #ddba99; }
/* 当天只有一条单天事件时,允许换行不省略 */
.event-chip.single-line-open {
white-space: normal;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3; /* 最多三行 */
-webkit-box-orient: vertical;
overflow: hidden;
}
/* 与跨天冲突时,单日事件强制两行省略并稍作下移 */
.event-chip.conflict {
white-space: normal !important;
display: -webkit-box !important;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2 !important;
overflow: hidden !important;
text-overflow: ellipsis !important;
margin-top: 6rpx;
}
.overlay {
position: absolute;
@ -520,7 +628,7 @@ export default {
right: 0;
bottom: 0;
pointer-events: none;
z-index: 2;
z-index: 4; /* 置于单日事件之上,避免被遮挡 */
}
.continuous-bar {
position: absolute;
@ -529,20 +637,35 @@ export default {
color: #fff;
font-size: 11px;
line-height: 18px;
padding: 0 4px;
border-radius: 3px;
padding: 0rpx 10rpx;
border-radius: 16rpx;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
background: #409EFF;
background: #ddba99;
text-align: center;
}
.continuous-bar.event-type-1 { background: linear-gradient(90deg, #67C23A 0%, #5CB85C 100%); }
.continuous-bar.event-type-2 { background: linear-gradient(90deg, #409EFF 0%, #337ecc 100%); }
.continuous-bar.event-type-3 { background: linear-gradient(90deg, #E6A23C 0%, #D4952B 100%); }
.continuous-bar.event-type-4 { background: linear-gradient(90deg, #F56C6C 0%, #E85555 100%); }
.continuous-bar.event-type-5 { background: linear-gradient(90deg, #909399 0%, #73767A 100%); }
.continuous-bar.event-type-default { background: linear-gradient(90deg, #409EFF 0%, #337ecc 100%); }
.continuous-bar.event-type-default { background: #ddba99; }
/* 跨天事件在整段期间独占时不省略,允许换行 */
.continuous-bar.nobreak {
white-space: normal;
word-break: break-all;
text-overflow: ellipsis;
height: auto !important; /* 允许多行内容自适应高度 */
line-height: 1.4;
padding-top: 6rpx;
padding-bottom: 6rpx;
display: -webkit-box;
-webkit-line-clamp: 3; /* 最多三行 */
-webkit-box-orient: vertical;
overflow: hidden;
}
</style>

@ -0,0 +1,260 @@
<template>
<view class="calendar-widget">
<!-- 月份切换加载指示器 -->
<!-- <view v-if="switchingMonth" class="month-loading">
<u-loading mode="circle" size="24"></u-loading>
<text class="loading-text">加载中...</text>
</view> -->
<!-- 自定义日历支持跨天横条显示 -->
<view class="calendar-title">学院日历</view>
<view class="calendar-container" :class="{ 'loading-opacity': switchingMonth }">
<CalendarGrid
:month="calendarDate"
:events="courses"
:rowHeightRpx="146"
:headerHeightRpx="60"
:weekHeaderHeightRpx="40"
:dateNumberHeightRpx="36"
@dayClick="onDateChange"
@monthChange="onMonthSwitch"
@edit="onEditEvent"
@eventClick="showCourseDetail"
/>
</view>
</view>
</template>
<script>
import CalendarGrid from '@/components/calendar-grid/calendar-grid.vue'
export default {
name: 'CalendarWidget',
components: {
CalendarGrid
},
data() {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0');
return {
calendarDate: `${year}-${month}`,
courses: [],
monthEvents: [],
loading: false,
switchingMonth: false
}
},
mounted() {
this.loadCourses()
},
methods: {
//
parseDateTime(dateTimeStr) {
if (!dateTimeStr) return null
const [datePart, timePart = '00:00:00'] = dateTimeStr.trim().split(/[T\s]+/)
const [y, m, d] = datePart.split('-').map(n => parseInt(n, 10))
const [hh = 0, mm = 0, ss = 0] = timePart.split(':').map(n => parseInt(n, 10))
return new Date(y, (m || 1) - 1, d || 1, hh || 0, mm || 0, ss || 0)
},
//
async loadCourses() {
if (this.loading) return
try {
this.loading = true
await this.loadCoursesForMonth(this.calendarDate)
} catch (error) {
console.error('加载课程数据失败:', error)
uni.showToast({
title: '加载日历数据失败',
icon: 'none'
})
} finally {
this.loading = false
}
},
//
async loadCoursesForMonth(monthDate) {
const res = await this.$u.api.calendarsGet({
month: monthDate
})
const rows = (res && res.data) ? res.data : (Array.isArray(res) ? res : [])
this.courses = Array.isArray(rows) ? rows : []
console.log('日历数据加载成功:', this.courses)
},
//
onDateChange({ fulldate }) {
const evs = this.getEventsForDate(fulldate)
if (evs.length) {
//
evs.sort((a,b) => this.parseDateTime(a.start_time) - this.parseDateTime(b.start_time))
this.showCourseDetail(evs[0])
}
},
//
async onMonthSwitch({ year, month }) {
const newDate = `${year}-${String(month).padStart(2, '0')}`
//
if (newDate === this.calendarDate) return
//
this.switchingMonth = true
try {
//
this.calendarDate = newDate
//
await this.loadCoursesForMonth(newDate)
} catch (error) {
console.error('月份切换失败:', error)
uni.showToast({
title: '切换月份失败',
icon: 'none'
})
} finally {
//
setTimeout(() => {
this.switchingMonth = false
}, 300)
}
},
//
onEditEvent(event) {
console.log('编辑事件:', event)
},
//
getEventsForDate(dateStr) {
const targetDate = new Date(dateStr)
targetDate.setHours(0, 0, 0, 0)
return this.courses.filter(ev => {
const startDate = this.parseDateTime(ev.start_time)
const endDate = ev.end_time ? this.parseDateTime(ev.end_time) : this.parseDateTime(ev.start_time)
if (!startDate || !endDate) return false
startDate.setHours(0,0,0,0)
endDate.setHours(0,0,0,0)
return targetDate >= startDate && targetDate <= endDate
})
},
//
showCourseDetail(ev) {
//
// type=1
// type=3
// type=4 webview
const type = ev.type
if (type === 1) {
if (ev.course_id) {
uni.navigateTo({ url: `/packages/course/detail?id=${ev.course_id}` })
return
}
// course_id
uni.showModal({
title: ev.title || '课程详情',
content: `时间:${ev.start_time}\n地点${ev.location || '待定'}`,
showCancel: false
})
return
}
if (type === 3) {
uni.showModal({
title: ev.title || '事件详情',
content: ev.content || '暂无详细信息',
showCancel: false
})
return
}
if (type === 4) {
if (ev.url) {
const encoded = ev.url
uni.navigateTo({ url: `/packages/webview/index?type=3&url=${encoded}` })
return
}
// url
uni.showModal({
title: ev.title || '资讯详情',
content: ev.content || '暂无详细信息',
showCancel: false
})
return
}
//
uni.showModal({
title: ev.title || '详情',
content: ev.content || '暂无详细信息',
showCancel: false
})
}
}
}
</script>
<style scoped>
.calendar-widget {
padding: 25rpx;
}
.month-loading {
display: flex;
align-items: center;
justify-content: center;
padding: 12rpx 20rpx;
background: rgba(255, 255, 255, 0.95);
border-radius: 20rpx;
margin-bottom: 12rpx;
position: relative;
z-index: 10;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
animation: slideDown 0.3s ease-out;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.loading-text {
margin-left: 12rpx;
font-size: 22rpx;
color: #666;
}
.loading-opacity {
opacity: 0.7;
transition: opacity 0.2s ease;
pointer-events: none;
}
.calendar-container {
margin-bottom: 0;
}
.calendar-title{
font-size: 34rpx;
color: #fff;
border-radius: 20rpx 20rpx 0 0;
text-align: center;
background:linear-gradient(90deg, #ddba99, #b18d6d);
padding:20rpx;
}
</style>

@ -30,26 +30,26 @@
@confirm="confirmCrop"
/> -->
<!-- 预览区 -->
<view v-if="croppedImage" class="crop-preview-wrap">
<view class="crop-preview">
<view class="preview-item">
<image :src="croppedImage" class="preview-circle small" mode="aspectFill" />
<view class="preview-label">小尺寸</view>
</view>
<view class="preview-item">
<image :src="croppedImage" class="preview-circle medium" mode="aspectFill" />
<view class="preview-label">中尺寸</view>
</view>
<view class="preview-item">
<image :src="croppedImage" class="preview-circle large" mode="aspectFill" />
<view class="preview-label">大尺寸</view>
</view>
<view v-if="croppedImage" class="crop-preview-wrap">
<view class="crop-preview">
<view class="preview-item">
<image :src="croppedImage" class="preview-circle small" mode="aspectFill" />
<view class="preview-label">小尺寸</view>
</view>
<view class="preview-item">
<image :src="croppedImage" class="preview-circle medium" mode="aspectFill" />
<view class="preview-label">中尺寸</view>
</view>
<view class="preview-item">
<image :src="croppedImage" class="preview-circle large" mode="aspectFill" />
<view class="preview-label">大尺寸</view>
</view>
</view>
<view class="form-btn">
<view @click="saveUser" type="primary">提交</view>
<view class="form-btn">
<view @click="saveUser" type="primary">提交</view>
</view>
</view>
</view>
<qf-image-cropper ref="qfCropper" v-if="showCropper" :width="400" :height="400" :radius="200"
@crop="uploadSuccess" @close="closeCrop"></qf-image-cropper>
@ -60,8 +60,8 @@
<script>
// uCropper https://ext.dcloud.net.cn/plugin?id=2713
import QfImageCropper from '@/uni_modules/qf-image-cropper/components/qf-image-cropper/qf-image-cropper.vue';
import {
ROOTPATH
import {
ROOTPATH
} from '@/common/config'
export default {
components: {
@ -75,10 +75,10 @@
loading: false,
success: false
}
},
onLoad(){
this.croppedImage = this.vuex_user.headimgurl?this.vuex_user.headimgurl:''
console.log("this.vuex_user.headimgurl",this.vuex_user.headimgurl)
},
onLoad(){
this.croppedImage = this.vuex_user.headimgurl?this.vuex_user.headimgurl:''
console.log("this.vuex_user.headimgurl",this.vuex_user.headimgurl)
},
methods: {
chooseImage() {
@ -98,53 +98,51 @@
});
},
uploadSuccess(res) {
console.log("res", res)
console.log("res", res)
this.saveAvatar(res.tempFilePath)
},
closeCrop(){
// this.croppedImage = ''
this.showCropper = false;
this.tempImage = '';
},
//
},
closeCrop(){
// this.croppedImage = ''
this.showCropper = false;
this.tempImage = '';
},
//
// userimg
async saveAvatar(file) {
if (!file) {
this.base.toast("请选择头像")
return
if (!file) {
this.base.toast("请选择头像")
return
};
this.loading = true;
//
await uni.uploadFile({
url: ROOTPATH + "/api/mobile/upload-file",
filePath: file,
name: 'file',
header: {
['Authorization']: `Bearer ${this.vuex_token}`
},
success: (res) => {
console.log("res",res)
let data = JSON.parse(res.data)
//
await uni.uploadFile({
url: ROOTPATH + "/api/mobile/upload-file",
filePath: file,
name: 'file',
header: {
['Authorization']: `Bearer ${this.vuex_token}`
},
success: (res) => {
console.log("res",res)
let data = JSON.parse(res.data)
this.croppedImage = data.url
this.showCropper = false;
this.tempImage = '';
}
})
this.tempImage = '';
}
})
},
async saveUser(files){
const res = await this.$u.api.saveUser({
headimgurl:this.croppedImage,
username:this.vuex_user.username
})
this.base.toast("更新成功",1500,function(){
setTimeout(function(){
uni.switchTab({
url:'/pages/me/index'
})
},1500)
})
},
async saveUser(files){
const res = await this.$u.api.saveUser({
headimgurl:this.croppedImage,
username:this.vuex_user.username
})
this.base.toast("更新成功",1500,function(){
setTimeout(function(){
uni.navigateBack()
},1500)
})
}
}
}
@ -186,7 +184,7 @@
justify-content: center;
}
.current-avatar image {
width: 240rpx;
width: 240rpx;
height: 240rpx;
border-radius: 50%;
}
@ -218,12 +216,12 @@
background-color: #fff;
}
.crop-preview{
display: flex;
justify-content: center;
gap: 30rpx;
text-align: center;
}
.crop-preview{
display: flex;
justify-content: center;
gap: 30rpx;
text-align: center;
}
.preview-item {
@ -270,20 +268,20 @@
border-radius: 20rpx;
margin: 30rpx 0;
text-align: center;
}
.form-btn {
width: 100%;
position: relative;
padding: 60rpx 0;
&>view {
width: 70%;
text-align: center;
margin: 0 auto;
color: #fff;
background: linear-gradient(to right, #5e5fbc, #0d0398);
border-radius: 30rpx;
padding: 20rpx;
}
}
.form-btn {
width: 100%;
position: relative;
padding: 60rpx 0;
&>view {
width: 70%;
text-align: center;
margin: 0 auto;
color: #fff;
background: linear-gradient(to right, #5e5fbc, #0d0398);
border-radius: 30rpx;
padding: 20rpx;
}
}
</style>

@ -0,0 +1,26 @@
<template>
<view class="container">
<image style="width:100%" :show-menu-by-longpress="true" :src="base.imgHost('hr.png')" mode="widthFix" alt=""/>
</view>
</template>
<script>
export default{
data(){
return{
}
},
onLoad() {
},
methods:{
}
}
</script>
<style scoped lang="scss">
.container{
width: 100vw;
height: 100vh;
}
</style>

@ -2,6 +2,12 @@
<view class="container">
<image class="cbg" :src="base.imgHost('common_bg.png')"></image>
<view class="wrap">
<!-- 头像 -->
<view style="display:flex;justify-content:center;align-items:center;padding: 30rpx 0;">
<view @click="changeAvatar" style="width:140rpx;height:140rpx;border-radius:140rpx;overflow:hidden;">
<image style="width:100%;height:100%;" :src="userAvatar?userAvatar:base.imgHost('login-logo.png')"></image>
</view>
</view>
<u-form :model="form" :label-width="140" ref="uForm" :label-align="'left'" :error-type="['message']">
<u-form-item label="姓名" prop="username">
{{form.username}}
@ -19,10 +25,10 @@
<u-form-item label="身份证号" prop="idcard">
<u-input type="idcard" border placeholder="请输入身份证号" v-model="form.idcard" />
</u-form-item>
<u-form-item label="出生日期" prop="birthday">
<u-input @click="dateShow=true" placeholder="请选择出生日期" v-model="form.birthday"
type="select" /></u-form-item>
</u-form-item>
<u-form-item label="出生日期" prop="birthday">
<u-input @click="dateShow=true" placeholder="请选择出生日期" v-model="form.birthday"
type="select" />
</u-form-item>
<u-form-item label="邮箱" prop="email">
<u-input v-model="form.email" border placeholder="请输入邮箱" /></u-form-item>
<u-form-item label="公司名称" prop="company_name">
@ -35,7 +41,7 @@
<u-form-item label="车牌" prop="plate">
<view style="display: flex;align-items: center;justify-content: space-between;">
<view v-if="plateList.length>0">
<view v-for="(item,index) in plateList">
<view v-for="(item,index) in plateList" :key="index">
{{item}}
<u-icon color="red" style="margin-left:20rpx" @click="delPlate(index)"
name="close"></u-icon>
@ -50,7 +56,7 @@
<view class="form-btn">
<view @click="saveUser" type="primary">提交</view>
</view>
</view>
</view>
<u-picker @confirm="dateConfirm" mode="time" v-model="dateShow" :params="dateParams"></u-picker>
<view class="modal">
<u-popup v-model="showPark" mode="bottom">
@ -103,6 +109,7 @@
},
data() {
return {
userAvatar: '',
showMobile: false,
myMobile: '',
myCode: '',
@ -120,15 +127,15 @@
'height': '80rpx',
'border': '1rpx solid #dad8d8;',
'border-radius': '20rpx 0 0 20rpx'
},
dateShow: false,
dateParams: {
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false
},
dateShow: false,
dateParams: {
year: true,
month: true,
day: true,
hour: false,
minute: false,
second: false
},
form: {
@ -195,10 +202,15 @@
this.sendTimer = null
}
},
methods: {
//
dateConfirm(e) {
this.form.birthday = e.year + '-' + e.month + '-' + e.day
methods: {
changeAvatar(){
uni.navigateTo({
url:'/packages/avatarUpload/index'
})
},
//
dateConfirm(e) {
this.form.birthday = e.year + '-' + e.month + '-' + e.day
},
addMobile() {
this.myMobile = this.form.mobile
@ -269,6 +281,8 @@
console.log("res", res)
// this.form = this.base.requestToForm(res.user, this.form)
this.form = this.base.deepCopy(res.user)
//
this.userAvatar = res.user && res.user.headimgurl ? res.user.headimgurl : ''
if (res.user.plate) {
this.plateList = res.user.plate.split(',')
this.plateList.map((item, index) => {

@ -1,10 +1,12 @@
<template>
<view class="container">
<image class="cbg" :src="base.imgHost('common_bg.png')"></image>
<view class="map-btn" @click="goToMap">
<!-- <view class="map-btn" @click="goToMap">
<u-icon name="map" color="#fff" size="32"></u-icon>
<text class="map-text">校友地图</text>
</view>
<view>按照姓名首字母顺序排列,排名不分先后</view>
<view>如需校友联系方式,可咨询班主任</view>
</view> -->
<view class="search">
<view class="search-icon" @click="showSearch=!showSearch">
<image :src="base.imgHost('search.png')"></image>
@ -27,11 +29,17 @@
<view class="wrap">
<view v-if="hasData">
<view class="tips">
<view>按照姓名首字母顺序排列,排名不分先后</view>
<view>如需校友联系方式,可咨询班主任</view>
<view class="map-btn" @click="goToMap">
<u-icon name="map" color="#fff" size="32"></u-icon>
<text class="map-text">校友地图</text>
</view>
<view class="map-btn map-setting" @click="showSetting=true">
<u-icon name="setting" color="#fff" size="32"></u-icon>
<text class="map-text">设置</text>
</view>
</view>
<scroll-view style="height:100vh" :scroll-y="true" @scrolltolower="scrollGet" class="list">
<view class="left-item-card" v-for="(mess,inx) in list">
<view class="left-item-card" v-for="(mess,inx) in list" :key="inx">
<view class="left-item-card-info">
<view class="left-item-card-name">
<view>
@ -44,6 +52,10 @@
style="font-size:28rpx;color:#666;margin-bottom:10rpx">
{{mess['company_position']?'职务:'+mess['company_position']:''}}
</view>
<view v-if="mess['open_mobile']"
style="font-size:28rpx;color:#666;margin-bottom:10rpx">
{{mess['mobile']?'联系方式:'+mess['mobile']:''}}
</view>
<view v-if="mess['company_product']"
style="font-size:28rpx;color:#666;margin-bottom:10rpx">
{{mess['company_product']?"主营业务:"+mess['company_product']:''}}
@ -112,6 +124,42 @@
<u-picker @confirm="selectIndustry" v-model="showIndustry" :range="selectArr.company_industry" range-key="value"
mode="selector"></u-picker>
<!-- 设置弹窗 -->
<u-popup v-model="showSetting" mode="center" border-radius="20" width="80%">
<view class="setting-popup">
<view class="setting-title">设置</view>
<view class="setting-tip">您想以下哪些学员能够查看到您的联系方式</view>
<view class="setting-list">
<!-- 同班同学 - 固定项 -->
<view class="setting-item setting-item-fixed">
<view class="setting-item-name">同班同学</view>
<u-checkbox
:value="true"
active-color="#b89155"
:disabled="true"
></u-checkbox>
</view>
<!-- 其他课程类型 -->
<view
v-for="item in courseType"
:key="item.id"
class="setting-item"
@click="toggleCourseType(item.id)"
>
<view class="setting-item-name">{{ item.name }}</view>
<u-checkbox
:value="selectedCourseTypes.includes(item.id)"
active-color="#b89155"
></u-checkbox>
</view>
</view>
<view class="setting-buttons">
<view class="setting-btn setting-btn-cancel" @click="showSetting=false"></view>
<view class="setting-btn setting-btn-confirm" @click="saveSettings"></view>
</view>
</view>
</u-popup>
</view>
</template>
@ -151,14 +199,43 @@
current_page: 1,
total_page: 0,
hasData: true,
letterList:["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
letterList:["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"],
courseType: [],
showSetting: false,
selectedCourseTypes: [] // ID
}
},
onLoad() {
this.getUserInfo()
this.getMyCourseTxl()
this.getIndustry()
this.getCourseType()
},
methods: {
//
async getCourseType() {
const res = await this.$u.api.otherConfig()
if(res.course_types_open_mobile && res.course_types_open_mobile.length>0){
this.courseType = res.course_types_open_mobile
}
},
async getUserInfo() {
const res = await this.$u.api.user()
this.$u.vuex('vuex_user', res.user)
//
if(res.user.open_course_types) {
this.selectedCourseTypes = res.user.open_course_types.split(',').map(id => parseInt(id)).filter(id => !isNaN(id))
} else {
this.selectedCourseTypes = []
}
if(res.user.open_course_types){
this.showSetting = false
}else{
this.showSetting = true
}
},
goToMap() {
uni.navigateTo({
url: '/packages/schoolmate/map'
@ -290,6 +367,40 @@
this.list = []
this.hasData = true
this.getMyCourseTxl()
},
//
toggleCourseType(courseId) {
const index = this.selectedCourseTypes.indexOf(courseId)
if (index > -1) {
this.selectedCourseTypes.splice(index, 1)
} else {
this.selectedCourseTypes.push(courseId)
}
},
//
async saveSettings() {
try {
const open_course_types = this.selectedCourseTypes.join(',')
await this.$u.api.saveUser({
open_course_types: open_course_types
})
//
await this.getUserInfo()
uni.showToast({
title: '设置保存成功',
icon: 'success'
})
this.showSetting = false
} catch (error) {
console.error('保存设置失败:', error)
uni.showToast({
title: '保存失败,请重试',
icon: 'none'
})
}
}
}
@ -311,16 +422,20 @@
height: 100vh;
}
.map-btn{
position: fixed;
top: 110rpx;
right: 20rpx;
z-index: 999;
background-color: #b89155;
padding: 10rpx 20rpx;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
// position: fixed;
// top: 110rpx;
// right: 20rpx;
z-index: 999;
background-color: #b89155;
padding: 15rpx 20rpx;
border-radius: 40rpx;
display: flex;
align-items: center;
justify-content: center;
width:60%;
}
.map-setting{
width:30%;
}
.map-text{
font-size: 28rpx;
@ -374,11 +489,14 @@
.tips{
font-size: 24rpx;
text-align: left;
padding-left:30rpx;
// padding-left:30rpx;
color:#999999;
margin-bottom:30rpx;
border-bottom:1rpx solid #cfd5d9;
padding-bottom:20rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.left-item-card {
width: 100%;
@ -531,6 +649,91 @@
}
}
//
.setting-popup {
padding: 40rpx;
background: #fff;
border-radius: 20rpx;
.setting-title {
font-size: 36rpx;
font-weight: 600;
color: #333;
text-align: center;
margin-bottom: 20rpx;
}
.setting-tip {
font-size: 28rpx;
color: #666;
text-align: center;
margin-bottom: 40rpx;
line-height: 1.5;
}
.setting-list {
max-height: 500rpx;
overflow-y: auto;
margin-bottom: 40rpx;
.setting-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 24rpx 0;
border-bottom: 1rpx solid #f0f0f0;
&:last-child {
border-bottom: none;
}
&.setting-item-fixed {
background: #f8f9fa;
padding: 24rpx 20rpx;
margin: 0 -20rpx 0 -20rpx;
border-radius: 12rpx 12rpx 0 0;
border-bottom: 2rpx solid #e9ecef;
.setting-item-name {
color: #666;
font-weight: 500;
}
}
.setting-item-name {
font-size: 30rpx;
color: #333;
flex: 1;
}
}
}
.setting-buttons {
display: flex;
justify-content: space-between;
gap: 20rpx;
.setting-btn {
flex: 1;
text-align: center;
padding: 24rpx;
border-radius: 12rpx;
font-size: 30rpx;
font-weight: 500;
&-cancel {
background: #f5f5f5;
color: #666;
}
&-confirm {
background: linear-gradient(to right, #e4cdb4, #c69c6d);
color: #fff;
}
}
}
}
}
</style>

@ -8,14 +8,41 @@
<text class="post-time">{{ detail.created_at }}</text>
</view>
<view class="stats">
<text class="type-badge" :class="detail.type === 1 ? 'supply' : 'demand'">{{ detail.type === 1 ? '供应' : '需求' }}</text>
<text class="type-badge" :class="detail.type === 1 ? 'supply' : detail.type === 2 ? 'demand' : detail.type === 3 ? 'finance' : 'industry'">{{ detail.type === 1 ? '供应' : detail.type === 2 ? '需求' : detail.type === 3 ? '投融资' : '' }}</text>
<text class="views">{{ detail.contact_count }}人私信 {{ detail.view_count }}浏览</text>
</view>
</view>
<view class="content-card">
<text class="title">{{ detail.title }}</text>
<text class="description">{{ detail.content }}</text>
<view class="content-card">
<text class="title">{{ detail.title }}</text>
<!-- 投融资专用信息展示 -->
<view v-if="detail.type === 3" class="finance-info">
<view class="finance-row">
<text class="label">资金类型</text>
<text class="value">{{ detail.fund_type || '-' }}</text>
</view>
<view class="finance-row">
<text class="label">金额</text>
<text class="value">{{ formatAmount(detail.amount) }}</text>
</view>
<view class="finance-row" v-if="detail.fund_stage">
<text class="label">融资阶段</text>
<text class="value">{{ detail.fund_stage }}</text>
</view>
<view class="finance-row" v-if="detail.expect_fund_attr">
<text class="label">期望资金属性</text>
<text class="value">{{ detail.expect_fund_attr }}</text>
</view>
<view class="finance-row" v-if="detail.industry_type">
<text class="label">行业类型</text>
<text class="value">{{ detail.industry_type }}</text>
</view>
<view class="finance-row" v-if="detail.product">
<text class="label">主要产品</text>
<text class="value">{{ detail.product }}</text>
</view>
</view>
<text class="description">{{ detail.type === 3 ? (detail.desc || detail.content) : detail.content }}</text>
<!-- 图片展示区域 -->
<view class="images-container" v-if="detail.files && detail.files.length > 0">
<view class="images-title">
@ -31,7 +58,7 @@
</view>
</view>
</view>
<view class="tags" v-if="detail.tag">
<view class="tags" v-if="detail.tag && detail.type !== 3">
<text v-for="tag in detail.tag.split(',')" :key="tag" class="tag">{{ tag }}</text>
</view>
<!-- 过期提示 -->
@ -169,6 +196,12 @@
this.fetchDetailData(options.id);
},
methods: {
formatAmount(val){
if(val==null||val==='') return '-'
const num = Number(val)
if(isNaN(num)) return String(val)
return num.toLocaleString(undefined,{minimumFractionDigits:2, maximumFractionDigits:2})
},
fetchDetailData(id) {
this.$u.api.supplyDemandDetail({ id: id }).then(res => {
console.log('详情数据:', res);
@ -411,6 +444,16 @@
color: #007aff;
}
.type-badge.finance {
background-color: #e6f0ff;
color: #007aff;
}
.type-badge.industry {
background-color: #e6f0ff;
color: #007aff;
}
.views {
font-size: 24rpx;
color: #909399;
@ -424,6 +467,25 @@
border-radius: 20rpx;
}
/* 投融资信息块 */
.finance-info {
background: #fffaf3;
border: 1rpx solid #f5e6cd;
border-radius: 14rpx;
padding: 20rpx;
margin-bottom: 20rpx;
}
.finance-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12rpx 0;
border-bottom: 1rpx solid #f5f0e6;
}
.finance-row:last-child { border-bottom: none; }
.finance-row .label { color: #8a6d3b; font-size: 26rpx; }
.finance-row .value { color: #333; font-weight: 500; font-size: 28rpx; }
.title {
font-size: 36rpx;
font-weight: bold;

@ -19,7 +19,7 @@
<view class="list-container">
<view v-for="item in list" :key="item.id" class="list-item">
<view class="item-header">
<view :class="['type-badge', item.type === 1 ? 'supply' : 'demand']">{{ item.type === 1 ? '供应' : '需求' }}</view>
<view :class="['type-badge', item.type === 1 ? 'supply' : item.type === 2 ? 'demand' : item.type === 3 ? 'finance' : 'industry']">{{ item.type === 1 ? '供应' : item.type === 2 ? '需求' : item.type === 3 ? '投融资' : '' }}</view>
<text class="time">{{ item.created_at }}</text>
</view>
<text class="title">{{ item.title }}</text>
@ -76,6 +76,8 @@
name: '供应'
}, {
name: '需求'
}, {
name: '投融资'
}],
list: [],
page: 1,
@ -141,6 +143,8 @@
params.type = 1; //
} else if (this.currentTab === 2) {
params.type = 2; //
} else if (this.currentTab === 3) {
params.type = 3; //
}
//
@ -279,6 +283,16 @@
color: #007aff;
}
.finance {
background-color: #e6f0ff;
color: #007aff;
}
.industry {
background-color: #e6f0ff;
color: #007aff;
}
.time {
font-size: 24rpx;
color: #999;

@ -16,7 +16,7 @@
</view>
<view v-else v-for="item in list" :key="item.id" class="list-item">
<view class="item-header">
<view :class="['type-badge', item.type === 1 ? 'supply' : 'demand']">{{ item.type === 1 ? '供应' : '需求' }}</view>
<view :class="['type-badge', item.type === 1 ? 'supply' : item.type === 2 ? 'demand' : item.type === 3 ? 'finance' : 'industry']">{{ item.type === 1 ? '供应' : item.type === 2 ? '需求' : item.type === 3 ? '投融资' : '' }}</view>
<view :class="['status-badge', getStatusClass(item.status)]">{{ getStatusText(item.status) }}</view>
<text class="time">{{ item.created_at }}</text>
</view>
@ -250,6 +250,16 @@
color: #007aff;
}
.finance {
background-color: #e6f0ff;
color: #007aff;
}
.industry {
background-color: #e6f0ff;
color: #007aff;
}
.status-badge {
font-size: 24rpx;
padding: 8rpx 15rpx;

@ -11,8 +11,12 @@
<u-icon name="order" :color="form.type === 'demand' ? '#C9A36D' : '#909399'"></u-icon>
<text class="type-text">需求</text>
</view>
<view :class="['type-button', form.type === 'finance' ? 'active' : '']" @click="form.type = 'finance'">
<u-icon name="rmb-circle" :color="form.type === 'finance' ? '#C9A36D' : '#909399'"></u-icon>
<text class="type-text">投融资</text>
</view>
</view>
</view>
</view>
<view class="card">
<text class="section-title">基本信息</text>
@ -21,21 +25,53 @@
<u-input v-model="form.title" placeholder="请输入标题, 简明扼要" :maxlength="50" type="text"
:custom-style="inputStyle('title')" @focus="activeInput = 'title'" @blur="activeInput = null" />
</u-form-item>
<u-form-item label="详细描述" label-width="150" prop="description" :border-bottom="false">
<u-input v-model="form.description" type="textarea" placeholder="请详细描述您的供需内容..." :maxlength="500" height="200"
:custom-style="inputStyle('description')" @focus="activeInput = 'description'" @blur="activeInput = null" />
</u-form-item>
<u-form-item label="行业标签" label-width="150" prop="tags" :border-bottom="false">
<u-input v-model="tagInput" type="text" placeholder="输入后按回车键确认"
:custom-style="inputStyle('tags')" @focus="activeInput = 'tags'" @blur="activeInput = null" @confirm="addTag" />
</u-form-item>
<view class="tag-container" v-if="form.tags.length > 0">
<view v-for="(tag, index) in form.tags" :key="index" class="tag-item">
<text>{{ tag }}</text>
<u-icon name="close" size="20" @click="removeTag(index)"></u-icon>
<!-- 投融资专用字段 -->
<template v-if="form.type === 'finance'">
<u-form-item label="资金类型" label-width="150" prop="fund_type" :border-bottom="false">
<u-radio-group v-model="form.fund_type">
<u-radio name="投资">投资</u-radio>
<u-radio name="融资">融资</u-radio>
</u-radio-group>
</u-form-item>
<u-form-item label="金额" label-width="150" prop="amount" :border-bottom="false">
<u-input v-model="form.amount" type="number" placeholder="请输入金额(元)" :custom-style="inputStyle('amount')" @focus="activeInput='amount'" @blur="activeInput=null" />
</u-form-item>
<u-form-item label="融资阶段" label-width="150" prop="fund_stage" :border-bottom="false">
<u-input v-model="form.fund_stage" placeholder="如:天使轮/A轮/B轮..." :custom-style="inputStyle('fund_stage')" @focus="activeInput='fund_stage'" @blur="activeInput=null" />
</u-form-item>
<u-form-item label="期望资金属性" label-width="150" prop="expect_fund_attr" :border-bottom="false">
<u-input v-model="form.expect_fund_attr" placeholder="如:国资、基金、民营等..." :custom-style="inputStyle('expect_fund_attr')" @focus="activeInput='expect_fund_attr'" @blur="activeInput=null" />
</u-form-item>
<u-form-item label="行业类型" label-width="150" prop="industry_type" :border-bottom="false">
<u-input v-model="form.industry_type" placeholder="如:智能制造/生物医药..." :custom-style="inputStyle('industry_type')" @focus="activeInput='industry_type'" @blur="activeInput=null" />
</u-form-item>
<u-form-item label="主要产品" label-width="150" prop="product" :border-bottom="false">
<u-input v-model="form.product" placeholder="请输入主要产品" :custom-style="inputStyle('product')" @focus="activeInput='product'" @blur="activeInput=null" />
</u-form-item>
<u-form-item label="简要描述" label-width="150" prop="finance_desc" :border-bottom="false">
<u-input v-model="form.finance_desc" type="textarea" placeholder="请简要描述投融资需求..." :maxlength="500" height="200" :custom-style="inputStyle('finance_desc')" @focus="activeInput='finance_desc'" @blur="activeInput=null" />
</u-form-item>
</template>
<!-- 非投融资沿用原有描述/标签 -->
<template v-else>
<u-form-item label="详细描述" label-width="150" prop="description" :border-bottom="false">
<u-input v-model="form.description" type="textarea" placeholder="请详细描述您的供需内容..." :maxlength="500" height="200"
:custom-style="inputStyle('description')" @focus="activeInput = 'description'" @blur="activeInput = null" />
</u-form-item>
<u-form-item label="行业标签" label-width="150" prop="tags" :border-bottom="false">
<u-input v-model="tagInput" type="text" placeholder="输入后按回车键确认"
:custom-style="inputStyle('tags')" @focus="activeInput = 'tags'" @blur="activeInput = null" @confirm="addTag" />
</u-form-item>
<view class="tag-container" v-if="form.tags.length > 0">
<view v-for="(tag, index) in form.tags" :key="index" class="tag-item">
<text>{{ tag }}</text>
<u-icon name="close" size="20" @click="removeTag(index)"></u-icon>
</view>
</view>
</view>
<view class="form-tip">建议添加相关行业标签, 方便其他校友找到你</view>
<view class="form-tip">建议添加相关行业标签, 方便其他校友找到你</view>
</template>
</u-form>
</view>
@ -141,9 +177,17 @@
tagInput: '',
header: {}, // header
form: {
type: 'supply', // supply or demand
type: 'supply', // supply or demand or finance or industry
title: '',
description: '',
//
fund_type: '投资',
amount: '',
fund_stage: '',
expect_fund_attr: '',
industry_type: '',
product: '',
finance_desc: '',
tags: [],
contactType: 'wechat', // wechat, phone, email
contactValue: '',
@ -264,10 +308,10 @@
this.$u.toast('请输入标题');
return;
}
if (!this.form.description.trim()) {
this.$u.toast('请输入详细描述');
return;
}
// if (!this.form.description.trim()) {
// this.$u.toast('');
// return;
// }
if (!this.form.contactName.trim()) {
this.$u.toast('请输入联系人');
return;
@ -311,9 +355,9 @@
//
const params = {
title: this.form.title,
type: this.form.type === 'supply' ? 1 : 2,
content: this.form.description,
tag: this.form.tags.join(','),
type: this.form.type === 'supply' ? 1 : this.form.type === 'demand' ? 2 : this.form.type === 'finance' ? 3 : 4,
content: this.form.type === 'finance' ? this.form.finance_desc : this.form.description,
tag: this.form.type === 'finance' ? '' : this.form.tags.join(','),
wechat: this.form.contactType === 'wechat' ? this.form.contactValue : '',
mobile: this.form.contactType === 'phone' ? this.form.contactValue : '',
email: this.form.contactType === 'email' ? this.form.contactValue : '',
@ -322,6 +366,17 @@
file_ids: fileIds, // 使
};
//
if (this.form.type === 'finance') {
params.fund_type = this.form.fund_type || ''
params.amount = this.form.amount || ''
params.fund_stage = this.form.fund_stage || ''
params.expect_fund_attr = this.form.expect_fund_attr || ''
params.industry_type = this.form.industry_type || ''
params.product = this.form.product || ''
params.desc = this.form.finance_desc || ''
}
// expire_time
if (this.form.expiryType === 'specific' && this.form.expiryDate) {
params.expire_time = this.form.expiryDate + ' 23:59:59'; //

@ -160,7 +160,7 @@
},{
"path": "supply/index",
"style": {
"navigationBarTitleText": "供需发布"
"navigationBarTitleText": "供需对接"
}
},{
"path": "supply/publish",
@ -192,6 +192,11 @@
"style": {
"navigationBarTitleText": "校友地图"
}
},{
"path": "hr/index",
"style": {
"navigationBarTitleText": "人才招聘"
}
}]
}],
"preloadRule": {

@ -4,32 +4,40 @@
<!-- <image class="profile-icon" src="/static/index_icon1-4.png" @click="goToProfile"></image> -->
<view class="button-grid">
<view class="grid-item" @click="handleButtonClick('alumni')">
<image class="item-bg" :src="base.imgHost('alumni-benefits-item2.png')"></image>
<view class="item-content">
<image class="item-bg" :src="base.imgHost('xy1.png')"></image>
<!-- <view class="item-content">
<image class="icon" :src="base.imgHost('alumni-benefits-icon1.png')" mode="aspectFit"></image>
<text class="label-1">校友库</text>
</view>
</view>
<view class="grid-item" @click="handleButtonClick('booking')">
<image class="item-bg" :src="base.imgHost('alumni-benefits-item1.png')"></image>
<view class="item-content">
<image class="icon" :src="base.imgHost('alumni-benefits-icon2.png')" mode="aspectFit"></image>
<text class="label-2">场地预约</text>
</view>
</view> -->
</view>
<view class="grid-item" @click="handleButtonClick('supply-demand')">
<image class="item-bg" :src="base.imgHost('alumni-benefits-item1.png')"></image>
<view class="item-content">
<image class="item-bg" :src="base.imgHost('xy2.png')"></image>
<!-- <view class="item-content">
<image class="icon" :src="base.imgHost('alumni-benefits-icon3.png')" mode="aspectFit"></image>
<text class="label-2">供需发布</text>
</view>
</view> -->
</view>
<view class="grid-item" @click="handleButtonClick('booking')">
<image class="item-bg" :src="base.imgHost('xy3.png')"></image>
<!-- <view class="item-content">
<image class="icon" :src="base.imgHost('alumni-benefits-icon2.png')" mode="aspectFit"></image>
<text class="label-2">场地预约</text>
</view> -->
</view>
<view class="grid-item" @click="handleButtonClick('library')">
<image class="item-bg" :src="base.imgHost('alumni-benefits-item2.png')"></image>
<view class="item-content">
<image class="item-bg" :src="base.imgHost('xy4.png')"></image>
<!-- <view class="item-content">
<image class="icon" :src="base.imgHost('alumni-benefits-icon4.png')" mode="aspectFit"></image>
<text class="label-1">图书馆查询</text>
</view> -->
</view>
<view class="grid-item grid-item-wide" @click="handleButtonClick('hr')">
<image class="item-bg item-bg-wide" :src="base.imgHost('xy5.png')"></image>
<!-- <view class="item-content">
<image class="icon" :src="base.imgHost('alumni-benefits-icon4.png')" mode="aspectFit"></image>
<text class="label-1">图书馆查询</text>
</view>
</view> -->
</view>
</view>
<tabbar :currentPage="2"></tabbar>
@ -111,6 +119,11 @@
url: '/packages/library/index'
})
break;
case 'hr':
uni.navigateTo({
url: '/packages/hr/index'
})
break;
}
}
},
@ -148,26 +161,39 @@
.button-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20rpx;
grid-template-columns: repeat(2, 368rpx);
// grid-column-gap: 20rpx;
// grid-row-gap: 20rpx;
width: 100%;
justify-content: center;
padding: 0 40rpx;
box-sizing: border-box;
}
.grid-item {
position: relative;
width: 100%;
padding-top: 127.8125%;
/* Creates a 320:409 aspect ratio */
width: 368rpx;
height: 380rpx;
}
/* 最后一张横向大图 */
.grid-item-wide {
grid-column: span 2;
width: 729rpx;
height: 239rpx;
}
.item-bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
width: 368rpx;
height: 380rpx;
}
.item-bg-wide {
width: 729rpx;
height: 239rpx;
}
.item-content {

@ -4,11 +4,35 @@
<!-- <view> -->
<scroll-view :scroll-y="true" @scrolltolower="scrollGet" class="list">
<!-- <topBanner v-if="banner_list.length>0" :banner_list="banner_list"></topBanner> -->
<image class="list-top" :src="base.imgHost('course-top1.png')"></image>
<image mode="widthFix" @click="goCourse" class="list-img" :src="base.imgHost('course-top.png')"></image>
<view v-if="hasData" style="padding-bottom: 200rpx;">
<!-- <image class="list-top" :src="base.imgHost('course-top1.png')"></image> -->
<view class="list-top-text">
<view class="list-top-text-title">课程体系</view>
<view class="list-top-text-swiper swiper-with-arrows">
<swiper
:autoplay="false"
:indicator-dots="false"
:circular="true"
:interval="5000"
:duration="400"
previous-margin="0rpx"
next-margin="80rpx"
:current="swiperCurrent"
@change="onSwiperChange"
style="width:100%;height:614rpx;margin-left: 30rpx;"
>
<swiper-item v-for="(img, idx) in bannerImages" :key="'banner-'+idx">
<image :src="img" style="width:632rpx;height:614rpx;border-radius:20rpx;" mode="aspectFill" />
</swiper-item>
</swiper>
<!-- 左右箭头 -->
<view class="arrow arrow-left" @click="prevSlide"></view>
<view class="arrow arrow-right" @click="nextSlide"></view>
</view>
</view>
<!-- <image mode="widthFix" @click="goCourse" class="list-img" :src="base.imgHost('course-top.png')"></image> -->
<view v-if="hasData" style="padding-bottom: 200rpx;">
<!-- 10进行中 40已结束 -->
<view class="list-item" :class="{'list-end':item.sign_status===40}" v-for="item in course_list">
<view class="list-item" :class="{'list-end':item.sign_status===40}" v-for="(item, index) in course_list" :key="item.id || item.course_id || index">
<view class="list-item-wrap">
<view class="list-item-wrap-time">
<view>
@ -115,6 +139,14 @@
return {
showRegister: false,
banner_list: [],
bannerImages: [
this.base.imgHost('type1.png'),
this.base.imgHost('type2.png'),
this.base.imgHost('type3.png'),
this.base.imgHost('type4.png'),
this.base.imgHost('type5.png')
],
swiperCurrent: 0,
hasMobile: false,
go_course_id: '',
hasData: true,
@ -156,6 +188,17 @@
},
methods: {
onSwiperChange(e){
this.swiperCurrent = e.detail.current || 0
},
prevSlide(){
const total = this.bannerImages.length
this.swiperCurrent = (this.swiperCurrent - 1 + total) % total
},
nextSlide(){
const total = this.bannerImages.length
this.swiperCurrent = (this.swiperCurrent + 1) % total
},
goCourse() {
uni.navigateTo({
url: '/packages/mycourse/index'
@ -308,6 +351,26 @@
height: 100vh;
}
.swiper-with-arrows {
position: relative;
}
.arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 56rpx;
height: 56rpx;
line-height: 56rpx;
text-align: center;
border-radius: 56rpx;
background: rgba(0,0,0,0.3);
color: #fff;
z-index: 10;
font-size: 40rpx;
}
.arrow-left { left: 10rpx; }
.arrow-right { right: 10rpx; }
.list {
@ -328,6 +391,15 @@
width: 95%;
display: block;
margin-bottom: 30rpx;
&-text{
margin-bottom: 40rpx;
&-title{
color:#97714c;
margin:30rpx;
margin-top:0;
font-size: 32rpx;
}
}
}
&-img {
width: calc(100% - 60rpx);

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save