@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
C:/Users/kola/project/school-prompt/backend/mini小程序端接口设计文档.md |
||||
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 988 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 91 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 86 KiB |
@ -1,89 +1,101 @@
@@ -1,89 +1,101 @@
|
||||
<view class="page"> |
||||
<van-tabs |
||||
class="tabs" |
||||
color="rgba(74, 184, 253, 1)" |
||||
title-inactive-color="rgba(71, 85, 105, 1)" |
||||
title-active-color="rgba(74, 184, 253, 1)" |
||||
active="{{ active }}" |
||||
bind:change="onChange" |
||||
sticky |
||||
> |
||||
<!-- 公告 --> |
||||
<van-tab title="公告"> |
||||
<view class="page0"> |
||||
<view |
||||
class="module" |
||||
wx:for="{{announcementList}}" |
||||
wx:key="id" |
||||
data-id="{{item.id}}" |
||||
bind:tap="handleAnnouncementDetail" |
||||
> |
||||
<view class="date">{{item.createdAt}}</view> |
||||
<view class="card"> |
||||
<view class="title">{{item.title}}</view> |
||||
<mp-html class="content" content="{{item.content}}"></mp-html> |
||||
<view class="c-footer"> |
||||
<view class="detail"> |
||||
查看详情 |
||||
<van-icon name="arrow" /> |
||||
</view> |
||||
</view> |
||||
<view class="page-header"> |
||||
<van-tabs |
||||
class="tabs" |
||||
color="rgba(74, 184, 253, 1)" |
||||
title-inactive-color="rgba(71, 85, 105, 1)" |
||||
title-active-color="rgba(74, 184, 253, 1)" |
||||
active="{{ active }}" |
||||
bind:change="onChange" |
||||
> |
||||
<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> |
||||
|
||||
<!-- 公告 --> |
||||
<view class="page0" wx:if="{{active==0}}"> |
||||
<view |
||||
class="module" |
||||
wx:for="{{announcementList}}" |
||||
wx:key="id" |
||||
data-id="{{item.id}}" |
||||
bind:tap="handleAnnouncementDetail" |
||||
> |
||||
<view class="date">{{item.createdAt}}</view> |
||||
<view class="card"> |
||||
<view class="title">{{item.title}}</view> |
||||
<mp-html class="content" content="{{item.content}}"></mp-html> |
||||
<view class="c-footer"> |
||||
<view class="detail"> |
||||
查看详情 |
||||
<van-icon name="arrow" /> |
||||
</view> |
||||
</view> |
||||
<pagination pagination="{{announcementPagination}}"></pagination> |
||||
</view> |
||||
</van-tab> |
||||
</view> |
||||
<pagination pagination="{{announcementPagination}}"></pagination> |
||||
</view> |
||||
|
||||
<!-- 重要通知 --> |
||||
<van-tab title="重要通知"> |
||||
<view class="page0"> |
||||
<view |
||||
class="module" |
||||
wx:for="{{importantList}}" |
||||
wx:key="id" |
||||
data-task-id="{{item.taskId}}" |
||||
bind:tap="handleNoticeDetail" |
||||
> |
||||
<view class="date">{{item.scheduleAt}}</view> |
||||
<view class="card"> |
||||
<view class="title">{{item.title}}</view> |
||||
<mp-html class="content" content="{{item.content}}"></mp-html> |
||||
<view class="c-footer"> |
||||
<view class="detail"> |
||||
查看详情 |
||||
<van-icon name="arrow" /> |
||||
</view> |
||||
</view> |
||||
<!-- 重要通知 --> |
||||
<view class="page0" wx:elif="{{active==1}}"> |
||||
<view |
||||
class="module" |
||||
wx:for="{{importantList}}" |
||||
wx:key="id" |
||||
data-task-id="{{item.taskId}}" |
||||
bind:tap="handleNoticeDetail" |
||||
> |
||||
<view class="date">{{item.scheduleAt}}</view> |
||||
<view class="card"> |
||||
<view class="title">{{item.title}}</view> |
||||
<mp-html class="content" content="{{item.content}}"></mp-html> |
||||
<view class="c-footer"> |
||||
<view class="detail"> |
||||
查看详情 |
||||
<van-icon name="arrow" /> |
||||
</view> |
||||
</view> |
||||
<pagination pagination="{{importantPagination}}"></pagination> |
||||
</view> |
||||
</van-tab> |
||||
</view> |
||||
<pagination pagination="{{importantPagination}}"></pagination> |
||||
</view> |
||||
|
||||
<!-- 活动通知 --> |
||||
<van-tab title="活动通知"> |
||||
<view class="page2"> |
||||
<view class="module" wx:for="{{activityList}}" wx:key="id" data-index="{{index}}" bind:tap="handleActNotice"> |
||||
<view class="date">{{item.scheduleAt}}</view> |
||||
<view class="card"> |
||||
<view class="title">{{item.title}}</view> |
||||
<view class="content">{{item.subtitle}}</view> |
||||
<view class="c-footer"> |
||||
<view class="tag {{item.subType}}">{{item.subTypeName}}</view> |
||||
<view class="detail"> |
||||
查看详情 |
||||
<van-icon name="arrow" /> |
||||
</view> |
||||
</view> |
||||
<!-- 活动通知 --> |
||||
<view class="page2" wx:elif="{{active==2}}"> |
||||
<view class="module" wx:for="{{activityList}}" wx:key="id" data-index="{{index}}" bind:tap="handleActNotice"> |
||||
<view class="date">{{item.scheduleAt}}</view> |
||||
<view class="card"> |
||||
<view class="title">{{item.title}}</view> |
||||
<view class="content">{{item.subtitle}}</view> |
||||
<view class="c-footer"> |
||||
<view class="tag {{item.subType}}">{{item.subTypeName}}</view> |
||||
<view class="detail"> |
||||
查看详情 |
||||
<van-icon name="arrow" /> |
||||
</view> |
||||
</view> |
||||
<pagination pagination="{{activityPagination}}"></pagination> |
||||
</view> |
||||
</van-tab> |
||||
</view> |
||||
<pagination pagination="{{activityPagination}}"></pagination> |
||||
</view> |
||||
|
||||
<!-- 智能体通知 --> |
||||
<van-tab title="智能体通知"> |
||||
<view class="page-empty">暂未开放</view> |
||||
</van-tab> |
||||
</van-tabs> |
||||
<!-- 智能体通知 --> |
||||
<view class="page-empty" wx:elif="{{active==3}}">暂未开放</view> |
||||
</view> |
||||
|
||||
@ -1,8 +1,230 @@
@@ -1,8 +1,230 @@
|
||||
const _app = getApp<IAppOption>(); |
||||
const app = getApp<IAppOption>() |
||||
|
||||
Page({ |
||||
data: {}, |
||||
onLoad() {}, |
||||
}); |
||||
data: { |
||||
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 {} |
||||
|
||||