feat: 百科rag
This commit is contained in:
@@ -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();
|
||||
},
|
||||
});
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user