@sparkelf/dsh-task-bus 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +473 -160
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -837,214 +837,523 @@ window.__ModuleLoader__.load({
|
|
|
837
837
|
* that stands in for "disabled". A row missing `reviewStatus` counts as pending, which
|
|
838
838
|
* matches `reviewStatusOf` in the package.
|
|
839
839
|
*/
|
|
840
|
-
async function
|
|
840
|
+
async function readSkillPlazaRows() {
|
|
841
841
|
try {
|
|
842
|
-
const [listResponse, plazaResponse] = await Promise.all([fetch("
|
|
842
|
+
const [listResponse, plazaResponse] = await Promise.all([fetch("api/dsh-skill-center/list", { cache: "no-store" }), fetch("integrations/dataops/skill-plaza?mine=1", { cache: "no-store" })]);
|
|
843
843
|
const disabled = /* @__PURE__ */ new Set();
|
|
844
844
|
if (listResponse.ok) {
|
|
845
845
|
const body = await listResponse.json();
|
|
846
846
|
for (const group of body.groups ?? []) for (const skill of group.skills ?? []) if (typeof skill.name === "string" && skill.modelInvocable === false) disabled.add(skill.name);
|
|
847
847
|
}
|
|
848
|
-
if (!plazaResponse.ok) return
|
|
848
|
+
if (!plazaResponse.ok) return [];
|
|
849
849
|
const plaza = await plazaResponse.json();
|
|
850
|
-
const names =
|
|
850
|
+
const names = [];
|
|
851
851
|
for (const row of plaza.skills ?? []) {
|
|
852
852
|
if (typeof row.name !== "string" || row.name === "") continue;
|
|
853
853
|
if (row.reviewStatus === "approved") continue;
|
|
854
854
|
if (disabled.has(row.name)) continue;
|
|
855
|
-
names.
|
|
855
|
+
names.push(row.name);
|
|
856
856
|
}
|
|
857
|
-
return names
|
|
857
|
+
return names;
|
|
858
858
|
} catch {
|
|
859
|
-
return
|
|
859
|
+
return [];
|
|
860
860
|
}
|
|
861
861
|
}
|
|
862
|
-
/**
|
|
863
|
-
|
|
862
|
+
/**
|
|
863
|
+
* The same review inbox the plaza bell used to show, now rendered inside the task center's
|
|
864
|
+
* notification tab so every notification lives in one list.
|
|
865
|
+
*/
|
|
866
|
+
async function readReviewInbox() {
|
|
867
|
+
try {
|
|
868
|
+
const response = await fetch("integrations/dataops/review-notifications", { cache: "no-store" });
|
|
869
|
+
if (!response.ok) return [];
|
|
870
|
+
const body = await response.json();
|
|
871
|
+
const rows = [];
|
|
872
|
+
for (const raw of body.items ?? []) {
|
|
873
|
+
if (typeof raw.id !== "string" || typeof raw.title !== "string") continue;
|
|
874
|
+
rows.push({
|
|
875
|
+
id: raw.id,
|
|
876
|
+
type: typeof raw.type === "string" ? raw.type : "info",
|
|
877
|
+
title: raw.title,
|
|
878
|
+
...typeof raw.body === "string" && raw.body !== "" ? { body: raw.body } : {},
|
|
879
|
+
createdAt: typeof raw.createdAt === "string" ? raw.createdAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
880
|
+
read: raw.read === true
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
return rows.sort((a, b) => Date.parse(b.createdAt) - Date.parse(a.createdAt)).slice(0, 20);
|
|
884
|
+
} catch {
|
|
885
|
+
return [];
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
/** One notification card shared by every source in the notification tab. */
|
|
889
|
+
function NotificationCard({ title, body, time, unread, onClick }) {
|
|
864
890
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
865
891
|
type: "button",
|
|
866
|
-
onClick
|
|
892
|
+
onClick,
|
|
893
|
+
disabled: onClick === void 0,
|
|
867
894
|
style: {
|
|
868
895
|
display: "flex",
|
|
869
|
-
alignItems: "
|
|
870
|
-
gap:
|
|
896
|
+
alignItems: "flex-start",
|
|
897
|
+
gap: 10,
|
|
871
898
|
width: "100%",
|
|
872
|
-
padding: "
|
|
899
|
+
padding: "10px 12px",
|
|
873
900
|
border: "1px solid " + colors.line,
|
|
874
901
|
borderRadius: 8,
|
|
875
902
|
background: colors.panelAlt,
|
|
876
903
|
color: colors.text,
|
|
877
904
|
fontSize: 12,
|
|
878
905
|
textAlign: "left",
|
|
879
|
-
cursor: "pointer"
|
|
906
|
+
cursor: onClick === void 0 ? "default" : "pointer"
|
|
880
907
|
},
|
|
881
|
-
children: [
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
908
|
+
children: [
|
|
909
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
|
|
910
|
+
flex: "0 0 auto",
|
|
911
|
+
width: 6,
|
|
912
|
+
height: 6,
|
|
913
|
+
marginTop: 6,
|
|
914
|
+
borderRadius: 99,
|
|
915
|
+
background: unread === true ? colors.accent : "transparent"
|
|
916
|
+
} }),
|
|
917
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
918
|
+
style: {
|
|
919
|
+
flex: 1,
|
|
920
|
+
minWidth: 0
|
|
921
|
+
},
|
|
922
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
923
|
+
style: {
|
|
924
|
+
display: "block",
|
|
925
|
+
fontSize: 12,
|
|
926
|
+
fontWeight: 500,
|
|
927
|
+
overflow: "hidden",
|
|
928
|
+
textOverflow: "ellipsis",
|
|
929
|
+
whiteSpace: "nowrap"
|
|
930
|
+
},
|
|
931
|
+
children: title
|
|
932
|
+
}), body === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
933
|
+
style: {
|
|
934
|
+
display: "block",
|
|
935
|
+
marginTop: 2,
|
|
936
|
+
fontSize: 11,
|
|
937
|
+
color: colors.muted
|
|
938
|
+
},
|
|
939
|
+
children: body
|
|
940
|
+
})]
|
|
941
|
+
}),
|
|
942
|
+
time === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
943
|
+
style: {
|
|
944
|
+
fontSize: 10,
|
|
945
|
+
color: colors.muted,
|
|
946
|
+
whiteSpace: "nowrap"
|
|
947
|
+
},
|
|
948
|
+
children: time
|
|
949
|
+
})
|
|
950
|
+
]
|
|
895
951
|
});
|
|
896
952
|
}
|
|
897
|
-
/**
|
|
898
|
-
|
|
899
|
-
|
|
953
|
+
/** How many rows one notification group shows before it pages. */
|
|
954
|
+
const NOTIFICATION_PAGE_SIZE = 10;
|
|
955
|
+
/** Names the reader hid from the review group; clearing is recoverable, so it outlives a reload. */
|
|
956
|
+
const HIDDEN_SKILLS_KEY = "dataops-task-bus-hidden-skills-v1";
|
|
957
|
+
/** Ids the reader cleared from the audit group, so a reload does not bring them back. */
|
|
958
|
+
const CLEARED_NOTIFICATIONS_KEY = "dataops-task-bus-cleared-notifications-v1";
|
|
959
|
+
/** Read a string set the browser persisted; an unreadable value is an empty set. */
|
|
960
|
+
function readStoredSet(key) {
|
|
961
|
+
try {
|
|
962
|
+
const raw = window.localStorage.getItem(key);
|
|
963
|
+
if (raw === null || raw === "") return /* @__PURE__ */ new Set();
|
|
964
|
+
const parsed = JSON.parse(raw);
|
|
965
|
+
return new Set(Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === "string") : []);
|
|
966
|
+
} catch {
|
|
967
|
+
return /* @__PURE__ */ new Set();
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
/** Persist one string set; storage failures leave the in-memory set authoritative. */
|
|
971
|
+
function writeStoredSet(key, values) {
|
|
972
|
+
try {
|
|
973
|
+
window.localStorage.setItem(key, JSON.stringify([...values]));
|
|
974
|
+
} catch {}
|
|
975
|
+
}
|
|
976
|
+
/** Slice one page out of a list and report the page count a pager needs. */
|
|
977
|
+
function pageOf(items, page) {
|
|
978
|
+
const pages = Math.max(1, Math.ceil(items.length / NOTIFICATION_PAGE_SIZE));
|
|
979
|
+
const current = Math.min(Math.max(0, page), pages - 1);
|
|
980
|
+
return {
|
|
981
|
+
rows: items.slice(current * NOTIFICATION_PAGE_SIZE, (current + 1) * NOTIFICATION_PAGE_SIZE),
|
|
982
|
+
pages,
|
|
983
|
+
page: current
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
/** `上一页 / 第 x/y 页 / 下一页`, hidden while a group fits on one page. */
|
|
987
|
+
function NotificationPager({ page, pages, onChange }) {
|
|
988
|
+
if (pages <= 1) return null;
|
|
900
989
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
901
990
|
style: {
|
|
902
991
|
display: "flex",
|
|
903
|
-
|
|
904
|
-
|
|
992
|
+
alignItems: "center",
|
|
993
|
+
justifyContent: "flex-end",
|
|
994
|
+
gap: 8
|
|
995
|
+
},
|
|
996
|
+
children: [
|
|
997
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
998
|
+
size: "sm",
|
|
999
|
+
variant: "ghost",
|
|
1000
|
+
disabled: page <= 0,
|
|
1001
|
+
onClick: () => onChange(page - 1),
|
|
1002
|
+
children: "上一页"
|
|
1003
|
+
}),
|
|
1004
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1005
|
+
style: {
|
|
1006
|
+
fontSize: 12,
|
|
1007
|
+
color: colors.muted,
|
|
1008
|
+
fontVariantNumeric: "tabular-nums"
|
|
1009
|
+
},
|
|
1010
|
+
children: [
|
|
1011
|
+
"第 ",
|
|
1012
|
+
page + 1,
|
|
1013
|
+
"/",
|
|
1014
|
+
pages,
|
|
1015
|
+
" 页"
|
|
1016
|
+
]
|
|
1017
|
+
}),
|
|
1018
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1019
|
+
size: "sm",
|
|
1020
|
+
variant: "ghost",
|
|
1021
|
+
disabled: page >= pages - 1,
|
|
1022
|
+
onClick: () => onChange(page + 1),
|
|
1023
|
+
children: "下一页"
|
|
1024
|
+
})
|
|
1025
|
+
]
|
|
1026
|
+
});
|
|
1027
|
+
}
|
|
1028
|
+
/** The header every group shares: title, total, current page, and its own clear action. */
|
|
1029
|
+
function NotificationGroupHeader({ title, total, pages, page, clearLabel, onClear, restore, testId }) {
|
|
1030
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1031
|
+
"data-testid": testId,
|
|
1032
|
+
style: {
|
|
1033
|
+
display: "flex",
|
|
1034
|
+
alignItems: "center",
|
|
1035
|
+
justifyContent: "space-between",
|
|
1036
|
+
gap: 8
|
|
905
1037
|
},
|
|
906
1038
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
907
1039
|
style: {
|
|
908
1040
|
display: "flex",
|
|
909
|
-
alignItems: "
|
|
910
|
-
|
|
911
|
-
|
|
1041
|
+
alignItems: "baseline",
|
|
1042
|
+
gap: 8,
|
|
1043
|
+
minWidth: 0
|
|
912
1044
|
},
|
|
913
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1045
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
914
1046
|
style: {
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
1047
|
+
fontSize: 13,
|
|
1048
|
+
fontWeight: 600,
|
|
1049
|
+
color: colors.text
|
|
918
1050
|
},
|
|
919
|
-
children:
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
}
|
|
1051
|
+
children: title
|
|
1052
|
+
}), total > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1053
|
+
style: {
|
|
1054
|
+
fontSize: 12,
|
|
1055
|
+
color: "#8ea6c6",
|
|
1056
|
+
fontVariantNumeric: "tabular-nums"
|
|
1057
|
+
},
|
|
1058
|
+
children: [
|
|
1059
|
+
total,
|
|
1060
|
+
" 条",
|
|
1061
|
+
pages > 1 ? ` · 第 ${page + 1}/${pages} 页` : ""
|
|
1062
|
+
]
|
|
1063
|
+
}) : null]
|
|
1064
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1065
|
+
style: {
|
|
1066
|
+
display: "flex",
|
|
1067
|
+
alignItems: "center",
|
|
1068
|
+
gap: 6
|
|
1069
|
+
},
|
|
1070
|
+
children: [restore === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
938
1071
|
size: "sm",
|
|
939
1072
|
variant: "ghost",
|
|
940
|
-
|
|
1073
|
+
onClick: restore.onClick,
|
|
1074
|
+
children: restore.label
|
|
1075
|
+
}), clearLabel === void 0 || onClear === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
1076
|
+
size: "sm",
|
|
1077
|
+
variant: "ghost",
|
|
1078
|
+
"data-testid": testId === void 0 ? void 0 : testId + "-clear",
|
|
1079
|
+
disabled: total === 0,
|
|
941
1080
|
onClick: onClear,
|
|
942
|
-
children:
|
|
1081
|
+
children: clearLabel
|
|
943
1082
|
})]
|
|
944
|
-
})
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1083
|
+
})]
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
/** The "notifications" tab: every source rendered as the same notification card, paged per source. */
|
|
1087
|
+
function KbNotificationPanel({ tasks, skillRows, reviewItems, onOpenSkill, onClear }) {
|
|
1088
|
+
const [auditPage, setAuditPage] = (0, react.useState)(0);
|
|
1089
|
+
const [skillPage, setSkillPage] = (0, react.useState)(0);
|
|
1090
|
+
const [kbPage, setKbPage] = (0, react.useState)(0);
|
|
1091
|
+
const [hiddenSkills, setHiddenSkills] = (0, react.useState)(() => readStoredSet(HIDDEN_SKILLS_KEY));
|
|
1092
|
+
const [clearedIds, setClearedIds] = (0, react.useState)(() => readStoredSet(CLEARED_NOTIFICATIONS_KEY));
|
|
1093
|
+
const audits = reviewItems.filter((item) => !clearedIds.has(item.id));
|
|
1094
|
+
const skills = skillRows.filter((name) => !hiddenSkills.has(name));
|
|
1095
|
+
const audit = pageOf(audits, auditPage);
|
|
1096
|
+
const skill = pageOf(skills, skillPage);
|
|
1097
|
+
const kb = pageOf(tasks, kbPage);
|
|
1098
|
+
const done = tasks.filter((task) => task.stage === "done" || task.stage === "uploaded").length;
|
|
1099
|
+
const timeOf = (value) => {
|
|
1100
|
+
const date = new Date(value);
|
|
1101
|
+
if (Number.isNaN(date.getTime())) return "";
|
|
1102
|
+
return date.toLocaleString("zh-CN", {
|
|
1103
|
+
month: "2-digit",
|
|
1104
|
+
day: "2-digit",
|
|
1105
|
+
hour: "2-digit",
|
|
1106
|
+
minute: "2-digit"
|
|
1107
|
+
});
|
|
1108
|
+
};
|
|
1109
|
+
/** Mark every audit row read on the host, then keep them out of the list so clearing is visible. */
|
|
1110
|
+
const clearAudits = () => {
|
|
1111
|
+
const ids = new Set(clearedIds);
|
|
1112
|
+
for (const item of reviewItems) ids.add(item.id);
|
|
1113
|
+
setClearedIds(ids);
|
|
1114
|
+
writeStoredSet(CLEARED_NOTIFICATIONS_KEY, ids);
|
|
1115
|
+
fetch("integrations/dataops/review-notifications", {
|
|
1116
|
+
method: "POST",
|
|
1117
|
+
headers: { "content-type": "application/json" },
|
|
1118
|
+
body: JSON.stringify({ all: true })
|
|
1119
|
+
}).catch(() => {});
|
|
1120
|
+
};
|
|
1121
|
+
/** Hide the pending skills; the header keeps a 恢复 entry so nothing is lost. */
|
|
1122
|
+
const clearSkills = () => {
|
|
1123
|
+
const names = new Set(hiddenSkills);
|
|
1124
|
+
for (const name of skillRows) names.add(name);
|
|
1125
|
+
setHiddenSkills(names);
|
|
1126
|
+
writeStoredSet(HIDDEN_SKILLS_KEY, names);
|
|
1127
|
+
};
|
|
1128
|
+
const restoreSkills = () => {
|
|
1129
|
+
setHiddenSkills(/* @__PURE__ */ new Set());
|
|
1130
|
+
writeStoredSet(HIDDEN_SKILLS_KEY, []);
|
|
1131
|
+
setSkillPage(0);
|
|
1132
|
+
};
|
|
1133
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1134
|
+
style: {
|
|
1135
|
+
display: "flex",
|
|
1136
|
+
flexDirection: "column",
|
|
1137
|
+
gap: 14
|
|
1138
|
+
},
|
|
1139
|
+
children: [
|
|
1140
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
956
1141
|
style: {
|
|
957
|
-
padding: "10px 12px",
|
|
958
|
-
border: "1px solid " + colors.line,
|
|
959
|
-
borderRadius: 8,
|
|
960
|
-
background: colors.panelAlt,
|
|
961
1142
|
display: "flex",
|
|
962
1143
|
flexDirection: "column",
|
|
963
|
-
gap:
|
|
1144
|
+
gap: 8
|
|
964
1145
|
},
|
|
965
1146
|
children: [
|
|
966
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1147
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(NotificationGroupHeader, {
|
|
1148
|
+
title: "审核通知",
|
|
1149
|
+
testId: "notify-audit",
|
|
1150
|
+
total: audits.length,
|
|
1151
|
+
pages: audit.pages,
|
|
1152
|
+
page: audit.page,
|
|
1153
|
+
clearLabel: "清空",
|
|
1154
|
+
onClear: clearAudits
|
|
1155
|
+
}),
|
|
1156
|
+
audits.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
967
1157
|
style: {
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
1158
|
+
padding: 14,
|
|
1159
|
+
textAlign: "center",
|
|
1160
|
+
color: colors.muted,
|
|
1161
|
+
fontSize: 12
|
|
1162
|
+
},
|
|
1163
|
+
children: "暂无审核通知"
|
|
1164
|
+
}) : audit.rows.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NotificationCard, {
|
|
1165
|
+
title: item.title,
|
|
1166
|
+
body: item.body,
|
|
1167
|
+
time: timeOf(item.createdAt),
|
|
1168
|
+
unread: !item.read,
|
|
1169
|
+
onClick: onOpenSkill
|
|
1170
|
+
}, item.id)),
|
|
1171
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(NotificationPager, {
|
|
1172
|
+
page: audit.page,
|
|
1173
|
+
pages: audit.pages,
|
|
1174
|
+
onChange: setAuditPage
|
|
1175
|
+
})
|
|
1176
|
+
]
|
|
1177
|
+
}),
|
|
1178
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1179
|
+
style: {
|
|
1180
|
+
display: "flex",
|
|
1181
|
+
flexDirection: "column",
|
|
1182
|
+
gap: 8
|
|
1183
|
+
},
|
|
1184
|
+
children: [
|
|
1185
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(NotificationGroupHeader, {
|
|
1186
|
+
title: "技能广场待审核",
|
|
1187
|
+
testId: "notify-skills",
|
|
1188
|
+
total: skills.length,
|
|
1189
|
+
pages: skill.pages,
|
|
1190
|
+
page: skill.page,
|
|
1191
|
+
clearLabel: "清空",
|
|
1192
|
+
onClear: clearSkills,
|
|
1193
|
+
...hiddenSkills.size > 0 ? { restore: {
|
|
1194
|
+
label: `恢复隐藏的 ${hiddenSkills.size} 条`,
|
|
1195
|
+
onClick: restoreSkills
|
|
1196
|
+
} } : {}
|
|
1197
|
+
}),
|
|
1198
|
+
skills.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1199
|
+
style: {
|
|
1200
|
+
padding: 14,
|
|
1201
|
+
textAlign: "center",
|
|
1202
|
+
color: colors.muted,
|
|
1203
|
+
fontSize: 12
|
|
1204
|
+
},
|
|
1205
|
+
children: "暂无待审核技能"
|
|
1206
|
+
}) : skill.rows.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NotificationCard, {
|
|
1207
|
+
title: "技能「" + name + "」等待审核",
|
|
1208
|
+
body: "提交到技能广场,等待管理员审核",
|
|
1209
|
+
unread: true,
|
|
1210
|
+
onClick: onOpenSkill
|
|
1211
|
+
}, name)),
|
|
1212
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(NotificationPager, {
|
|
1213
|
+
page: skill.page,
|
|
1214
|
+
pages: skill.pages,
|
|
1215
|
+
onChange: setSkillPage
|
|
1216
|
+
})
|
|
1217
|
+
]
|
|
1218
|
+
}),
|
|
1219
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1220
|
+
style: {
|
|
1221
|
+
display: "flex",
|
|
1222
|
+
flexDirection: "column",
|
|
1223
|
+
gap: 8
|
|
1224
|
+
},
|
|
1225
|
+
children: [
|
|
1226
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(NotificationGroupHeader, {
|
|
1227
|
+
title: "知识库任务",
|
|
1228
|
+
testId: "notify-kb",
|
|
1229
|
+
total: tasks.length,
|
|
1230
|
+
pages: kb.pages,
|
|
1231
|
+
page: kb.page,
|
|
1232
|
+
clearLabel: "清空记录",
|
|
1233
|
+
onClear
|
|
1234
|
+
}),
|
|
1235
|
+
tasks.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1236
|
+
style: {
|
|
1237
|
+
fontSize: 12,
|
|
1238
|
+
color: colors.muted,
|
|
1239
|
+
fontVariantNumeric: "tabular-nums"
|
|
971
1240
|
},
|
|
972
1241
|
children: [
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
overflow: "hidden",
|
|
978
|
-
textOverflow: "ellipsis",
|
|
979
|
-
whiteSpace: "nowrap",
|
|
980
|
-
fontSize: 12,
|
|
981
|
-
fontWeight: 500,
|
|
982
|
-
color: colors.text
|
|
983
|
-
},
|
|
984
|
-
children: task.fileName
|
|
985
|
-
}),
|
|
986
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
987
|
-
style: {
|
|
988
|
-
fontSize: 10,
|
|
989
|
-
color: colors.muted
|
|
990
|
-
},
|
|
991
|
-
children: new Date(task.startedAt).toLocaleTimeString("zh-CN", {
|
|
992
|
-
hour: "2-digit",
|
|
993
|
-
minute: "2-digit"
|
|
994
|
-
})
|
|
995
|
-
}),
|
|
996
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
997
|
-
style: {
|
|
998
|
-
fontSize: 10,
|
|
999
|
-
color: tone,
|
|
1000
|
-
whiteSpace: "nowrap"
|
|
1001
|
-
},
|
|
1002
|
-
children: KB_STAGE_LABEL[task.stage]
|
|
1003
|
-
})
|
|
1242
|
+
"已完成 ",
|
|
1243
|
+
done,
|
|
1244
|
+
"/",
|
|
1245
|
+
tasks.length
|
|
1004
1246
|
]
|
|
1005
|
-
}),
|
|
1006
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
1247
|
+
}) : null,
|
|
1248
|
+
tasks.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1007
1249
|
style: {
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1250
|
+
padding: 14,
|
|
1251
|
+
textAlign: "center",
|
|
1252
|
+
color: colors.muted,
|
|
1253
|
+
fontSize: 12
|
|
1011
1254
|
},
|
|
1012
|
-
children:
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
background: "rgba(255,255,255,.08)",
|
|
1018
|
-
overflow: "hidden"
|
|
1019
|
-
},
|
|
1020
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
1021
|
-
width: String(percent) + "%",
|
|
1022
|
-
height: "100%",
|
|
1023
|
-
borderRadius: 999,
|
|
1024
|
-
background: tone,
|
|
1025
|
-
transition: "width 120ms linear"
|
|
1026
|
-
} })
|
|
1027
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1255
|
+
children: "暂无提取任务"
|
|
1256
|
+
}) : kb.rows.map((task) => {
|
|
1257
|
+
const percent = Math.max(0, Math.min(100, Math.round(task.progress ?? (task.stage === "done" ? 100 : task.stage === "uploaded" ? 100 : 0))));
|
|
1258
|
+
const tone = task.stage === "failed" ? colors.danger : task.stage === "done" || task.stage === "uploaded" ? colors.success : colors.accent;
|
|
1259
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1028
1260
|
style: {
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
fontVariantNumeric: "tabular-nums"
|
|
1261
|
+
padding: "10px 12px",
|
|
1262
|
+
border: "1px solid " + colors.line,
|
|
1263
|
+
borderRadius: 8,
|
|
1264
|
+
background: colors.panelAlt
|
|
1034
1265
|
},
|
|
1035
|
-
children:
|
|
1036
|
-
|
|
1266
|
+
children: [
|
|
1267
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1268
|
+
style: {
|
|
1269
|
+
display: "flex",
|
|
1270
|
+
alignItems: "center",
|
|
1271
|
+
gap: 8
|
|
1272
|
+
},
|
|
1273
|
+
children: [
|
|
1274
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1275
|
+
style: {
|
|
1276
|
+
flex: 1,
|
|
1277
|
+
minWidth: 0,
|
|
1278
|
+
overflow: "hidden",
|
|
1279
|
+
textOverflow: "ellipsis",
|
|
1280
|
+
whiteSpace: "nowrap",
|
|
1281
|
+
fontSize: 12,
|
|
1282
|
+
fontWeight: 600,
|
|
1283
|
+
color: colors.text
|
|
1284
|
+
},
|
|
1285
|
+
children: task.fileName
|
|
1286
|
+
}),
|
|
1287
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1288
|
+
style: {
|
|
1289
|
+
fontSize: 10,
|
|
1290
|
+
color: colors.muted
|
|
1291
|
+
},
|
|
1292
|
+
children: new Date(task.startedAt).toLocaleTimeString("zh-CN", {
|
|
1293
|
+
hour: "2-digit",
|
|
1294
|
+
minute: "2-digit"
|
|
1295
|
+
})
|
|
1296
|
+
}),
|
|
1297
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1298
|
+
style: {
|
|
1299
|
+
fontSize: 10,
|
|
1300
|
+
color: tone,
|
|
1301
|
+
whiteSpace: "nowrap"
|
|
1302
|
+
},
|
|
1303
|
+
children: KB_STAGE_LABEL[task.stage]
|
|
1304
|
+
})
|
|
1305
|
+
]
|
|
1306
|
+
}),
|
|
1307
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1308
|
+
style: {
|
|
1309
|
+
display: "flex",
|
|
1310
|
+
alignItems: "center",
|
|
1311
|
+
gap: 8
|
|
1312
|
+
},
|
|
1313
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1314
|
+
style: {
|
|
1315
|
+
flex: 1,
|
|
1316
|
+
height: 6,
|
|
1317
|
+
borderRadius: 999,
|
|
1318
|
+
background: "rgba(255,255,255,.08)",
|
|
1319
|
+
overflow: "hidden"
|
|
1320
|
+
},
|
|
1321
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
1322
|
+
width: String(percent) + "%",
|
|
1323
|
+
height: "100%",
|
|
1324
|
+
borderRadius: 999,
|
|
1325
|
+
background: tone,
|
|
1326
|
+
transition: "width 120ms ease"
|
|
1327
|
+
} })
|
|
1328
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1329
|
+
style: {
|
|
1330
|
+
minWidth: 34,
|
|
1331
|
+
textAlign: "right",
|
|
1332
|
+
fontSize: 11,
|
|
1333
|
+
color: colors.muted,
|
|
1334
|
+
fontVariantNumeric: "tabular-nums"
|
|
1335
|
+
},
|
|
1336
|
+
children: String(percent) + "%"
|
|
1337
|
+
})]
|
|
1338
|
+
}),
|
|
1339
|
+
task.error !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1340
|
+
style: {
|
|
1341
|
+
fontSize: 11,
|
|
1342
|
+
color: colors.danger
|
|
1343
|
+
},
|
|
1344
|
+
children: task.error
|
|
1345
|
+
}) : null
|
|
1346
|
+
]
|
|
1347
|
+
}, task.id);
|
|
1037
1348
|
}),
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
children: task.error
|
|
1044
|
-
}) : null
|
|
1349
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(NotificationPager, {
|
|
1350
|
+
page: kb.page,
|
|
1351
|
+
pages: kb.pages,
|
|
1352
|
+
onChange: setKbPage
|
|
1353
|
+
})
|
|
1045
1354
|
]
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1355
|
+
})
|
|
1356
|
+
]
|
|
1048
1357
|
});
|
|
1049
1358
|
}
|
|
1050
1359
|
const TaskCenterButton = ({ openSession }) => {
|
|
@@ -1059,7 +1368,8 @@ window.__ModuleLoader__.load({
|
|
|
1059
1368
|
const [anchor, setAnchor] = (0, react.useState)(null);
|
|
1060
1369
|
const [pendingCount, setPendingCount] = (0, react.useState)(0);
|
|
1061
1370
|
const [kbTasks, setKbTasks] = (0, react.useState)(() => readKbTasks());
|
|
1062
|
-
const [
|
|
1371
|
+
const [skillRows, setSkillRows] = (0, react.useState)([]);
|
|
1372
|
+
const [reviewInbox, setReviewInbox] = (0, react.useState)([]);
|
|
1063
1373
|
(0, react.useEffect)(() => {
|
|
1064
1374
|
if (document.getElementById(TASK_BUS_STYLE_ID) !== null) return;
|
|
1065
1375
|
const style = document.createElement("style");
|
|
@@ -1160,8 +1470,11 @@ window.__ModuleLoader__.load({
|
|
|
1160
1470
|
(0, react.useEffect)(() => {
|
|
1161
1471
|
let alive = true;
|
|
1162
1472
|
const sync = () => {
|
|
1163
|
-
|
|
1164
|
-
if (alive)
|
|
1473
|
+
readSkillPlazaRows().then((rows) => {
|
|
1474
|
+
if (alive) setSkillRows(rows);
|
|
1475
|
+
});
|
|
1476
|
+
readReviewInbox().then((items) => {
|
|
1477
|
+
if (alive) setReviewInbox(items);
|
|
1165
1478
|
});
|
|
1166
1479
|
};
|
|
1167
1480
|
sync();
|
|
@@ -1321,7 +1634,7 @@ window.__ModuleLoader__.load({
|
|
|
1321
1634
|
strokeLinejoin: "round",
|
|
1322
1635
|
"aria-hidden": "true",
|
|
1323
1636
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M13.7 21a2 2 0 0 1-3.4 0" })]
|
|
1324
|
-
}), pendingCount + kbPending +
|
|
1637
|
+
}), pendingCount + kbPending + skillRows.length + reviewInbox.filter((item) => !item.read).length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1325
1638
|
style: {
|
|
1326
1639
|
position: "absolute",
|
|
1327
1640
|
bottom: -2,
|
|
@@ -1337,7 +1650,7 @@ window.__ModuleLoader__.load({
|
|
|
1337
1650
|
lineHeight: "14px",
|
|
1338
1651
|
textAlign: "center"
|
|
1339
1652
|
},
|
|
1340
|
-
children: pendingCount + kbPending +
|
|
1653
|
+
children: pendingCount + kbPending + skillRows.length + reviewInbox.filter((item) => !item.read).length > 99 ? "99+" : pendingCount + kbPending + skillRows.length + reviewInbox.filter((item) => !item.read).length
|
|
1341
1654
|
}) : null]
|
|
1342
1655
|
}) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
1343
1656
|
open,
|
|
@@ -1433,13 +1746,13 @@ window.__ModuleLoader__.load({
|
|
|
1433
1746
|
overflowY: "auto",
|
|
1434
1747
|
flex: 1
|
|
1435
1748
|
},
|
|
1436
|
-
children: tab === "notifications" ? /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1437
|
-
count: skillPending,
|
|
1438
|
-
onOpen: openSkillCenter
|
|
1439
|
-
}) : null, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KbNotificationPanel, {
|
|
1749
|
+
children: tab === "notifications" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(KbNotificationPanel, {
|
|
1440
1750
|
tasks: kbTasks,
|
|
1751
|
+
skillRows,
|
|
1752
|
+
reviewItems: reviewInbox,
|
|
1753
|
+
onOpenSkill: openSkillCenter,
|
|
1441
1754
|
onClear: clearKbTasks
|
|
1442
|
-
})
|
|
1755
|
+
}) : selected !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskDetail, {
|
|
1443
1756
|
task: selected,
|
|
1444
1757
|
onBack: () => setSelected(null)
|
|
1445
1758
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|