diff --git a/apps/mobile/src/screens/WorkspaceScreen.tsx b/apps/mobile/src/screens/WorkspaceScreen.tsx
index 714cb0bb..24935347 100644
--- a/apps/mobile/src/screens/WorkspaceScreen.tsx
+++ b/apps/mobile/src/screens/WorkspaceScreen.tsx
@@ -3115,7 +3115,8 @@ const RevisionHistoryModal = ({
const revisions = revisionsQuery.data?.revisions ?? [];
const selectedRevision = revisions.find((revision) => revision.id === selectedRevisionId) ?? revisions[0] ?? null;
- const changedLines = selectedRevision ? countChangedLines(selectedRevision.contentMarkdown, memo?.contentMarkdown ?? "") : 0;
+ const diffRows = selectedRevision ? buildRevisionDiffRows(selectedRevision.contentMarkdown, memo?.contentMarkdown ?? "") : null;
+ const changedLines = diffRows?.changed ?? 0;
useEffect(() => {
if (memo && revisions.length > 0 && !selectedRevisionId) {
@@ -3213,11 +3214,11 @@ const RevisionHistoryModal = ({
历史版本
- {selectedRevision.contentMarkdown || selectedRevision.contentText || "没有正文内容"}
+
当前内容
- {memo?.contentMarkdown || memo?.contentText || "没有正文内容"}
+
>
) : null}
@@ -3231,6 +3232,36 @@ const RevisionHistoryModal = ({
);
};
+const RevisionDiffPreview = ({ rows, tone }: { rows: DiffRow[]; tone: "history" | "current" }) => {
+ const hasContent = rows.some((row) => row.text);
+
+ if (!hasContent) {
+ return 没有正文内容;
+ }
+
+ return (
+
+ {rows.map((row) => {
+ const changed = row.state === "changed";
+
+ return (
+
+ {row.lineNumber}
+ {row.text || " "}
+
+ );
+ })}
+
+ );
+};
+
const MemoDetailModal = ({
isDeleting,
isLoading,
@@ -4731,19 +4762,42 @@ const buildMcpRemoteConfig = (baseUrl: string, token: string) =>
2
);
-const countChangedLines = (left: string, right: string) => {
+type DiffRow = {
+ lineNumber: number;
+ text: string;
+ state: "same" | "changed" | "empty";
+};
+
+const buildRevisionDiffRows = (left: string, right: string) => {
const leftLines = left.split("\n");
const rightLines = right.split("\n");
- const maxLines = Math.max(leftLines.length, rightLines.length);
+ const maxLines = Math.max(leftLines.length, rightLines.length, 1);
+ const leftRows: DiffRow[] = [];
+ const rightRows: DiffRow[] = [];
let changed = 0;
for (let index = 0; index < maxLines; index += 1) {
- if ((leftLines[index] ?? "") !== (rightLines[index] ?? "")) {
+ const leftText = leftLines[index] ?? "";
+ const rightText = rightLines[index] ?? "";
+ const isChanged = leftText !== rightText;
+
+ if (isChanged) {
changed += 1;
}
+
+ leftRows.push({
+ lineNumber: index + 1,
+ text: leftText,
+ state: isChanged ? "changed" : leftText ? "same" : "empty",
+ });
+ rightRows.push({
+ lineNumber: index + 1,
+ text: rightText,
+ state: isChanged ? "changed" : rightText ? "same" : "empty",
+ });
}
- return changed;
+ return { changed, leftRows, rightRows };
};
const formatRevisionActor = (actor: string) => {
@@ -5833,6 +5887,45 @@ const styles = StyleSheet.create({
fontSize: 13,
lineHeight: 20,
},
+ revisionDiffTable: {
+ borderColor: "#e2e8f0",
+ borderRadius: 8,
+ borderWidth: 1,
+ overflow: "hidden",
+ },
+ revisionDiffRow: {
+ borderBottomColor: "#f1f5f9",
+ borderBottomWidth: 1,
+ flexDirection: "row",
+ minHeight: 28,
+ },
+ revisionDiffRowHistory: {
+ backgroundColor: "#fffbeb",
+ },
+ revisionDiffRowCurrent: {
+ backgroundColor: "#ecfdf5",
+ },
+ revisionDiffLineNumber: {
+ borderRightColor: "#e2e8f0",
+ borderRightWidth: 1,
+ color: "#94a3b8",
+ fontSize: 11,
+ minWidth: 42,
+ paddingHorizontal: 8,
+ paddingTop: 6,
+ textAlign: "right",
+ },
+ revisionDiffText: {
+ color: "#334155",
+ flex: 1,
+ fontSize: 12,
+ lineHeight: 18,
+ paddingHorizontal: 10,
+ paddingVertical: 5,
+ },
+ revisionDiffTextEmpty: {
+ color: "#94a3b8",
+ },
label: {
color: "#334155",
fontSize: 13,