Skip to content

Commit

Permalink
fix: When switching tabs quickly, the feedback list is abnormal
Browse files Browse the repository at this point in the history
快速切换标签时,反馈列表显示异常
由于网络请求延迟,反馈列表有可能显示其他页面的数据
解决方法是为每个请求创建一个id,仅处理当前id的信号

Log:
  • Loading branch information
myml committed Aug 14, 2023
1 parent 8e6ea7f commit 7b07f83
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 102 deletions.
185 changes: 93 additions & 92 deletions src/maincomponentplugin/api/API.qml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Item {
// daemon发送的托盘事件,用于控制主窗口的显示
signal showMainWindow(bool isIconClick)
// 反馈列表更新
signal signalFeedbackListUpdate(var feedbacks)
signal signalFeedbackListUpdate(string reqID, var feedbacks)
// 发送http请求
function request(method, rawUrl, body, callback) {
const url = node + rawUrl
Expand Down Expand Up @@ -108,34 +108,53 @@ Item {
callback(JSON.parse(resp.value))
})
}
// 给用户反馈列表填充和用户关联关系,用于显示是否已点赞,已收藏
// 顺便把图片地址修正

// 补全反馈信息,包括:图片地址、用户关联、统计数据
function fill_feedback(feedbacks) {
let url = "/api/v1/user/feedback/relation?offset=0&limit=20"
// 拼接id参数
for(let feedback of feedbacks) {
feedback.like = false
feedback.collect = false
url+="&id=" + feedback.public_id
let relationURL = "/api/v1/user/feedback/relation?offset=0&limit=20";
for (let feedback of feedbacks) {
feedback.like = false;
feedback.collect = false;
relationURL += "&id=" + feedback.public_id;
// 补全图片前缀
if (feedback.screenshots)
feedback.screenshots = feedback.screenshots.map((id) => {
return node + "/api/v1/public/upload/" + id;
});

// 补全统计信息
const stat = worker.awaitPromise((promise) => {
feedbackStat(feedback.public_id, promise.resolve);
});
feedback.view_count = stat.view_count;
feedback.like_count = stat.like_count;
feedback.collect_count = stat.collect_count;
}
// 填充关联关系到对象中
get(url, (relations) => {
for(let relation of relations) {
const feedback = feedbacks.find(feedback=>feedback.public_id === relation.feedback_id)
if(feedback){
switch(relation.relation) {
case "like":
feedback.like = true
break
case "collect":
feedback.collect = true
break
}
}
if (isLogin)
return ;

// 用户已登陆,补全用户和反馈的关联关系(点赞、收藏等)
const relations = worker.awaitPromise((promise) => {
get(urlrelationURL, promise.resolve);
});
for (let relation of relations) {
const feedback = feedbacks.find((feedback) => {
return feedback.public_id === relation.feedback_id;
});
if (!feedback)
continue;

switch (relation.relation) {
case "like":
feedback.like = true;
break;
case "collect":
feedback.collect = true;
break;
}
signalFeedbackListUpdate(feedbacks)
})
}
}

// 预览图片,使用qml下载图片可以重用缓存
function imagePreview(url: string) {
var xhr = new XMLHttpRequest();
Expand All @@ -148,67 +167,38 @@ Item {
xhr.open("GET", url)
xhr.send()
}

// 获取反馈列表
function getFeedback(opt) {
function getFeedback(reqID, opt) {
// 拼接ID
let ids=""
if(opt.ids) {
for(const id of opt.ids) {
ids+="&public_id=" + id
}
}
const url = "/api/v1/public/feedback?offset=%1&limit=%2&&type=%4&language=%5%6".
arg(opt.offset).
arg(opt.limit).
arg(opt.type).
arg(language).
arg(ids)
const resp = worker.awaitPromise(promise=>{
get(url, promise.resolve)
})
for(let feedback of resp){
const id = feedback.public_id
const stat = worker.awaitPromise(promise=>{
feedbackStat(id, promise.resolve)
})
feedback.view_count = stat.view_count
feedback.like_count = stat.like_count
feedback.collect_count = stat.collect_count
if(feedback.screenshots) {
feedback.screenshots = feedback.screenshots.map((id)=> {
return node + "/api/v1/public/upload/" + id
})
let ids = "";
if (opt.ids) {
for (const id of opt.ids) {
ids += "&public_id=" + id;
}
}
if(!isLogin){
signalFeedbackListUpdate(resp)
return
}
return fill_feedback(resp)
const url = "/api/v1/public/feedback?offset=%1&limit=%2&&type=%4&language=%5%6".arg(opt.offset).arg(opt.limit).arg(opt.type).arg(language).arg(ids);
const resp = worker.awaitPromise((promise) => {
get(url, promise.resolve);
});
fill_feedback(resp);
signalFeedbackListUpdate(reqID, resp);
}

// 获取我的反馈
function getMyFeedback(opt) {
const url = "/api/v1/user/feedback?offset=%1&limit=%2&type=%4".arg(opt.offset).arg(opt.limit).arg(opt.type)
get(url, (resp)=>{
for(let feedback of resp) {
const id = feedback.public_id
const stat = worker.awaitPromise(promise=>{
feedbackStat(id, promise.resolve)
})
feedback.view_count = stat.view_count
feedback.like_count = stat.like_count
feedback.collect_count = stat.collect_count
feedback.avatar = avatar
feedback.nickname = nickname
if(feedback.screenshots) {
feedback.screenshots = feedback.screenshots.map((id)=> {
return node + "/api/v1/public/upload/" + id
})
}
}
return fill_feedback(resp)
})
function getMyFeedback(reqID, opt) {
const url = "/api/v1/user/feedback?offset=%1&limit=%2&type=%4".arg(opt.offset).arg(opt.limit).arg(opt.type);
const resp = worker.awaitPromise((promise) => {
get(url, promise.resolve);
});
fill_feedback(resp);
for (let feedback of resp) {
feedback.avatar = avatar
feedback.nickname = nickname
}
signalFeedbackListUpdate(reqID, resp);
}

// 点赞一个反馈
function likeFeedback(id, callback) {
post("/api/v1/user/feedback/%1/like".arg(id), null, callback)
Expand All @@ -225,21 +215,26 @@ Item {
function cancelCollectFeedback(id, callback) {
delete_("/api/v1/user/feedback/%1/collect".arg(id), callback)
}

// 获取和用户关联的反馈
function getRelation(opt) {
let url = "/api/v1/user/feedback/relation?offset=%1&limit=%2&type=%3&relation=%4".arg(opt.offset).arg(opt.limit).arg(opt.type).arg(opt.relation)
get(url, (relations) => {
if(relations.length === 0){
signalFeedbackListUpdate([])
return
}
let ids = []
for(let relation of relations) {
ids.push(relation.feedback_id)
}
getFeedback({offset:"", limit: "",type: opt.type, ids: ids})
})
function getRelation(reqID, opt) {
const url = "/api/v1/user/feedback/relation?offset=%1&limit=%2&type=%3&relation=%4".arg(opt.offset).arg(opt.limit).arg(opt.type).arg(opt.relation);
const relations = worker.awaitPromise((promise) => {
get(url, promise.resolve);
});
if (relations.length === 0) {
signalFeedbackListUpdate(reqID, []);
return ;
}
const ids = relations.map((r) => r.feedback_id);
getFeedback(reqID, {
"offset": 0,
"limit": ids.length,
"type": opt.type,
"ids": ids
});
}

// 获取系统版本
function sysVersion() {
return worker.sysVersion();
Expand Down Expand Up @@ -338,6 +333,12 @@ Item {
function isZH() {
return language.startsWith("zh")
}

// 生成UUID
function genUUID() {
return worker.genUUID();
}

Component.onCompleted: {
node = worker.getNode()
autostart = getAutoStart()
Expand Down
2 changes: 1 addition & 1 deletion src/maincomponentplugin/feedback/Card.qml
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Rectangle {
onLinkActivated: (link)=> {
if(link.startsWith("#")){
const public_id = link.slice(1)
API.getFeedback({type: '', offset: 0, limit: 1, ids: [public_id]})
API.getFeedback("", {type: '', offset: 0, limit: 1, ids: [public_id]})
return
}
Qt.openUrlExternally(link)
Expand Down
2 changes: 1 addition & 1 deletion src/maincomponentplugin/feedback/Detail.qml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Item {
Connections {
target: API
// 列表刷新信号
function onSignalFeedbackListUpdate(feedbacks) {
function onSignalFeedbackListUpdate(reqID, feedbacks) {
if(feedbacks.length==1) {
const feedback = feedbacks[0]
API.publicViewFeedback(feedback.public_id)
Expand Down
20 changes: 13 additions & 7 deletions src/maincomponentplugin/feedback/List.qml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ Item {
property bool hasMore: true
// 是否正在“加载更多”
property bool loadMore: false

// 记录请求ID,避免信号干扰
property string reqID: ''
ListModel {
id: feedbackList
}

function goDetail(feedback) {
API.publicViewFeedback(feedback.public_id)
if(API.isLogin) {
Expand All @@ -45,7 +47,10 @@ Item {
Connections {
target: API
// 列表刷新信号
function onSignalFeedbackListUpdate(feedbacks) {
function onSignalFeedbackListUpdate(reqID, feedbacks) {
if(reqID != root.reqID) {
return
}
root.offset += root.limit
// 返回的条数小于要求的条数,则不再显示“加载更多”按钮
if(feedbacks.length != root.limit) {
Expand All @@ -67,6 +72,7 @@ Item {
root.hasMore = true
feedbackList.clear()
}
root.reqID = API.genUUID()
const opt = {
"offset": root.offset,
"limit": root.limit,
Expand All @@ -75,22 +81,22 @@ Item {
}
switch(root.relation){
case "create":
API.getMyFeedback(opt)
API.getMyFeedback(root.reqID, opt)
break
case "collect":
case "like":
// 获取我的收藏和我的关注
API.getRelation(opt)
API.getRelation(root.reqID, opt)
break
case "":
// 获取反馈广场
API.getFeedback(opt)
API.getFeedback(root.reqID, opt)
break
}
}

Component.onCompleted: {
Qt.callLater(getList, true)
getList(true)
}

// 分类过滤下拉框
Expand Down Expand Up @@ -233,7 +239,7 @@ Item {
repeat: false
onTriggered: {
console.log("timer trigger")
Qt.callLater(getList, false)
getList(false)
}
}
BusyIndicator {
Expand Down
9 changes: 8 additions & 1 deletion src/maincomponentplugin/worker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,11 @@ QVariant Worker::awaitPromise(QJSValue func)
// 如果在qml中调用reject,promise会在qml上下文中抛出异常,await反馈空结果
// 如果在qml中调用resolve,await返回resolve传递的result
return promise->await();
};
};


// 生成UUID
QString Worker::genUUID()
{
return QUuid::createUuid().toString(QUuid::WithoutBraces);
}
2 changes: 2 additions & 0 deletions src/maincomponentplugin/worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ public slots:
// 类似js中的await Promise()
// 可在qml中将异步函数转为同步执行
QVariant awaitPromise(QJSValue func);
// 生成UUID
QString genUUID();
signals:
void userInfoChanged();
void messageChanged();
Expand Down

0 comments on commit 7b07f83

Please sign in to comment.