feat: 百科rag

This commit is contained in:
Blizzard
2026-04-23 11:13:23 +08:00
parent 40f3a8cfa8
commit 9fe2fd42e0
23 changed files with 1129 additions and 69 deletions
+113
View File
@@ -0,0 +1,113 @@
// pages/wiki/chat/history/index.js
import request from '../../../../utils/request';
Page({
data: {
list: [],
total: 0,
current: 1,
pageSize: 15,
loading: false,
hasMore: true,
showClearDialog: false,
},
onLoad() {
this.fetchHistory(true);
},
fetchHistory(reset = false) {
if (this.data.loading) return;
if (!reset && !this.data.hasMore) return;
const current = reset ? 1 : this.data.current;
this.setData({ loading: true });
request.get('/plant/chat/history', { current, pageSize: this.data.pageSize })
.then(res => {
const items = (res.list || []).map(item => ({
...item,
answerPreview: (item.answer || '').substring(0, 80) + ((item.answer || '').length > 80 ? '...' : ''),
}));
const total = res.total || 0;
if (reset) {
this.setData({
list: items,
total,
current: 2,
hasMore: items.length < total,
loading: false,
});
} else {
const old = this.data.list;
const update = {};
items.forEach((item, i) => {
update[`list[${old.length + i}]`] = item;
});
update.current = current + 1;
update.hasMore = (old.length + items.length) < total;
update.loading = false;
update.total = total;
this.setData(update);
}
})
.catch(() => {
this.setData({ loading: false });
});
},
loadMore() {
this.fetchHistory(false);
},
onTapItem(e) {
const item = e.currentTarget.dataset.item;
// Navigate to chat page with prefilled Q&A
wx.navigateTo({
url: '/pages/wiki/chat/index?fromHistory=1',
success(res) {
res.eventChannel.emit('historyData', {
question: item.question,
answer: item.answer,
});
},
});
},
onDeleteItem(e) {
const id = e.currentTarget.dataset.id;
wx.showModal({
title: '删除记录',
content: '确定删除这条问答记录吗?',
success: (res) => {
if (res.confirm) {
request.post('/plant/chat/history/delete', { id }).then(() => {
wx.showToast({ title: '已删除', icon: 'success' });
this.fetchHistory(true);
});
}
},
});
},
onClearAll() {
this.setData({ showClearDialog: true });
},
closeClearDialog() {
this.setData({ showClearDialog: false });
},
doClearAll() {
this.setData({ showClearDialog: false });
request.post('/plant/chat/history/clear').then(() => {
wx.showToast({ title: '已清空', icon: 'success' });
this.setData({ list: [], total: 0, hasMore: false });
});
},
goToChat() {
wx.navigateBack();
},
});
+12
View File
@@ -0,0 +1,12 @@
{
"navigationBarTitleText": "问答历史",
"navigationBarBackgroundColor": "#558B2F",
"navigationBarTextStyle": "white",
"usingComponents": {
"t-icon": "tdesign-miniprogram/icon/icon",
"t-loading": "tdesign-miniprogram/loading/loading",
"t-empty": "tdesign-miniprogram/empty/empty",
"t-dialog": "tdesign-miniprogram/dialog/dialog",
"t-swipe-cell": "tdesign-miniprogram/swipe-cell/swipe-cell"
}
}
+67
View File
@@ -0,0 +1,67 @@
<!--pages/wiki/chat/history/index.wxml-->
<view class="history-page">
<scroll-view
class="history-scroll"
scroll-y
bindscrolltolower="loadMore"
enhanced
show-scrollbar="{{false}}"
>
<!-- Header Actions -->
<view class="header-bar" wx:if="{{list.length > 0}}">
<text class="header-count">共 {{total}} 条记录</text>
<view class="clear-btn" bindtap="onClearAll">
<t-icon name="delete" size="32rpx" color="#EF4444" />
<text>清空全部</text>
</view>
</view>
<!-- History List -->
<view wx:for="{{list}}" wx:key="id" class="history-card" bindtap="onTapItem" data-item="{{item}}">
<view class="card-header">
<text class="card-time">{{item.createdAtStr}}</text>
<view class="card-del" catchtap="onDeleteItem" data-id="{{item.id}}">
<t-icon name="close" size="28rpx" color="#9CA3AF" />
</view>
</view>
<view class="card-question">
<text class="q-label">Q</text>
<text class="q-text">{{item.question}}</text>
</view>
<view class="card-answer">
<text class="a-label">A</text>
<text class="a-text">{{item.answerPreview}}</text>
<view class="card-arrow">
<t-icon name="chevron-right" size="28rpx" color="#CCC" />
</view>
</view>
</view>
<!-- States -->
<view class="footer">
<t-loading wx:if="{{loading}}" theme="circular" size="40rpx" text="加载中..." />
<text wx:elif="{{!hasMore && list.length > 0}}" class="no-more">没有更多了</text>
</view>
<view wx:if="{{!loading && list.length === 0}}" class="empty-wrap">
<view class="empty-icon">📝</view>
<text class="empty-text">暂无问答记录</text>
<text class="empty-sub">去和AI助手聊聊吧</text>
<view class="empty-cta" bindtap="goToChat">
<text>开始提问</text>
</view>
</view>
<view style="height: 60rpx;"></view>
</scroll-view>
<t-dialog
visible="{{showClearDialog}}"
title="清空全部历史"
content="确定要清空所有问答记录吗?此操作不可恢复。"
confirm-btn="确定清空"
cancel-btn="取消"
bind:confirm="doClearAll"
bind:cancel="closeClearDialog"
/>
</view>
+195
View File
@@ -0,0 +1,195 @@
/** pages/wiki/chat/history/index.wxss **/
.history-page {
height: 100vh;
background: linear-gradient(180deg, #EEF3E5 0%, #F4F6F0 100%);
}
.history-scroll {
height: 100%;
padding: 24rpx 28rpx;
}
.header-bar {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 24rpx;
padding: 0 8rpx;
}
.header-count {
font-size: 26rpx;
color: #78909C;
}
.clear-btn {
display: flex;
align-items: center;
gap: 6rpx;
font-size: 26rpx;
color: #EF4444;
font-weight: 600;
padding: 8rpx 16rpx;
border-radius: 16rpx;
}
.clear-btn:active {
background: rgba(239,68,68,0.08);
}
/* Card */
.history-card {
background: rgba(255,255,255,0.92);
backdrop-filter: blur(8px);
border-radius: 24rpx;
padding: 24rpx 24rpx 20rpx;
margin-bottom: 16rpx;
box-shadow: 0 2rpx 12rpx rgba(85,139,47,0.05);
border: 1rpx solid rgba(85,139,47,0.04);
transition: all 0.15s;
animation: cardIn 0.3s ease-out;
}
@keyframes cardIn {
from { opacity: 0; transform: translateY(12rpx); }
to { opacity: 1; transform: translateY(0); }
}
.history-card:active {
transform: scale(0.98);
background: #FAFDF7;
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16rpx;
}
.card-time {
font-size: 22rpx;
color: #9CA3AF;
}
.card-del {
padding: 8rpx;
margin: -8rpx;
}
.card-question {
display: flex;
gap: 12rpx;
margin-bottom: 12rpx;
}
.q-label {
width: 40rpx;
height: 40rpx;
border-radius: 10rpx;
background: linear-gradient(135deg, #558B2F, #7CB342);
color: #fff;
font-size: 24rpx;
font-weight: 700;
text-align: center;
line-height: 40rpx;
flex-shrink: 0;
}
.q-text {
font-size: 30rpx;
font-weight: 600;
color: #1F2937;
line-height: 1.5;
flex: 1;
}
.card-answer {
display: flex;
gap: 12rpx;
}
.a-label {
width: 40rpx;
height: 40rpx;
border-radius: 10rpx;
background: #E8F5E9;
color: #2E7D32;
font-size: 24rpx;
font-weight: 700;
text-align: center;
line-height: 40rpx;
flex-shrink: 0;
}
.a-text {
font-size: 26rpx;
color: #6B7280;
line-height: 1.6;
flex: 1;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.card-arrow {
display: flex;
align-items: center;
flex-shrink: 0;
margin-left: auto;
padding-left: 8rpx;
}
/* Footer */
.footer {
padding: 32rpx;
display: flex;
justify-content: center;
}
.no-more {
font-size: 24rpx;
color: #CCC;
}
/* Empty */
.empty-wrap {
display: flex;
flex-direction: column;
align-items: center;
padding: 120rpx 0;
}
.empty-icon {
font-size: 96rpx;
margin-bottom: 24rpx;
}
.empty-text {
font-size: 32rpx;
font-weight: 600;
color: #9CA3AF;
margin-bottom: 8rpx;
}
.empty-sub {
font-size: 26rpx;
color: #CCC;
margin-bottom: 32rpx;
}
.empty-cta {
padding: 16rpx 48rpx;
border-radius: 40rpx;
background: linear-gradient(135deg, #558B2F, #7CB342);
color: #fff;
font-size: 28rpx;
font-weight: 600;
box-shadow: 0 6rpx 20rpx rgba(85,139,47,0.3);
transition: all 0.15s;
}
.empty-cta:active {
transform: scale(0.95);
}