feat: add thread status read views
This commit is contained in:
@@ -231,6 +231,10 @@ public class BossApiClient {
|
||||
return requestWithRestore("GET", "/api/v1/projects/" + encode(projectId) + "/participants", null);
|
||||
}
|
||||
|
||||
public ApiResponse getThreadStatus(String projectId) throws IOException, JSONException {
|
||||
return requestWithRestore("GET", "/api/v1/projects/" + encode(projectId) + "/thread-status", null);
|
||||
}
|
||||
|
||||
public ApiResponse replaceConversationParticipants(String projectId, JSONArray memberProjectIds) throws IOException, JSONException {
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("memberProjectIds", memberProjectIds == null ? new JSONArray() : memberProjectIds);
|
||||
|
||||
@@ -102,6 +102,15 @@ public class ConversationInfoActivity extends BossScreenActivity {
|
||||
v -> openProject(projectId, projectName)
|
||||
));
|
||||
|
||||
appendContent(BossUi.buildWechatMenuRow(
|
||||
this,
|
||||
"线程状态",
|
||||
"只读状态文档和最近进展事件",
|
||||
projectFolderName.isEmpty() ? "只读" : projectFolderName + " · 只读",
|
||||
null,
|
||||
v -> openThreadStatus()
|
||||
));
|
||||
|
||||
appendContent(BossUi.buildWechatMenuRow(
|
||||
this,
|
||||
"参与线程",
|
||||
@@ -175,6 +184,17 @@ public class ConversationInfoActivity extends BossScreenActivity {
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void openThreadStatus() {
|
||||
if (projectId == null || projectId.isEmpty()) {
|
||||
showMessage("缺少 projectId");
|
||||
return;
|
||||
}
|
||||
Intent intent = new Intent(this, ThreadStatusActivity.class);
|
||||
intent.putExtra(ThreadStatusActivity.EXTRA_PROJECT_ID, projectId);
|
||||
intent.putExtra(ThreadStatusActivity.EXTRA_PROJECT_NAME, projectName);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
private void openRenameDialog() {
|
||||
final EditText input = BossUi.buildInput(this, "线程名", false);
|
||||
input.setText(projectName == null ? "" : projectName);
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
package com.hyzq.boss;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class ThreadStatusActivity extends BossScreenActivity {
|
||||
public static final String EXTRA_PROJECT_ID = "project_id";
|
||||
public static final String EXTRA_PROJECT_NAME = "project_name";
|
||||
|
||||
private String projectId;
|
||||
private String projectName;
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
projectId = getIntent().getStringExtra(EXTRA_PROJECT_ID);
|
||||
projectName = getIntent().getStringExtra(EXTRA_PROJECT_NAME);
|
||||
configureScreen("线程状态", projectName == null ? "只读状态文档" : projectName);
|
||||
setHeaderAction("只读", v -> showMessage("线程状态只读"));
|
||||
reload();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reload() {
|
||||
if (projectId == null || projectId.isEmpty()) {
|
||||
replaceContent(BossUi.buildEmptyCard(this, "缺少 projectId。"));
|
||||
setRefreshing(false);
|
||||
return;
|
||||
}
|
||||
setRefreshing(true);
|
||||
executor.execute(() -> {
|
||||
try {
|
||||
BossApiClient.ApiResponse response = apiClient.getThreadStatus(projectId);
|
||||
if (!response.ok()) throw new IllegalStateException(response.message());
|
||||
runOnUiThread(() -> renderThreadStatus(response.json));
|
||||
} catch (Exception error) {
|
||||
runOnUiThread(() -> {
|
||||
setRefreshing(false);
|
||||
replaceContent(BossUi.buildEmptyCard(this, "线程状态加载失败:" + error.getMessage()));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void renderThreadStatus(JSONObject payload) {
|
||||
replaceContent();
|
||||
JSONObject document = payload.optJSONObject("threadStatusDocument");
|
||||
JSONArray recentProgressEvents = payload.optJSONArray("recentProgressEvents");
|
||||
|
||||
if (document == null) {
|
||||
appendContent(BossUi.buildEmptyCard(this, "当前还没有线程状态文档。"));
|
||||
setRefreshing(false);
|
||||
return;
|
||||
}
|
||||
|
||||
String threadDisplayName = document.optString(
|
||||
"threadDisplayName",
|
||||
projectName == null ? "线程状态" : projectName
|
||||
);
|
||||
configureScreen("线程状态", buildSubtitle(document, recentProgressEvents));
|
||||
|
||||
appendContent(BossUi.buildSimpleProfileHeader(
|
||||
this,
|
||||
threadDisplayName,
|
||||
"只读状态文档",
|
||||
buildHeaderDetail(document, recentProgressEvents)
|
||||
));
|
||||
|
||||
appendStatusCard("当前目标", document.optString("projectGoal", "暂无目标"));
|
||||
appendStatusCard("当前阶段", document.optString("currentPhase", "暂无阶段"));
|
||||
appendStatusCard("当前进度", document.optString("currentProgress", "暂无进度"));
|
||||
appendStatusCard("技术架构", document.optString("technicalArchitecture", "暂无架构"));
|
||||
appendStatusCard("当前阻塞", document.optString("currentBlockers", "暂无阻塞"));
|
||||
appendStatusCard("建议下一步", document.optString("recommendedNextStep", "暂无建议"));
|
||||
appendRecentEvents(recentProgressEvents);
|
||||
|
||||
setRefreshing(false);
|
||||
}
|
||||
|
||||
private void appendStatusCard(String title, String body) {
|
||||
appendContent(BossUi.buildCard(this, title, body, ""));
|
||||
}
|
||||
|
||||
private void appendRecentEvents(@Nullable JSONArray recentProgressEvents) {
|
||||
int count = recentProgressEvents == null ? 0 : recentProgressEvents.length();
|
||||
appendContent(BossUi.buildWechatMenuRow(
|
||||
this,
|
||||
"最近进展事件",
|
||||
count <= 0 ? "当前还没有进展事件。" : "共 " + count + " 条",
|
||||
"只读视图 · 最近 5 条",
|
||||
null,
|
||||
null
|
||||
));
|
||||
if (recentProgressEvents == null || recentProgressEvents.length() == 0) {
|
||||
appendContent(BossUi.buildEmptyCard(this, "当前还没有进展事件。"));
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < recentProgressEvents.length(); i++) {
|
||||
JSONObject event = recentProgressEvents.optJSONObject(i);
|
||||
if (event == null) continue;
|
||||
LinearLayout row = BossUi.buildWechatMenuRow(
|
||||
this,
|
||||
event.optString("summary", "线程状态更新"),
|
||||
event.optString("phase", event.optString("eventType", "progress_updated")),
|
||||
buildEventMeta(event),
|
||||
null,
|
||||
null
|
||||
);
|
||||
appendContent(row);
|
||||
}
|
||||
}
|
||||
|
||||
private String buildSubtitle(JSONObject document, @Nullable JSONArray recentProgressEvents) {
|
||||
int count = recentProgressEvents == null ? 0 : recentProgressEvents.length();
|
||||
String folderName = document.optString("folderName", "");
|
||||
String suffix = count <= 0 ? "暂无进展事件" : "最近 " + count + " 条进展事件";
|
||||
if (folderName.isEmpty()) {
|
||||
return suffix;
|
||||
}
|
||||
return folderName + " · " + suffix;
|
||||
}
|
||||
|
||||
private String buildHeaderDetail(JSONObject document, @Nullable JSONArray recentProgressEvents) {
|
||||
int count = recentProgressEvents == null ? 0 : recentProgressEvents.length();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String threadId = document.optString("threadId", "");
|
||||
if (!threadId.isEmpty()) {
|
||||
builder.append(threadId);
|
||||
}
|
||||
String deviceId = document.optString("deviceId", "");
|
||||
if (!deviceId.isEmpty()) {
|
||||
if (builder.length() > 0) {
|
||||
builder.append(" · ");
|
||||
}
|
||||
builder.append(deviceId);
|
||||
}
|
||||
if (builder.length() > 0) {
|
||||
builder.append(" · ");
|
||||
}
|
||||
builder.append(count <= 0 ? "暂无进展事件" : count + " 条进展事件");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String buildEventMeta(JSONObject event) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String deviceId = event.optString("deviceId", "");
|
||||
if (!deviceId.isEmpty()) {
|
||||
builder.append(deviceId);
|
||||
}
|
||||
String createdAt = event.optString("createdAt", "");
|
||||
if (!createdAt.isEmpty()) {
|
||||
if (builder.length() > 0) {
|
||||
builder.append(" · ");
|
||||
}
|
||||
builder.append(createdAt);
|
||||
}
|
||||
if (builder.length() == 0) {
|
||||
return event.optString("eventType", "progress_updated");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user