Browse Source

首页,搜索页联调

master
kola-web 2 days ago
parent
commit
1e2fa6aced
  1. 25
      README.md
  2. 1
      mini小程序端接口设计文档.md
  3. 3
      src/app.json
  4. 12
      src/components/popup/index.wxml
  5. BIN
      src/images/icon100.png
  6. BIN
      src/images/icon101.png
  7. BIN
      src/images/icon102.png
  8. BIN
      src/images/temporary/agent1.png
  9. BIN
      src/images/temporary/agent10.png
  10. BIN
      src/images/temporary/agent11.png
  11. BIN
      src/images/temporary/agent12.png
  12. BIN
      src/images/temporary/agent2.png
  13. BIN
      src/images/temporary/agent3.png
  14. BIN
      src/images/temporary/agent4.png
  15. BIN
      src/images/temporary/agent5.png
  16. BIN
      src/images/temporary/agent6.png
  17. BIN
      src/images/temporary/agent7.png
  18. BIN
      src/images/temporary/agent8.png
  19. BIN
      src/images/temporary/agent9.png
  20. 10
      src/pages/act/index.scss
  21. 1
      src/pages/act/index.wxml
  22. 49
      src/pages/actAdd/index.scss
  23. 7
      src/pages/actAdd/index.ts
  24. 35
      src/pages/actAdd/index.wxml
  25. 2
      src/pages/actDetail/index.scss
  26. 2
      src/pages/actPoster/index.wxml
  27. 2
      src/pages/actQrcode/index.scss
  28. 4
      src/pages/actQrcode/index.wxml
  29. 67
      src/pages/agent/index.ts
  30. 34
      src/pages/agent/index.wxml
  31. 4
      src/pages/chat/index.scss
  32. 3
      src/pages/chat/index.ts
  33. 7
      src/pages/chat/index.wxml
  34. 25
      src/pages/index/index.scss
  35. 80
      src/pages/index/index.ts
  36. 45
      src/pages/index/index.wxml
  37. 10
      src/pages/login/index.scss
  38. 2
      src/pages/my/index.scss
  39. 3
      src/pages/myAct/index.scss
  40. 2
      src/pages/myAct/index.wxml
  41. 8
      src/pages/myComment/index.wxml
  42. 45
      src/pages/notice/index.scss
  43. 44
      src/pages/notice/index.ts
  44. 40
      src/pages/notice/index.wxml
  45. 2
      src/pages/noticeDetail/index.scss
  46. 41
      src/pages/noticeDetail/index.ts
  47. 2
      src/pages/noticeDetail/index.wxml
  48. 2
      src/pages/schedule/index.scss
  49. 173
      src/pages/search/index.scss
  50. 230
      src/pages/search/index.ts
  51. 73
      src/pages/search/index.wxml

25
README.md

@ -3,13 +3,38 @@ git http://39.106.86.127:3000/hb_rd/front_dist.git
branch proj_icampus_dev branch proj_icampus_dev
powershell 软链形式 powershell 软链形式
``` ```
New-Item -ItemType Junction -Path "src/images" -Target C:\Users\kola\project\school-system\web_dist\images New-Item -ItemType Junction -Path "src/images" -Target C:\Users\kola\project\school-system\web_dist\images
``` ```
接口文档
```
New-Item -ItemType SymbolicLink -Path mini小程序端接口设计文档.md -Target C:\Users\kola\project\school-prompt\backend\mini小程序端接口设计文档.md
```
测试账号 测试账号
``` ```
账号 2026050122123 账号 2026050122123
密码 123456 密码 123456
``` ```
未联调模块
小程序端
1. 智能体模块
1. 通知模块智能体列表
2. 首页智能体相关内容
3. 个人中心我的整能体,我的评论-智能体
4. 搜索页智能体相关
2. 课表
3. 校车
管理端
1. 智能体管理
2. 数据统计
3. 数据总揽
4. 权限相关内容

1
mini小程序端接口设计文档.md

@ -0,0 +1 @@
C:/Users/kola/project/school-prompt/backend/mini小程序端接口设计文档.md

3
src/app.json

@ -23,7 +23,8 @@
"pages/myComment/index", "pages/myComment/index",
"pages/schedule/index", "pages/schedule/index",
"pages/feedback/index", "pages/feedback/index",
"pages/search/index" "pages/search/index",
"pages/webview/index"
], ],
"window": { "window": {
"backgroundTextStyle": "light", "backgroundTextStyle": "light",

12
src/components/popup/index.wxml

@ -17,13 +17,13 @@
</view> </view>
</view> </view>
<view class="popup2" wx:if="{{type==='popup2'}}"> <view class="popup2" wx:if="{{type==='popup2'}}">
<view class="container" style="background: url('/images/bg8.png') no-repeat top center/100%"> <view class="container" style="background: url('{{imageUrl}}bg8.png?t={{Timestamp}}') no-repeat top center/100%">
<view class="title">提交成功</view> <view class="title">提交成功</view>
<view class="content">感谢您的反馈,我们会尽快处理</view> <view class="content">感谢您的反馈,我们会尽快处理</view>
</view> </view>
</view> </view>
<view class="popup3" wx:if="{{type==='popup3'}}"> <view class="popup3" wx:if="{{type==='popup3'}}">
<view class="container" style="background: url('/images/bg10.png') no-repeat top center/100%"> <view class="container" style="background: url('{{imageUrl}}bg10.png?t={{Timestamp}}') no-repeat top center/100%">
<view class="title">创建您专属智能体</view> <view class="title">创建您专属智能体</view>
<view class="content">请登陆电脑端创建您的专属智能体</view> <view class="content">请登陆电脑端创建您的专属智能体</view>
<view class="link">www.tencent.yuanqi.com</view> <view class="link">www.tencent.yuanqi.com</view>
@ -36,14 +36,14 @@
<view class="title">通识基础 创新思维</view> <view class="title">通识基础 创新思维</view>
</view> </view>
<view class="row"> <view class="row">
<image class="r-icon" src="/images/icon96.png"></image> <image class="r-icon" src="{{imageUrl}}icon96.png?t={{Timestamp}}"></image>
<view class="wrap"> <view class="wrap">
<view class="w-title">授课老师</view> <view class="w-title">授课老师</view>
<view class="w-content">丁蔚健</view> <view class="w-content">丁蔚健</view>
</view> </view>
</view> </view>
<view class="row"> <view class="row">
<image class="r-icon" src="/images/icon97.png"></image> <image class="r-icon" src="{{imageUrl}}icon97.png?t={{Timestamp}}"></image>
<view class="wrap"> <view class="wrap">
<view class="w-title">授课地点</view> <view class="w-title">授课地点</view>
<view class="w-content">西丽湖园区 日新楼北406</view> <view class="w-content">西丽湖园区 日新楼北406</view>
@ -51,14 +51,14 @@
</view> </view>
<view class="row-wrap"> <view class="row-wrap">
<view class="row"> <view class="row">
<image class="r-icon" src="/images/icon98.png"></image> <image class="r-icon" src="{{imageUrl}}icon98.png?t={{Timestamp}}"></image>
<view class="wrap"> <view class="wrap">
<view class="w-title">绩点</view> <view class="w-title">绩点</view>
<view class="w-content">2</view> <view class="w-content">2</view>
</view> </view>
</view> </view>
<view class="row"> <view class="row">
<image class="r-icon" src="/images/icon99.png"></image> <image class="r-icon" src="{{imageUrl}}icon99.png?t={{Timestamp}}"></image>
<view class="wrap"> <view class="wrap">
<view class="w-title">课时</view> <view class="w-title">课时</view>
<view class="w-content">32</view> <view class="w-content">32</view>

BIN
src/images/icon100.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
src/images/icon101.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/images/icon102.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
src/images/temporary/agent1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 KiB

BIN
src/images/temporary/agent10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
src/images/temporary/agent11.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
src/images/temporary/agent12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
src/images/temporary/agent2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
src/images/temporary/agent3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
src/images/temporary/agent4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
src/images/temporary/agent5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
src/images/temporary/agent6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
src/images/temporary/agent7.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
src/images/temporary/agent8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
src/images/temporary/agent9.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

10
src/pages/act/index.scss

@ -62,17 +62,14 @@ page {
} }
} }
.filter-btn { .filter-btn {
margin-top: 2rpx; padding: 16rpx 0 18rpx 64rpx;
align-self: start;
padding: 8rpx 24rpx;
flex-shrink: 0; flex-shrink: 0;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 6rpx; gap: 6rpx;
background-color: rgba(247, 248, 250, 1);
border-radius: 40rpx;
font-size: 28rpx; font-size: 28rpx;
color: rgba(74, 184, 253, 1); color: rgba(74, 184, 253, 1);
background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, #fff 100%);
.icon { .icon {
width: 32rpx; width: 32rpx;
height: 32rpx; height: 32rpx;
@ -261,8 +258,9 @@ page {
color: rgba(100, 116, 139, 1); color: rgba(100, 116, 139, 1);
display: flex; display: flex;
gap: 8rpx; gap: 8rpx;
line-height: 32rpx;
.icon { .icon {
margin-top: 8rpx; margin-top: 4rpx;
flex-shrink: 0; flex-shrink: 0;
width: 22rpx; width: 22rpx;
height: 22rpx; height: 22rpx;

1
src/pages/act/index.wxml

@ -18,7 +18,6 @@
</view> </view>
<view class="filter-btn" bind:tap="handleFilterOpen"> <view class="filter-btn" bind:tap="handleFilterOpen">
<image class="icon" src="{{imageUrl}}icon4.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon4.png?t={{Timestamp}}"></image>
筛选
</view> </view>
</view> </view>
</view> </view>

49
src/pages/actAdd/index.scss

@ -68,7 +68,7 @@ page {
} }
.step-num { .step-num {
font-size: 26rpx; font-size: 28rpx;
color: rgba(148, 163, 184, 1); color: rgba(148, 163, 184, 1);
font-weight: 500; font-weight: 500;
} }
@ -144,6 +144,27 @@ page {
margin-left: 6rpx; margin-left: 6rpx;
font-size: 28rpx; font-size: 28rpx;
} }
.extra {
flex: 1;
display: flex;
justify-content: flex-end;
.ai-img {
width: 203rpx;
height: 56rpx;
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
background: linear-gradient(90deg, #9ddffd 0%, #4ab8fd 100%);
border-radius: 68rpx 68rpx 68rpx 68rpx;
font-size: 28rpx;
color: rgba(255, 255, 255, 1);
.icon {
width: 32rpx;
height: 32rpx;
}
}
}
} }
.input-wrap { .input-wrap {
@ -325,7 +346,7 @@ page {
text-align: center; text-align: center;
font-size: 32rpx; font-size: 32rpx;
color: rgba(100, 116, 139, 1); color: rgba(100, 116, 139, 1);
background: rgba(247, 248, 250, 1); background: #F7F8FA;
transition: all 0.2s; transition: all 0.2s;
&.is-active { &.is-active {
@ -696,3 +717,27 @@ page {
.bottom-safe { .bottom-safe {
height: 40rpx; height: 40rpx;
} }
.slidebar-add {
padding-top: 17rpx;
position: fixed;
right: 16rpx;
bottom: 320rpx;
width: 110rpx;
height: 110rpx;
background: linear-gradient(90deg, #9ddffd 0%, #4ab8fd 100%);
box-shadow:
inset 0rpx 4rpx 24rpx 0rpx rgba(255, 255, 255, 0.25),
0rpx 15rpx 30rpx -6rpx rgba(74, 172, 219, 0.4);
border-radius: 50%;
text-align: center;
box-sizing: border-box;
.icon {
width: 48rpx;
height: 48rpx;
}
.name {
font-size: 20rpx;
color: rgba(255, 255, 255, 1);
}
}

7
src/pages/actAdd/index.ts

@ -200,7 +200,7 @@ Page({
// 分类和标签 // 分类和标签
const selectedCategoryIds = res.categoryIds || [] const selectedCategoryIds = res.categoryIds || []
const selectedTagIds = (res.tags || []).map((t: any) => typeof t === 'object' ? t.id : t) const selectedTagIds = (res.tags || []).map((t: any) => (typeof t === 'object' ? t.id : t))
// 报名设置 // 报名设置
const needRegister = res.regType === 1 const needRegister = res.regType === 1
@ -919,6 +919,11 @@ Page({
this.clearDraft() this.clearDraft()
wx.switchTab({ url: '/pages/index/index' }) wx.switchTab({ url: '/pages/index/index' })
}, },
handleAiAdd() {
wx.navigateTo({
url: '/pages/chat/index',
})
},
}) })
export {} export {}

35
src/pages/actAdd/index.wxml

@ -25,6 +25,12 @@
<view class="form-label"> <view class="form-label">
<text>活动头图</text> <text>活动头图</text>
<text class="required">*</text> <text class="required">*</text>
<view class="extra">
<view class="ai-img">
<image class="icon" src="{{imageUrl}}icon102.png?t={{Timestamp}}"></image>
智能出图
</view>
</view>
</view> </view>
<upload-file <upload-file
maxCount="{{1}}" maxCount="{{1}}"
@ -242,21 +248,13 @@
<text>报名时间</text> <text>报名时间</text>
<text class="required">*</text> <text class="required">*</text>
</view> </view>
<view <view class="form-picker" data-field="registerStartTime" bind:tap="onOpenDatePicker">
class="form-picker"
data-field="registerStartTime"
bind:tap="onOpenDatePicker"
>
<view class="picker-value {{registerStartTime ? '' : 'is-placeholder'}}"> <view class="picker-value {{registerStartTime ? '' : 'is-placeholder'}}">
{{registerStartTime || '开始时间'}} {{registerStartTime || '开始时间'}}
</view> </view>
<image class="picker-icon" src="{{imageUrl}}icon17.png?t={{Timestamp}}"></image> <image class="picker-icon" src="{{imageUrl}}icon17.png?t={{Timestamp}}"></image>
</view> </view>
<view <view class="form-picker" data-field="registerEndTime" bind:tap="onOpenDatePicker">
class="form-picker"
data-field="registerEndTime"
bind:tap="onOpenDatePicker"
>
<view class="picker-value {{registerEndTime ? '' : 'is-placeholder'}}"> <view class="picker-value {{registerEndTime ? '' : 'is-placeholder'}}">
{{registerEndTime || '结束时间'}} {{registerEndTime || '结束时间'}}
</view> </view>
@ -376,21 +374,13 @@
<text>签到时间</text> <text>签到时间</text>
<text class="required">*</text> <text class="required">*</text>
</view> </view>
<view <view class="form-picker" data-field="checkinStartTime" bind:tap="onOpenDatePicker">
class="form-picker"
data-field="checkinStartTime"
bind:tap="onOpenDatePicker"
>
<view class="picker-value {{checkinStartTime ? '' : 'is-placeholder'}}"> <view class="picker-value {{checkinStartTime ? '' : 'is-placeholder'}}">
{{checkinStartTime || '开始时间'}} {{checkinStartTime || '开始时间'}}
</view> </view>
<image class="picker-icon" src="{{imageUrl}}icon17.png?t={{Timestamp}}"></image> <image class="picker-icon" src="{{imageUrl}}icon17.png?t={{Timestamp}}"></image>
</view> </view>
<view <view class="form-picker" data-field="checkinEndTime" bind:tap="onOpenDatePicker">
class="form-picker"
data-field="checkinEndTime"
bind:tap="onOpenDatePicker"
>
<view class="picker-value {{checkinEndTime ? '' : 'is-placeholder'}}"> <view class="picker-value {{checkinEndTime ? '' : 'is-placeholder'}}">
{{checkinEndTime || '结束时间'}} {{checkinEndTime || '结束时间'}}
</view> </view>
@ -520,3 +510,8 @@
bind:cancel="onCloseAgendaDatePicker" bind:cancel="onCloseAgendaDatePicker"
/> />
</van-popup> </van-popup>
<view class="slidebar-add" bind:tap="handleAiAdd">
<image class="icon" src="{{imageUrl}}icon100.png?t={{Timestamp}}"></image>
<view class="name">智能创建</view>
</view>

2
src/pages/actDetail/index.scss

@ -6,7 +6,7 @@ page {
color: #fff; color: #fff;
} }
.page-back { .page-back {
font-size: 32rpx; font-size: 38rpx;
color: #fff; color: #fff;
} }

2
src/pages/actPoster/index.wxml

@ -1,6 +1,6 @@
<navbar fixed customStyle="background:{{background}};"> <navbar fixed customStyle="background:{{background}};">
<view class="page-back" slot="left" bind:tap="handleBack"> <view class="page-back" slot="left" bind:tap="handleBack">
<image class="icon" src="/images/icon91.png"></image> <image class="icon" src="{{imageUrl}}icon91.png?t={{Timestamp}}"></image>
</view> </view>
</navbar> </navbar>

2
src/pages/actQrcode/index.scss

@ -7,7 +7,7 @@ page {
color: #fff; color: #fff;
} }
.page-back { .page-back {
font-size: 32rpx; font-size: 38rpx;
color: #fff; color: #fff;
} }
.page { .page {

4
src/pages/actQrcode/index.wxml

@ -2,7 +2,7 @@
<van-icon class="page-back" name="arrow-left" slot="left" bind:tap="handleBack" /> <van-icon class="page-back" name="arrow-left" slot="left" bind:tap="handleBack" />
<view class="page-title" slot="title"></view> <view class="page-title" slot="title"></view>
</navbar> </navbar>
<view class="page" style="background: url('/images/bg9.png') no-repeat top center/100% 1627rpx"> <view class="page" style="background: url('{{imageUrl}}bg9.png?t={{Timestamp}}') no-repeat top center/100% 1627rpx">
<view class="page-title">{{detail.name}}</view> <view class="page-title">{{detail.name}}</view>
<view class="title">活动签到</view> <view class="title">活动签到</view>
<view class="content"> <view class="content">
@ -12,7 +12,7 @@
</view> </view>
<image class="code" src="{{codeUrl}}"></image> <image class="code" src="{{codeUrl}}"></image>
<view class="btn"> <view class="btn">
<image class="icon" src="/images/icon92.png"></image> <image class="icon" src="{{imageUrl}}icon92.png?t={{Timestamp}}"></image>
长按保存二维码 长按保存二维码
</view> </view>
<view class="date">签到时间: {{detail.checkinStartTime}}</view> <view class="date">签到时间: {{detail.checkinStartTime}}</view>

67
src/pages/agent/index.ts

@ -3,9 +3,68 @@ const _app = getApp<IAppOption>()
Page({ Page({
data: { data: {
// 弹窗 // 弹窗
popupShow: true, popupShow: false,
popupType: 'popup3', popupType: 'popup3',
popupParams: {} as any, popupParams: {} as any,
list1: [
{
name: 'PPT小助手',
icon: 'agent8',
},
{
name: '雅思考官',
icon: 'agent9',
},
{
name: 'PDF翻译',
icon: 'agent10',
},
{
name: '文章去AI',
icon: 'agent2',
},
],
list2: [
{
name: '写作检测',
icon: 'agent2',
},
{
name: '文章去AI',
icon: 'agent3',
},
{
name: '文章去AI',
icon: 'agent4',
},
],
list3: [
{
name: '写作检测',
icon: 'agent5',
},
{
name: '文章去AI',
icon: 'agent6',
},
{
name: 'PDF翻译',
icon: 'agent7',
},
],
list4: [
{
name: '应用包生成助手',
content: '智能规划课表,轻松掌握学习节奏',
icon: 'agent11',
},
{
name: '社交平台文案生成助手',
content: '智能规划课表,轻松掌握学习节奏',
icon: 'agent12',
},
],
}, },
onLoad() {}, onLoad() {},
handleEva() { handleEva() {
@ -41,6 +100,12 @@ Page({
}, },
}) })
}, },
handleDetail() {
const url = `https://app.gohighedu.cn/statics_h5/`
wx.navigateTo({
url: `/pages/webview/index?url=${encodeURIComponent(url)}`,
})
},
// 弹窗取消 // 弹窗取消
handlePopupCancel() { handlePopupCancel() {

34
src/pages/agent/index.wxml

@ -20,7 +20,7 @@
indicator-active-color="rgba(74, 184, 253, 1)" indicator-active-color="rgba(74, 184, 253, 1)"
> >
<swiper-item class="swiper-item"> <swiper-item class="swiper-item">
<image class="s-img" mode="aspectFill" src="{{imageUrl}}bg1.png?t={{Timestamp}}"></image> <image class="s-img" mode="aspectFill" src="{{imageUrl}}temporary/agent1.png?t={{Timestamp}}"></image>
</swiper-item> </swiper-item>
</swiper> </swiper>
</view> </view>
@ -33,9 +33,9 @@
</view> </view>
</view> </view>
<view class="k-body"> <view class="k-body">
<view class="k-item" wx:for="{{4}}" wx:key="index"> <view class="k-item" wx:for="{{list1}}" wx:key="index" bind:tap="handleDetail">
<image class="icon" src="{{imageUrl}}icon2.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}temporary/{{item.icon}}.png?t={{Timestamp}}"></image>
<view class="name">PPT小助手</view> <view class="name">{{item.name}}</view>
</view> </view>
</view> </view>
</view> </view>
@ -43,8 +43,8 @@
<view class="k-row"> <view class="k-row">
<view class="kr-header">最近使用</view> <view class="kr-header">最近使用</view>
<view class="kr-body"> <view class="kr-body">
<view class="kr-item" wx:for="{{3}}" wx:key="index"> <view class="kr-item" wx:for="{{list2}}" wx:key="index">
<image class="icon" src="{{imageUrl}}icon2.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}temporary/{{item.icon}}.png?t={{Timestamp}}"></image>
<view class="name">PPT小助</view> <view class="name">PPT小助</view>
</view> </view>
</view> </view>
@ -52,8 +52,8 @@
<view class="k-row"> <view class="k-row">
<view class="kr-header">我的收藏</view> <view class="kr-header">我的收藏</view>
<view class="kr-body"> <view class="kr-body">
<view class="kr-item" wx:for="{{3}}" wx:key="index"> <view class="kr-item" wx:for="{{list3}}" wx:key="index">
<image class="icon" src="{{imageUrl}}icon2.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}temporary/{{item.icon}}.png?t={{Timestamp}}"></image>
<view class="name">文章去</view> <view class="name">文章去</view>
</view> </view>
</view> </view>
@ -72,7 +72,7 @@
> >
<van-tab title="全部"> <van-tab title="全部">
<view class="list"> <view class="list">
<view class="list-card" wx:for="{{10}}" wx:key="index"> <view class="list-card" wx:for="{{list4}}" wx:key="index">
<view class="order"> <view class="order">
<image class="icon" wx:if="{{index==0}}" src="{{imageUrl}}icon48.png?t={{Timestamp}}"></image> <image class="icon" wx:if="{{index==0}}" src="{{imageUrl}}icon48.png?t={{Timestamp}}"></image>
<image class="icon" wx:elif="{{index==1}}" src="{{imageUrl}}icon49.png?t={{Timestamp}}"></image> <image class="icon" wx:elif="{{index==1}}" src="{{imageUrl}}icon49.png?t={{Timestamp}}"></image>
@ -80,21 +80,21 @@
<view class="num" wx:else>{{index+1}}</view> <view class="num" wx:else>{{index+1}}</view>
</view> </view>
<view class="photo"> <view class="photo">
<image class="p-img" src="{{imageUrl}}icon2.png?t={{Timestamp}}"></image> <image class="p-img" src="{{imageUrl}}temporary/{{item.icon}}.png?t={{Timestamp}}"></image>
</view> </view>
<view class="wrap"> <view class="wrap">
<view class="title">应用包生成助手</view> <view class="title">{{item.name}}</view>
<view class="content">智能规划课表,轻松掌握学习轻松掌握学习</view> <view class="content">{{item.content}}</view>
<view class="stat">15.6w人使用</view> <view class="stat">15.6w人使用</view>
<view class="options"> <view class="options">
<view class="o-item active" bind:tap="handleEva"> <view class="o-item active" bind:tap="handleEva">
<image class="icon" src="{{imageUrl}}icon55.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon56.png?t={{Timestamp}}"></image>
<image class="icon" src="{{imageUrl}}icon51.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon57.png?t={{Timestamp}}"></image>
评级 评级
</view> </view>
<view class="o-item"> <view class="o-item">
<image class="icon" src="{{imageUrl}}icon56.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon55.png?t={{Timestamp}}"></image>
<image class="icon" src="{{imageUrl}}icon57.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon51.png?t={{Timestamp}}"></image>
收藏 收藏
</view> </view>
<view class="o-item">使用</view> <view class="o-item">使用</view>
@ -112,7 +112,7 @@
</view> </view>
<view class="fixed-add" bind:tap="handleAdd"> <view class="fixed-add" bind:tap="handleAdd">
<image class="icon" src="/images/icon95.png"></image> <image class="icon" src="{{imageUrl}}icon95.png?t={{Timestamp}}"></image>
</view> </view>
<popup <popup

4
src/pages/chat/index.scss

@ -2,7 +2,7 @@ page {
background-color: rgba(247, 248, 250, 1); background-color: rgba(247, 248, 250, 1);
} }
.page-back { .page-back {
font-size: 32rpx; font-size: 38rpx;
color: rgba(0, 0, 0, 0.9); color: rgba(0, 0, 0, 0.9);
} }
@ -39,7 +39,7 @@ page {
border-radius: 54rpx; border-radius: 54rpx;
} }
.first-card { .first-card {
margin-top: 39rpx; margin-top: 29rpx;
padding: 32rpx; padding: 32rpx;
font-size: 32rpx; font-size: 32rpx;
color: rgba(31, 41, 55, 1); color: rgba(31, 41, 55, 1);

3
src/pages/chat/index.ts

@ -311,6 +311,9 @@ Page({
recognitionManager.stop() recognitionManager.stop()
wx.showToast({ title: '识别已取消', icon: 'none' }) wx.showToast({ title: '识别已取消', icon: 'none' })
}, },
handleBack() {
wx.navigateBack()
},
}) })
export {} export {}

7
src/pages/chat/index.wxml

@ -3,7 +3,7 @@
style="background: url('{{imageUrl}}bg3.png?t={{Timestamp}}') no-repeat top center/100% 556rpx;padding-top: {{pageTop}}px;" style="background: url('{{imageUrl}}bg3.png?t={{Timestamp}}') no-repeat top center/100% 556rpx;padding-top: {{pageTop}}px;"
> >
<navbar fixed customStyle="background:{{background}};"> <navbar fixed customStyle="background:{{background}};">
<van-icon class="page-back" name="arrow-left" slot="left" bind:tap="goHistory" /> <van-icon class="page-back" name="arrow-left" slot="left" bind:tap="handleBack" />
</navbar> </navbar>
<scroll-view class="chat-scroll" scroll-y scroll-into-view="{{scrollToView}}" enhanced show-scrollbar="{{false}}"> <scroll-view class="chat-scroll" scroll-y scroll-into-view="{{scrollToView}}" enhanced show-scrollbar="{{false}}">
<view class="scroll-top-safe"></view> <view class="scroll-top-safe"></view>
@ -27,7 +27,10 @@
<view class="scroll-bottom-safe" id="scroll-bottom-safe"></view> <view class="scroll-bottom-safe" id="scroll-bottom-safe"></view>
</scroll-view> </scroll-view>
<view class="chat-input"> <view class="chat-input">
<view class="go-act-draft" wx:if="{{activityId}}" bind:tap="goActDraft">查看当前草稿<van-icon name="arrow" /></view> <view class="go-act-draft" wx:if="{{activityId}}" bind:tap="goActDraft">
查看当前草稿
<van-icon name="arrow" />
</view>
<!-- 文本输入模式 --> <!-- 文本输入模式 -->
<view class="freetext" wx:if="{{inputMode === 'text'}}"> <view class="freetext" wx:if="{{inputMode === 'text'}}">
<input <input

25
src/pages/index/index.scss

@ -23,8 +23,30 @@ page {
line-height: 44rpx; line-height: 44rpx;
} }
} }
.banner-area {
margin: 20rpx 30rpx 0;
height: 300rpx;
position: relative;
.banner-dots {
position: absolute;
bottom: 16rpx;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 12rpx;
.dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background: rgba(255, 255, 255, 0.5);
&.active {
background: #fff;
}
}
}
}
.notice { .notice {
margin: 353rpx 30rpx 0; margin: 20rpx 30rpx 0;
padding: 12rpx 24rpx; padding: 12rpx 24rpx;
background-color: #fff; background-color: #fff;
border-radius: 59rpx; border-radius: 59rpx;
@ -296,6 +318,7 @@ page {
align-items: center; align-items: center;
gap: 8rpx; gap: 8rpx;
.icon { .icon {
flex-shrink: 0;
width: 22rpx; width: 22rpx;
height: 22rpx; height: 22rpx;
} }

80
src/pages/index/index.ts

@ -13,6 +13,8 @@ Page({
bannerItems: [] as any[], bannerItems: [] as any[],
currentBannerIndex: 0, currentBannerIndex: 0,
currentBannerImage: '', currentBannerImage: '',
// 模块排序
sortedModuleTypes: [] as string[],
// 推荐活动分页数据 // 推荐活动分页数据
latestActivities: [] as any[], latestActivities: [] as any[],
activityPagination: { activityPagination: {
@ -65,21 +67,27 @@ Page({
data.searchPlaceholder = res.searchModule.config.placeholder data.searchPlaceholder = res.searchModule.config.placeholder
} }
// 收集有数据的模块及其 sort 值,用于动态排序
const moduleSorts: { type: string; sort: number }[] = []
// Banner 模块 // Banner 模块
if (res.bannerModule?.items?.length) { if (res.bannerModule?.items?.length) {
data.bannerItems = res.bannerModule.items data.bannerItems = res.bannerModule.items
data.currentBannerImage = res.bannerModule.items[0].imageUrl data.currentBannerImage = res.bannerModule.items[0].imageUrl
moduleSorts.push({ type: 'banner', sort: res.bannerModule.sort ?? 99 })
this.startBannerRotation(res.bannerModule.items) this.startBannerRotation(res.bannerModule.items)
} }
// 快捷入口模块 // 快捷入口模块
if (res.quickEntryModule?.items?.length) { if (res.quickEntryModule?.items?.length) {
data.quickEntries = res.quickEntryModule.items data.quickEntries = res.quickEntryModule.items
moduleSorts.push({ type: 'quickEntry', sort: res.quickEntryModule.sort ?? 99 })
} }
// 通知栏模块 // 通知栏模块
if (res.notificationModule?.data?.length) { if (res.notificationModule?.data?.length) {
data.notifications = res.notificationModule.data data.notifications = res.notificationModule.data
moduleSorts.push({ type: 'notification', sort: res.notificationModule.sort ?? 99 })
} }
// 热门活动模块 - 处理mainImages JSON字符串解析 // 热门活动模块 - 处理mainImages JSON字符串解析
@ -98,13 +106,19 @@ Page({
return { ...item, mainImages } return { ...item, mainImages }
}) })
data.hotActivities = hotActivities data.hotActivities = hotActivities
moduleSorts.push({ type: 'hotActivity', sort: res.hotActivityModule.sort ?? 99 })
} }
// 推荐智能体模块 // 推荐智能体模块
if (res.recommendAgentModule?.data?.length) { if (res.recommendAgentModule?.data?.length) {
data.recommendAgents = res.recommendAgentModule.data data.recommendAgents = res.recommendAgentModule.data
moduleSorts.push({ type: 'recommendAgent', sort: res.recommendAgentModule.sort ?? 99 })
} }
// 按 sort 升序排列
moduleSorts.sort((a, b) => a.sort - b.sort)
data.sortedModuleTypes = moduleSorts.map((m) => m.type)
this.setData(data) this.setData(data)
}) })
.catch((err) => { .catch((err) => {
@ -215,6 +229,57 @@ Page({
const { index } = e.currentTarget.dataset const { index } = e.currentTarget.dataset
const { quickEntries } = this.data const { quickEntries } = this.data
const { jumpType, jumpTarget } = quickEntries[index] const { jumpType, jumpTarget } = quickEntries[index]
this.handleJump(jumpType, jumpTarget)
},
handleBannerTap(e) {
const { index } = e.currentTarget.dataset
const { bannerItems } = this.data
const { jumpType, jumpTarget } = bannerItems[index] || {}
this.handleJump(jumpType, jumpTarget)
},
handleNotificationTap(e) {
const { index } = e.currentTarget.dataset
const { notifications } = this.data
const idx = index ?? 0
const { jumpType, jumpTarget } = notifications[idx] || {}
if (!jumpType || jumpType === 0) return
this.handleJump(jumpType, jumpTarget)
},
handleJump(jumpType: number | string, jumpTarget: string) {
const jt = Number(jumpType)
if (!jt || !jumpTarget) return
switch (jt) {
case 2:
wx.navigateTo({ url: `/pages/actDetail/index?id=${jumpTarget}` })
break
case 3: {
const tabPages = [
'/pages/index/index',
'/pages/act/index',
'/pages/notice/index',
'/pages/agent/index',
'/pages/my/index',
]
const isTab = tabPages.some((p) => jumpTarget.startsWith(p))
if (isTab) {
wx.switchTab({ url: jumpTarget })
} else {
wx.navigateTo({ url: jumpTarget })
}
break
}
case 4:
wx.navigateTo({ url: `/pages/webview/index?url=${encodeURIComponent(jumpTarget)}` })
break
case 5:
wx.navigateToMiniProgram({ appId: jumpTarget })
break
default:
break
}
}, },
onAgentTap(e: WechatMiniprogram.TouchEvent) { onAgentTap(e: WechatMiniprogram.TouchEvent) {
@ -235,6 +300,21 @@ Page({
wx.switchTab({ url: '/pages/my/index' }) wx.switchTab({ url: '/pages/my/index' })
} }
}, },
handleSearchTap() {
wx.navigateTo({
url: '/pages/search/index',
})
},
handleActMore() {
wx.switchTab({
url: '/pages/act/index',
})
},
handleAgentMore() {
wx.switchTab({
url: '/pages/agent/index',
})
},
}) })
export {} export {}

45
src/pages/index/index.wxml

@ -2,56 +2,67 @@
class="page" class="page"
style="background: url('{{currentBannerImage || imageUrl + 'bg1.png?t=' + Timestamp}}') no-repeat top center/100% 655rpx;padding-top: {{pageTop}}px;" style="background: url('{{currentBannerImage || imageUrl + 'bg1.png?t=' + Timestamp}}') no-repeat top center/100% 655rpx;padding-top: {{pageTop}}px;"
> >
<view class="search"> <view class="search" bind:tap="handleSearchTap">
<image class="icon" src="{{imageUrl}}icon1.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon1.png?t={{Timestamp}}"></image>
<view class="content">{{searchPlaceholder}}</view> <view class="content">{{searchPlaceholder}}</view>
</view> </view>
<view class="notice" wx:if="{{notifications.length > 0}}"> <view class="banner-area" wx:if="{{bannerItems.length > 0}}" bind:tap="handleBannerTap" data-index="{{currentBannerIndex}}">
<view class="banner-dots" wx:if="{{bannerItems.length > 1}}">
<view class="dot {{currentBannerIndex === idx ? 'active' : ''}}" wx:for="{{bannerItems}}" wx:key="id" wx:for-index="idx"></view>
</view>
</view>
<block wx:for="{{sortedModuleTypes}}" wx:key="*this">
<!-- 通知栏模块 -->
<view class="notice" wx:if="{{item === 'notification' && notifications.length > 0}}" bind:tap="handleNotificationTap">
<image class="icon" src="{{imageUrl}}icon2.png?t={{Timestamp}}"></image> <image class="icon" src="{{imageUrl}}icon2.png?t={{Timestamp}}"></image>
<view class="content"> <view class="content">
<swiper class="notice-swiper" vertical="{{true}}" autoplay="{{true}}" circular="{{true}}" interval="{{3000}}"> <swiper class="notice-swiper" vertical="{{true}}" autoplay="{{true}}" circular="{{true}}" interval="{{3000}}">
<swiper-item wx:for="{{notifications}}" wx:key="id"> <swiper-item wx:for="{{notifications}}" wx:for-item="notice" wx:key="id" data-index="{{index}}" catch:tap="handleNotificationTap">
<view class="notice-text">{{item.title}}</view> <view class="notice-text">{{notice.title}}</view>
</swiper-item> </swiper-item>
</swiper> </swiper>
</view> </view>
<van-icon class="more" name="arrow" /> <van-icon class="more" name="arrow" />
</view> </view>
<view class="kkd" wx:if="{{quickEntries.length > 0}}"> <!-- 快捷入口模块 -->
<view class="k-item" wx:for="{{quickEntries}}" wx:key="id" bind:tap="handleKkd" data-index="{{index}}"> <view class="kkd" wx:if="{{item === 'quickEntry' && quickEntries.length > 0}}">
<image class="icon" src="{{item.imageUrl}}"></image> <view class="k-item" wx:for="{{quickEntries}}" wx:for-item="entry" wx:key="id" bind:tap="handleKkd" data-index="{{index}}">
<view class="name">{{item.name}}</view> <image class="icon" src="{{entry.imageUrl}}"></image>
<view class="name">{{entry.name}}</view>
</view> </view>
</view> </view>
<view class="module" wx:if="{{hotActivities.length > 0}}"> <!-- 热门活动模块 -->
<view class="module" wx:if="{{item === 'hotActivity' && hotActivities.length > 0}}">
<view class="m-header"> <view class="m-header">
<view class="title">热门活动</view> <view class="title">热门活动</view>
<view class="more"> <view class="more" bind:tap="handleActMore">
查看详情 查看详情
<van-icon name="arrow" /> <van-icon name="arrow" />
</view> </view>
</view> </view>
<view class="activity-list"> <view class="activity-list">
<view class="a-card" wx:for="{{hotActivities}}" wx:key="id"> <view class="a-card" wx:for="{{hotActivities}}" wx:for-item="activity" wx:key="id" bind:tap="onActivityTap" data-id="{{activity.id}}">
<image class="a-img" mode="aspectFill" src="{{item.mainImages[0]}}"></image> <image class="a-img" mode="aspectFill" src="{{activity.bannerImage}}"></image>
</view> </view>
</view> </view>
</view> </view>
<view class="module" wx:if="{{recommendAgents.length > 0}}"> <!-- 推荐智能体模块 -->
<view class="module" wx:if="{{item === 'recommendAgent' && recommendAgents.length > 0}}">
<view class="m-header"> <view class="m-header">
<view class="title">推荐智能体</view> <view class="title">推荐智能体</view>
<view class="more"> <view class="more" handleAgentMore>
查看详情 查看详情
<van-icon name="arrow" /> <van-icon name="arrow" />
</view> </view>
</view> </view>
<view class="agent-list"> <view class="agent-list">
<view class="a-card" wx:for="{{recommendAgents}}" wx:key="id"> <view class="a-card" wx:for="{{recommendAgents}}" wx:for-item="agent" wx:key="id" bind:tap="onAgentTap" data-id="{{agent.id}}">
<image class="icon" src="{{item.icon}}"></image> <image class="icon" src="{{agent.icon}}"></image>
<view class="name">{{item.name}}</view> <view class="name">{{agent.name}}</view>
</view> </view>
</view> </view>
</view> </view>
</block>
<view class="recommend"> <view class="recommend">
<van-tabs <van-tabs
active="{{ active }}" active="{{ active }}"

10
src/pages/login/index.scss

@ -77,6 +77,16 @@
width: 29rpx; width: 29rpx;
height: 29rpx; height: 29rpx;
border-radius: 50%; border-radius: 50%;
border-color: rgba(203, 213, 225, 1);
}
.wx-checkbox-input-checked {
background: rgba(74, 184, 253, 1);
border-color: rgba(74, 184, 253, 1);
&::before {
color: #fff;
font-size: 28rpx;
font-weight: bold;
}
} }
.high { .high {
color: rgba(74, 184, 253, 1); color: rgba(74, 184, 253, 1);

2
src/pages/my/index.scss

@ -50,9 +50,7 @@ page {
gap: 22rpx; gap: 22rpx;
.k-item { .k-item {
flex: 1; flex: 1;
background: linear-gradient(180deg, #ebfdff 0%, #ffffff 100%);
border-radius: 24rpx 24rpx 24rpx 24rpx; border-radius: 24rpx 24rpx 24rpx 24rpx;
border: 2rpx solid #ffffff;
.wrap { .wrap {
padding: 32rpx; padding: 32rpx;
.title { .title {

3
src/pages/myAct/index.scss

@ -146,8 +146,9 @@ page {
color: rgba(100, 116, 139, 1); color: rgba(100, 116, 139, 1);
display: flex; display: flex;
gap: 8rpx; gap: 8rpx;
line-height: 32rpx;
.icon { .icon {
margin-top: 8rpx; margin-top: 4rpx;
flex-shrink: 0; flex-shrink: 0;
width: 22rpx; width: 22rpx;
height: 22rpx; height: 22rpx;

2
src/pages/myAct/index.wxml

@ -37,7 +37,7 @@
</view> </view>
</view> </view>
<view class="reject" wx:if="{{item.activityStatus==4}}"> <view class="reject" wx:if="{{item.activityStatus==4}}">
<image class="icon" src="/images/icon63.png"></image> <image class="icon" src="{{imageUrl}}icon63.png?t={{Timestamp}}"></image>
<view class="r-content">驳回原因:{{item.reviewReason}}</view> <view class="r-content">驳回原因:{{item.reviewReason}}</view>
</view> </view>
<view class="c-footer"> <view class="c-footer">

8
src/pages/myComment/index.wxml

@ -18,13 +18,13 @@
<view class="wrap"> <view class="wrap">
<view class="name" wx:if="{{item.isAnonymous}}">匿名</view> <view class="name" wx:if="{{item.isAnonymous}}">匿名</view>
<view class="options" wx:if="{{item.auditStatus === 2 || item.auditStatus === 3}}" data-key="activity-{{index}}" catch:tap="handleToggleOptions"> <view class="options" wx:if="{{item.auditStatus === 2 || item.auditStatus === 3}}" data-key="activity-{{index}}" catch:tap="handleToggleOptions">
<image class="icon" src="/images/icon93.png"></image> <image class="icon" src="{{imageUrl}}icon93.png?t={{Timestamp}}"></image>
<view class="options-wrap" wx:if="{{showOptionsKey === 'activity-' + index}}"> <view class="options-wrap" wx:if="{{showOptionsKey === 'activity-' + index}}">
<view class="o-item" wx:if="{{item.auditStatus === 2 && item.isAnonymous}}" data-id="{{item.id}}" data-index="{{index}}" data-type="activity" catch:tap="handleSetPublic"> <view class="o-item" wx:if="{{item.auditStatus === 2 && item.isAnonymous}}" data-id="{{item.id}}" data-index="{{index}}" data-type="activity" catch:tap="handleSetPublic">
公开 公开
</view> </view>
<view class="o-item" data-id="{{item.id}}" data-index="{{index}}" catch:tap="handleDelete"> <view class="o-item" data-id="{{item.id}}" data-index="{{index}}" catch:tap="handleDelete">
<image class="icon" src="/images/icon94.png"></image> <image class="icon" src="{{imageUrl}}icon94.png?t={{Timestamp}}"></image>
删除 删除
</view> </view>
</view> </view>
@ -76,13 +76,13 @@
<view class="wrap"> <view class="wrap">
<view class="name" wx:if="{{item.isAnonymous}}">匿名</view> <view class="name" wx:if="{{item.isAnonymous}}">匿名</view>
<view class="options" wx:if="{{item.auditStatus === 2 || item.auditStatus === 3}}" data-key="agent-{{index}}" catch:tap="handleToggleOptions"> <view class="options" wx:if="{{item.auditStatus === 2 || item.auditStatus === 3}}" data-key="agent-{{index}}" catch:tap="handleToggleOptions">
<image class="icon" src="/images/icon93.png"></image> <image class="icon" src="{{imageUrl}}icon93.png?t={{Timestamp}}"></image>
<view class="options-wrap" wx:if="{{showOptionsKey === 'agent-' + index}}"> <view class="options-wrap" wx:if="{{showOptionsKey === 'agent-' + index}}">
<view class="o-item" wx:if="{{item.auditStatus === 2 && item.isAnonymous}}" data-id="{{item.id}}" data-index="{{index}}" data-type="agent" catch:tap="handleSetPublic"> <view class="o-item" wx:if="{{item.auditStatus === 2 && item.isAnonymous}}" data-id="{{item.id}}" data-index="{{index}}" data-type="agent" catch:tap="handleSetPublic">
公开 公开
</view> </view>
<view class="o-item" data-id="{{item.id}}" data-index="{{index}}" catch:tap="handleDelete"> <view class="o-item" data-id="{{item.id}}" data-index="{{index}}" catch:tap="handleDelete">
<image class="icon" src="/images/icon94.png"></image> <image class="icon" src="{{imageUrl}}icon94.png?t={{Timestamp}}"></image>
删除 删除
</view> </view>
</view> </view>

45
src/pages/notice/index.scss

@ -4,6 +4,51 @@ page {
.page { .page {
padding-bottom: calc(env(safe-area-inset-bottom) + 120rpx); padding-bottom: calc(env(safe-area-inset-bottom) + 120rpx);
.page-header {
position: sticky;
top: 0;
left: 0;
padding-bottom: 32rpx;
background-color: #fff;
.search-wrap {
margin: 32rpx 0 0 32rpx;
display: flex;
align-content: inherit;
.date-range {
padding: 0 32rpx;
flex: 1;
display: flex;
align-items: center;
gap: 16rpx;
background-color: rgba(247, 248, 250, 1);
border-radius: 80rpx;
.icon {
flex-shrink: 0;
width: 34rpx;
height: 34rpx;
}
.date {
padding: 20rpx 0;
text-align: center;
font-size: 32rpx;
color: rgba(71, 85, 105, 1);
}
.picker {
flex: 1;
}
.arrow {
font-size: 24rpx;
color: rgba(148, 163, 184, 1);
}
}
.clear {
padding: 20rpx;
flex-shrink: 0;
width: 34rpx;
height: 34rpx;
}
}
}
.tabs { .tabs {
.van-tabs__line { .van-tabs__line {
width: 32rpx !important; width: 32rpx !important;

44
src/pages/notice/index.ts

@ -64,7 +64,6 @@ Page({
onLoad() { onLoad() {
app.waitLogin({ type: 1 }).then(() => { app.waitLogin({ type: 1 }).then(() => {
this.clearNotice('announcement')
this.fetchAnnouncementList() this.fetchAnnouncementList()
}) })
}, },
@ -77,7 +76,14 @@ Page({
} }
}, },
// 自动清空当前tab类型的通知(进入列表时即清空) // 用户点击清除按钮
handleClearNotice() {
const types = ['announcement', 'important', 'activity'] as const
const type = types[this.data.active]
this.clearNotice(type)
},
// 清空指定类型的通知
async clearNotice(type: string) { async clearNotice(type: string) {
try { try {
await wx.ajax({ await wx.ajax({
@ -101,13 +107,10 @@ Page({
this.setData({ active }) this.setData({ active })
if (active === 0 && this.data.announcementList.length === 0) { if (active === 0 && this.data.announcementList.length === 0) {
this.clearNotice('announcement')
this.fetchAnnouncementList() this.fetchAnnouncementList()
} else if (active === 1 && this.data.importantList.length === 0) { } else if (active === 1 && this.data.importantList.length === 0) {
this.clearNotice('important')
this.fetchNoticeList('important') this.fetchNoticeList('important')
} else if (active === 2 && this.data.activityList.length === 0) { } else if (active === 2 && this.data.activityList.length === 0) {
this.clearNotice('activity')
this.fetchNoticeList('activity') this.fetchNoticeList('activity')
} }
}, },
@ -204,10 +207,33 @@ Page({
handleActNotice(e) { handleActNotice(e) {
const { index } = e.currentTarget.dataset const { index } = e.currentTarget.dataset
const { activityList } = this.data const { activityList } = this.data
const { jumpTarget } = activityList[index] const { jumpType, jumpTarget } = activityList[index]
wx.navigateTo({ if (!jumpType || !jumpTarget) return
url: `/pages/actDetail/index?id=${jumpTarget}`, const jt = Number(jumpType)
}) const tabPages = ['/pages/index/index', '/pages/act/index', '/pages/notice/index', '/pages/agent/index', '/pages/my/index']
switch (jt) {
case 1:
wx.navigateTo({ url: `/pages/actDetail/index?id=${jumpTarget}` })
break
case 2: {
const isTab = tabPages.some(p => jumpTarget.startsWith(p))
if (isTab) {
wx.switchTab({ url: jumpTarget })
}
else {
wx.navigateTo({ url: jumpTarget })
}
break
}
case 3:
wx.navigateTo({ url: `/pages/webview/index?url=${encodeURIComponent(jumpTarget)}` })
break
case 4:
wx.navigateToMiniProgram({ appId: jumpTarget })
break
default:
break
}
}, },
// 下拉刷新 // 下拉刷新

40
src/pages/notice/index.wxml

@ -1,4 +1,5 @@
<view class="page"> <view class="page">
<view class="page-header">
<van-tabs <van-tabs
class="tabs" class="tabs"
color="rgba(74, 184, 253, 1)" color="rgba(74, 184, 253, 1)"
@ -6,11 +7,30 @@
title-active-color="rgba(74, 184, 253, 1)" title-active-color="rgba(74, 184, 253, 1)"
active="{{ active }}" active="{{ active }}"
bind:change="onChange" bind:change="onChange"
sticky
> >
<van-tab title="公告"></van-tab>
<van-tab title="重要通知"></van-tab>
<van-tab title="活动通知"></van-tab>
<van-tab title="智能体通知"></van-tab>
</van-tabs>
<view class="search-wrap">
<view class="date-range">
<image class="icon" src="{{imageUrl}}icon4.png?t={{Timestamp}}"></image>
<picker class="picker" mode="date">
<view class="date">2026-05-28</view>
</picker>
<picker class="picker" mode="date">
<view class="date">2026-05-28</view>
</picker>
<van-icon class="arrow" name="arrow-down" />
</view>
<image class="clear" src="{{imageUrl}}icon101.png?t={{Timestamp}}" bindtap="handleClearNotice"></image>
</view>
</view>
<!-- 公告 --> <!-- 公告 -->
<van-tab title="公告"> <view class="page0" wx:if="{{active==0}}">
<view class="page0">
<view <view
class="module" class="module"
wx:for="{{announcementList}}" wx:for="{{announcementList}}"
@ -32,11 +52,9 @@
</view> </view>
<pagination pagination="{{announcementPagination}}"></pagination> <pagination pagination="{{announcementPagination}}"></pagination>
</view> </view>
</van-tab>
<!-- 重要通知 --> <!-- 重要通知 -->
<van-tab title="重要通知"> <view class="page0" wx:elif="{{active==1}}">
<view class="page0">
<view <view
class="module" class="module"
wx:for="{{importantList}}" wx:for="{{importantList}}"
@ -58,11 +76,9 @@
</view> </view>
<pagination pagination="{{importantPagination}}"></pagination> <pagination pagination="{{importantPagination}}"></pagination>
</view> </view>
</van-tab>
<!-- 活动通知 --> <!-- 活动通知 -->
<van-tab title="活动通知"> <view class="page2" wx:elif="{{active==2}}">
<view class="page2">
<view class="module" wx:for="{{activityList}}" wx:key="id" data-index="{{index}}" bind:tap="handleActNotice"> <view class="module" wx:for="{{activityList}}" wx:key="id" data-index="{{index}}" bind:tap="handleActNotice">
<view class="date">{{item.scheduleAt}}</view> <view class="date">{{item.scheduleAt}}</view>
<view class="card"> <view class="card">
@ -79,11 +95,7 @@
</view> </view>
<pagination pagination="{{activityPagination}}"></pagination> <pagination pagination="{{activityPagination}}"></pagination>
</view> </view>
</van-tab>
<!-- 智能体通知 --> <!-- 智能体通知 -->
<van-tab title="智能体通知"> <view class="page-empty" wx:elif="{{active==3}}">暂未开放</view>
<view class="page-empty">暂未开放</view>
</van-tab>
</van-tabs>
</view> </view>

2
src/pages/noticeDetail/index.scss

@ -1,5 +1,5 @@
.page { .page {
padding: 32rpx; padding: 32rpx 32rpx 220rpx;
.info { .info {
.row { .row {
display: flex; display: flex;

41
src/pages/noticeDetail/index.ts

@ -92,26 +92,31 @@ Page({
// 跳转 // 跳转
handleJump() { handleJump() {
const { detail } = this.data const { detail } = this.data
if (!detail || detail.jumpType === 0) return if (!detail || !detail.jumpType || !detail.jumpTarget) return
const jt = Number(detail.jumpType)
if (detail.jumpType === 1) { const tabPages = ['/pages/index/index', '/pages/act/index', '/pages/notice/index', '/pages/agent/index', '/pages/my/index']
// 不跳转 switch (jt) {
} else if (detail.jumpType === 2) { case 2:
// 跳转活动
wx.navigateTo({ url: `/pages/actDetail/index?id=${detail.jumpTarget}` }) wx.navigateTo({ url: `/pages/actDetail/index?id=${detail.jumpTarget}` })
} else if (detail.jumpType === 3) { break
// 跳转小程序页面 case 3: {
wx.navigateTo({ const isTab = tabPages.some(p => detail.jumpTarget.startsWith(p))
url: detail.jumpTarget, if (isTab) {
fail() {
wx.switchTab({ url: detail.jumpTarget }) wx.switchTab({ url: detail.jumpTarget })
}, }
}) else {
} else if (detail.jumpType === 4) { wx.navigateTo({ url: detail.jumpTarget })
// 跳转H5链接 }
wx.navigateTo({ break
url: `/pages/webview/index?url=${encodeURIComponent(detail.jumpTarget)}`, }
}) case 4:
wx.navigateTo({ url: `/pages/webview/index?url=${encodeURIComponent(detail.jumpTarget)}` })
break
case 5:
wx.navigateToMiniProgram({ appId: detail.jumpTarget })
break
default:
break
} }
}, },

2
src/pages/noticeDetail/index.wxml

@ -21,7 +21,7 @@
<view class="mp-html"> <view class="mp-html">
<mp-html content="{{type === 'announcement' ? detail.content : detail.richContent}}"></mp-html> <mp-html content="{{type === 'announcement' ? detail.content : detail.richContent}}"></mp-html>
</view> </view>
<view class="footer" wx:if="{{detail.jumpType !== 1 && detail.buttonText}}"> <view class="footer" wx:if="{{detail.jumpType && detail.jumpType !== 0 && detail.buttonText}}">
<view class="btn" bind:tap="handleJump">{{detail.buttonText}}</view> <view class="btn" bind:tap="handleJump">{{detail.buttonText}}</view>
</view> </view>
</view> </view>

2
src/pages/schedule/index.scss

@ -3,7 +3,7 @@
color: rgba(30, 41, 59, 1); color: rgba(30, 41, 59, 1);
} }
.page-back { .page-back {
font-size: 32rpx; font-size: 38rpx;
color: rgba(30, 41, 59, 1); color: rgba(30, 41, 59, 1);
} }

173
src/pages/search/index.scss

@ -1,10 +1,12 @@
.page { .page {
padding-bottom: calc(60px + env(safe-area-inset-bottom));
.header { .header {
position: sticky; position: sticky;
top: 0; top: 0;
left: 0; left: 0;
padding: 32rpx; padding: 32rpx;
background-color: #fff; background-color: #fff;
z-index: 10;
.search { .search {
display: flex; display: flex;
align-items: center; align-items: center;
@ -26,7 +28,7 @@
color: rgba(71, 85, 105, 1); color: rgba(71, 85, 105, 1);
height: 80rpx; height: 80rpx;
} }
.input-place { .place-input {
color: rgba(148, 163, 184, 0.7); color: rgba(148, 163, 184, 0.7);
} }
} }
@ -69,6 +71,9 @@
} }
} }
} }
.tabs-wrap {
background-color: #fff;
}
.tabs { .tabs {
.van-tabs__line { .van-tabs__line {
width: 42rpx !important; width: 42rpx !important;
@ -77,12 +82,166 @@
--tab-font-size: 32rpx; --tab-font-size: 32rpx;
} }
} }
.page0 { .list {
min-height: 100vh; margin: 30rpx;
background-color: rgba(247, 248, 250, 1); .card {
margin-bottom: 24rpx;
padding: 24rpx;
display: flex;
gap: 24rpx;
background-color: #fff;
border-radius: 24rpx;
.photo {
flex-shrink: 0;
position: relative;
width: 262rpx;
height: 196rpx;
border-radius: 16rpx;
overflow: hidden;
.status {
position: absolute;
top: 0;
left: 0;
padding: 8rpx 16rpx;
font-size: 22rpx;
border-radius: 16rpx 0rpx 16rpx 0rpx;
display: flex;
align-items: center;
gap: 8rpx;
.icon {
display: none;
width: 24rpx;
height: 24rpx;
}
&.status1 {
color: rgba(74, 184, 253, 1);
background: rgba(226, 244, 255, 1);
}
&.status2 {
color: rgba(255, 255, 255, 1);
background: rgba(254, 181, 74, 1);
.icon {
display: block;
}
}
&.status3 {
color: rgba(255, 255, 255, 1);
background: rgba(111, 220, 174, 1);
.icon {
display: block;
}
}
&.status4 {
color: rgba(255, 255, 255, 1);
background: rgba(253, 91, 89, 1);
}
&.status5 {
color: rgba(255, 255, 255, 1);
background: rgba(111, 220, 174, 1);
}
&.status6 {
color: rgba(255, 255, 255, 1);
background: rgba(254, 181, 74, 1);
}
&.status7 {
color: rgba(255, 255, 255, 1);
background: rgba(203, 213, 225, 1);
}
&.status8 {
color: rgba(100, 116, 139, 1);
background: rgba(233, 239, 245, 1);
}
&.status9 {
.icon {
display: block;
}
color: rgba(255, 255, 255, 1);
background: rgba(74, 184, 253, 1);
}
}
.p-img {
border-radius: 16rpx;
display: block;
width: 100%;
height: 100%;
}
.user {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
box-sizing: border-box;
text-align: center;
line-height: 44rpx;
font-size: 24rpx;
color: rgba(255, 255, 255, 1);
background-color: rgba(0, 0, 0, 0.36);
backdrop-filter: blur(8rpx);
}
}
.wrap {
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
font-size: 32rpx;
color: rgba(17, 24, 39, 1);
line-height: 48rpx;
font-weight: bold;
height: 96rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.date,
.site {
margin-top: 12rpx;
font-size: 28rpx;
color: rgba(100, 116, 139, 1);
display: flex;
gap: 8rpx;
line-height: 32rpx;
.icon {
margin-top: 4rpx;
flex-shrink: 0;
width: 22rpx;
height: 22rpx;
}
}
}
}
.agent-card {
display: flex;
align-items: center;
gap: 24rpx;
margin-bottom: 24rpx;
padding: 24rpx;
background-color: #fff;
border-radius: 24rpx;
.agent-icon {
flex-shrink: 0;
width: 112rpx;
height: 112rpx;
border-radius: 16rpx;
}
.agent-info {
flex: 1;
.agent-name {
font-size: 32rpx;
color: rgba(17, 24, 39, 1);
font-weight: bold;
}
.agent-brief {
margin-top: 8rpx;
font-size: 28rpx;
color: rgba(100, 116, 139, 1);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
} }
.page1 {
min-height: 100vh;
background-color: rgba(247, 248, 250, 1);
} }
} }

230
src/pages/search/index.ts

@ -1,8 +1,230 @@
const _app = getApp<IAppOption>(); const app = getApp<IAppOption>()
Page({ Page({
data: {}, data: {
onLoad() {}, imageUrl: app.globalData.imageUrl,
}); Timestamp: app.globalData.Timestamp,
keyword: '',
active: 0,
// 搜索历史
historyList: [] as any[],
// 是否已搜索
searched: false,
// 头部高度(用于 tabs 吸顶定位)
headerHeight: 0,
// 活动搜索结果
activityList: [] as any[],
activityPagination: { page: 1, pages: 1, count: 0 },
activityLoading: false,
// 智能体搜索结果
agentList: [] as any[],
agentPagination: { page: 1, pages: 1, count: 0 },
agentLoading: false,
},
onLoad() {
app.waitLogin().then(() => {
this.fetchHistory()
})
},
onReady() {
this.measureHeader()
},
onReachBottom() {
if (this.data.active === 0) {
this.loadMoreActivities()
}
else if (this.data.active === 1) {
this.loadMoreAgents()
}
},
// 获取搜索历史
fetchHistory() {
wx.ajax({
url: '/search/history',
method: 'GET',
})
.then((res: any) => {
if (res?.list?.length) {
this.setData({ historyList: res.list })
}
})
.catch((err) => {
console.error('获取搜索历史失败', err)
})
},
// 清除搜索历史
handleClearHistory() {
wx.ajax({
url: '/search/clear-history',
method: 'POST',
})
.then(() => {
this.setData({ historyList: [] })
})
.catch((err) => {
console.error('清除搜索历史失败', err)
})
},
// 测量头部高度
measureHeader() {
this.createSelectorQuery()
.select('.header')
.boundingClientRect((rect) => {
if (rect) {
this.setData({ headerHeight: rect.height })
}
})
.exec()
},
// 点击历史标签搜索
handleTagTap(e: WechatMiniprogram.TouchEvent) {
const keyword = e.currentTarget.dataset.keyword
this.setData({ keyword }, () => {
this.doSearch()
})
},
// 输入关键词
handleInput(e: WechatMiniprogram.Input) {
this.setData({ keyword: e.detail.value })
},
// 点击搜索按钮
handleSearch() {
this.doSearch()
},
// 执行搜索
doSearch() {
const { keyword } = this.data
if (!keyword.trim()) return
this.setData({
searched: true,
activityList: [],
agentList: [],
activityPagination: { page: 1, pages: 1, count: 0 },
agentPagination: { page: 1, pages: 1, count: 0 },
}, () => {
this.measureHeader()
})
// 根据当前 tab 决定搜索类型
const tabToType: Record<number, string> = { 0: '2', 1: '3' }
const type = tabToType[this.data.active] || '1'
this.fetchSearch(keyword, type, 1)
// 刷新搜索历史
this.fetchHistory()
},
// 切换 tab
onChange(e: WechatMiniprogram.CustomEvent) {
const active = e.detail.index ?? 0
this.setData({ active })
if (!this.data.searched) return
const tabToType: Record<number, string> = { 0: '2', 1: '3' }
const type = tabToType[active] || '1'
const list = active === 0 ? this.data.activityList : this.data.agentList
if (list.length === 0) {
this.fetchSearch(this.data.keyword, type, 1)
}
},
// 搜索接口
fetchSearch(keyword: string, type: string, page: number) {
const loadingKey = type === '2' ? 'activityLoading' : 'agentLoading'
this.setData({ [loadingKey]: true } as any)
wx.ajax({
url: '/search/search',
method: 'GET',
data: { keyword, type, page, pageSize: 20 },
})
.then((res: any) => {
const data: any = {}
if (type === '1' || type === '2') {
const acts = res?.activities?.list || []
const pagination = res?.activities?.pagination || {}
// 处理 mainImages
const activityList = acts.map((item: any) => {
let mainImages = item.mainImages
if (typeof mainImages === 'string') {
try {
mainImages = JSON.parse(mainImages)
}
catch (_) {
mainImages = []
}
}
return { ...item, mainImages }
})
const newList = page === 1 ? activityList : [...this.data.activityList, ...activityList]
data.activityList = newList
data.activityPagination = {
page: pagination.page || page,
pages: pagination.totalPages || 1,
count: pagination.total || 0,
}
}
if (type === '1' || type === '3') {
const agents = res?.agents?.list || []
const pagination = res?.agents?.pagination || {}
const newList = page === 1 ? agents : [...this.data.agentList, ...agents]
data.agentList = newList
data.agentPagination = {
page: pagination.page || page,
pages: pagination.totalPages || 1,
count: pagination.total || 0,
}
}
data[loadingKey] = false
this.setData(data)
})
.catch((err) => {
console.error('搜索失败', err)
this.setData({ [loadingKey]: false } as any)
})
},
// 活动触底加载
loadMoreActivities() {
const { activityPagination, activityLoading } = this.data
if (activityLoading || activityPagination.page >= activityPagination.pages) return
this.fetchSearch(this.data.keyword, '2', activityPagination.page + 1)
},
// 智能体触底加载
loadMoreAgents() {
const { agentPagination, agentLoading } = this.data
if (agentLoading || agentPagination.page >= agentPagination.pages) return
this.fetchSearch(this.data.keyword, '3', agentPagination.page + 1)
},
// 跳转活动详情
handleActivityTap(e: WechatMiniprogram.TouchEvent) {
const id = e.currentTarget.dataset.id
wx.navigateTo({ url: `/pages/actDetail/index?id=${id}` })
},
// 跳转智能体详情
handleAgentTap(e: WechatMiniprogram.TouchEvent) {
const id = e.currentTarget.dataset.id
wx.navigateTo({ url: `/pages/agent/index?id=${id}` })
},
})
export {} export {}

73
src/pages/search/index.wxml

@ -2,18 +2,35 @@
<view class="header"> <view class="header">
<view class="search"> <view class="search">
<view class="input-wrap"> <view class="input-wrap">
<image class="icon" src="/images/icon1.png"></image> <image class="icon" src="{{imageUrl}}icon1.png?t={{Timestamp}}"></image>
<input class="input" placeholder-class="place-input" type="text" placeholder="请搜索你想要的内容" /> <input
class="input"
placeholder-class="place-input"
type="text"
placeholder="请搜索你想要的内容"
value="{{keyword}}"
bindinput="handleInput"
bindconfirm="handleSearch"
confirm-type="search"
/>
</view> </view>
<view class="btn">搜索</view> <view class="btn" bind:tap="handleSearch">搜索</view>
</view> </view>
<view class="history"> <view class="history" wx:if="{{!searched && historyList.length > 0}}">
<view class="h-header"> <view class="h-header">
<view class="title">历史记录</view> <view class="title">历史记录</view>
<image class="clear" src="/images/icon94.png"></image> <image class="clear" src="{{imageUrl}}icon94.png?t={{Timestamp}}" bind:tap="handleClearHistory"></image>
</view> </view>
<view class="h-container"> <view class="h-container">
<view class="tag" wx:for="{{10}}" wx:key="index">暑假活动</view> <view
class="tag"
wx:for="{{historyList}}"
wx:key="keyword"
data-keyword="{{item.keyword}}"
bind:tap="handleTagTap"
>
{{item.keyword}}
</view>
</view> </view>
</view> </view>
</view> </view>
@ -25,12 +42,50 @@
active="{{ active }}" active="{{ active }}"
bind:change="onChange" bind:change="onChange"
sticky sticky
offset-top="{{headerHeight}}"
> >
<van-tab title="我发布的"> <van-tab title="活动">
<view class="page0"></view> <view class="list">
<view class="card" wx:for="{{activityList}}" wx:key="id" data-id="{{item.id}}" bind:tap="handleActivityTap">
<view class="photo">
<view class="status status{{item.activityStatus}}" wx:if="{{item.activityStatusName}}">
<image class="icon" src="{{imageUrl}}icon89.png?t={{Timestamp}}"></image>
{{item.activityStatusName}}
</view>
<image
class="p-img"
src="{{item.mainImages[0] || imageUrl + 'bg1.png?t=' + Timestamp}}"
mode="aspectFill"
></image>
<view class="user" wx:if="{{item.regCount}}">{{item.regCount}}人已报名</view>
</view>
<view class="wrap">
<view class="title">{{item.name}}</view>
<view class="date">
<image class="icon" src="{{imageUrl}}icon3.png?t={{Timestamp}}"></image>
<view class="content">{{item.startAt}} - {{item.endAt}}</view>
</view>
<view class="site">
<image class="icon" src="{{imageUrl}}icon15.png?t={{Timestamp}}"></image>
<view class="content">{{item.location}}</view>
</view>
</view>
</view>
<pagination pagination="{{activityPagination}}" />
</view>
</van-tab> </van-tab>
<van-tab title="智能体"> <van-tab title="智能体">
<view class="page1"></view> <view class="list">
<!-- 智能体列表样式待补充 -->
<view class="agent-card" wx:for="{{agentList}}" wx:key="id" data-id="{{item.id}}" bind:tap="handleAgentTap">
<image class="agent-icon" src="{{item.icon}}"></image>
<view class="agent-info">
<view class="agent-name">{{item.name}}</view>
<view class="agent-brief">{{item.brief}}</view>
</view>
</view>
<pagination pagination="{{agentPagination}}" />
</view>
</van-tab> </van-tab>
</van-tabs> </van-tabs>
</view> </view>

Loading…
Cancel
Save