mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-13 06:23:15 +08:00
Show auto-collected contacts in a table (4.9.1-ops.16).
Align nickname, phone, source, and grant actions like the other access lists. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a10d900a7b
commit
e4cdb6f60a
6 changed files with 220 additions and 153 deletions
190
lib/client.js
190
lib/client.js
|
|
@ -571,7 +571,7 @@ var React24 = __toESM(require("react"), 1);
|
|||
// package.json
|
||||
var package_default = {
|
||||
name: "dsh-im-ops",
|
||||
version: "4.9.1-ops.15",
|
||||
version: "4.9.1-ops.16",
|
||||
description: "Ops fork of dsh-im (all channels kept). Based on @xmanrui/dsh-im@4.9.1 \u2014 access/session policies owned here.",
|
||||
keywords: [
|
||||
"deepseek-harness",
|
||||
|
|
@ -852,6 +852,8 @@ var EN = Object.freeze({
|
|||
"\u673A\u5668\u4EBA\u8BBE\u7F6E\u9875\u7B7E": "Bot settings tabs",
|
||||
"\u6295\u9012\u8BBE\u7F6E": "Delivery settings",
|
||||
"\u8BBF\u95EE\u8BBE\u7F6E": "Access settings",
|
||||
"\u2014": "\u2014",
|
||||
"\u6765\u6E90": "Source",
|
||||
"\u6682\u65E0\u7BA1\u7406\u5458\uFF0C\u53EF\u70B9\u4E0B\u65B9\u65B0\u589E\u3002": "No admins yet. Add one below.",
|
||||
"\u6682\u65E0\u7528\u6237\uFF0C\u53EF\u70B9\u4E0B\u65B9\u65B0\u589E\u3002": "No users yet. Add one below.",
|
||||
"\u4E0D\u53EF\u5220\u9664": "Locked",
|
||||
|
|
@ -13254,90 +13256,123 @@ function AccessGrantSettingsPage({ channel: channel4, account, rpcCall, onSaved
|
|||
h2("legend", null, "\u6700\u8FD1\u8054\u7CFB\u4EBA\uFF08\u81EA\u52A8\u6C89\u6DC0\uFF09"),
|
||||
h2(
|
||||
"p",
|
||||
{ className: "dim-accessUsersEmpty" },
|
||||
{ className: "dim-accessHint" },
|
||||
"\u4EC5\u8BB0\u5F55\u79C1\u804A\u673A\u5668\u4EBA\uFF0C\u6216\u5728\u7FA4\u91CC @ \u673A\u5668\u4EBA\u7684\u4EBA\u3002\u5DF2\u6709\u5BF9\u5E94\u6743\u9650\u7684\u4EBA\u4F1A\u81EA\u52A8\u9690\u85CF\uFF1B\u7535\u8BDD\u662F\u552F\u4E00\u6388\u6743\u952E\uFF0C\u53EF\u4E00\u952E\u52A0\u5165\u79C1\u804A/\u672C\u7FA4\u6388\u6743\u3002"
|
||||
),
|
||||
actionableContacts.length === 0 ? h2(
|
||||
"div",
|
||||
{ className: "dim-accessUsersEmpty" },
|
||||
contacts.length === 0 ? "\u6682\u65E0\u8054\u7CFB\u4EBA\u3002\u6709\u4EBA\u79C1\u804A\u6216 @ \u673A\u5668\u4EBA\u540E\u4F1A\u51FA\u73B0\u5728\u6B64\u3002" : "\u5F53\u524D\u8054\u7CFB\u4EBA\u5747\u5DF2\u5177\u5907\u5BF9\u5E94\u6743\u9650\uFF0C\u65E0\u9700\u518D\u6388\u6743\u3002"
|
||||
) : h2("ul", { className: "dim-accessUserList" }, actionableContacts.slice(0, 30).map((contact) => {
|
||||
const phone = contact.phone || "";
|
||||
const alreadyDirect = Boolean(phone) && ((draft.directMembers ?? []).some((m) => m.phone === phone) || (draft.globalAdmins ?? []).includes(phone));
|
||||
const groupTargets = (contact.groupJids ?? []).filter((jid) => knownGroupJids.includes(jid)).filter((groupJid) => {
|
||||
if (!phone) return true;
|
||||
const group = draft.groups[groupJid] ?? { admins: [], members: [] };
|
||||
return !(group.admins ?? []).includes(phone) && !(group.members ?? []).some((m) => m.phone === phone);
|
||||
});
|
||||
return h2(
|
||||
"li",
|
||||
{
|
||||
key: `${contact.phone ?? ""}-${(contact.lids ?? []).join(",")}`,
|
||||
className: "dim-accessUserRow"
|
||||
},
|
||||
) : h2(
|
||||
"div",
|
||||
{ className: "dim-accessTableWrap" },
|
||||
h2(
|
||||
"table",
|
||||
{ className: "dim-accessTable", "data-kind": "contact" },
|
||||
h2(
|
||||
"div",
|
||||
{ className: "dim-accessField" },
|
||||
h2("strong", null, contactLabel(contact)),
|
||||
h2("span", null, (contact.scenes ?? []).join(" / ")),
|
||||
phone ? null : h2("span", null, "\u5F85\u8865\u7535\u8BDD")
|
||||
"thead",
|
||||
null,
|
||||
h2(
|
||||
"tr",
|
||||
null,
|
||||
h2("th", { scope: "col" }, "\u6635\u79F0"),
|
||||
h2("th", { scope: "col" }, "\u7535\u8BDD"),
|
||||
h2("th", { scope: "col" }, "\u6765\u6E90"),
|
||||
h2("th", { scope: "col", className: "dim-accessTableActions" }, "\u64CD\u4F5C")
|
||||
)
|
||||
),
|
||||
phone && !alreadyDirect ? h2("button", {
|
||||
type: "button",
|
||||
className: "dim-deliveryButton",
|
||||
"data-kind": "primary",
|
||||
disabled: saving,
|
||||
onClick: () => {
|
||||
setDraft((current) => {
|
||||
if (current.directMembers.some((m) => m.phone === phone)) return current;
|
||||
return {
|
||||
...current,
|
||||
directMembers: [
|
||||
...current.directMembers,
|
||||
{ phone, canExecuteCommands: true }
|
||||
]
|
||||
};
|
||||
});
|
||||
setFeedback({ tone: "success", message: "\u5DF2\u52A0\u5165\u79C1\u804A\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002" });
|
||||
}
|
||||
}, "\u52A0\u79C1\u804A") : null,
|
||||
...groupTargets.map((groupJid) => {
|
||||
const group = draft.groups[groupJid] ?? { admins: [], members: [] };
|
||||
const name2 = groupDisplayName(groupJid, draft.groups);
|
||||
return h2("button", {
|
||||
key: `add-${groupJid}`,
|
||||
type: "button",
|
||||
className: "dim-deliveryButton",
|
||||
disabled: saving || !phone,
|
||||
onClick: () => {
|
||||
setDraft((current) => {
|
||||
const existing = current.groups[groupJid] ?? { title: "", admins: [], members: [] };
|
||||
if (existing.admins.includes(phone) || existing.members.some((m) => m.phone === phone)) {
|
||||
return current;
|
||||
}
|
||||
return {
|
||||
...current,
|
||||
groups: {
|
||||
...current.groups,
|
||||
[groupJid]: {
|
||||
...existing,
|
||||
members: [
|
||||
...existing.members,
|
||||
h2("tbody", null, actionableContacts.slice(0, 30).map((contact) => {
|
||||
const phone = contact.phone || "";
|
||||
const nickname = typeof contact.pushName === "string" && contact.pushName.trim() ? contact.pushName.trim() : "\u6682\u65E0\u6635\u79F0";
|
||||
const alreadyDirect = Boolean(phone) && ((draft.directMembers ?? []).some((m) => m.phone === phone) || (draft.globalAdmins ?? []).includes(phone));
|
||||
const groupTargets = (contact.groupJids ?? []).filter((jid) => knownGroupJids.includes(jid)).filter((groupJid) => {
|
||||
if (!phone) return true;
|
||||
const group = draft.groups[groupJid] ?? { admins: [], members: [] };
|
||||
return !(group.admins ?? []).includes(phone) && !(group.members ?? []).some((m) => m.phone === phone);
|
||||
});
|
||||
return h2(
|
||||
"tr",
|
||||
{
|
||||
key: `${contact.phone ?? ""}-${(contact.lids ?? []).join(",")}`
|
||||
},
|
||||
h2(
|
||||
"td",
|
||||
{ className: "dim-accessTableNick" },
|
||||
h2("span", {
|
||||
className: nickname === "\u6682\u65E0\u6635\u79F0" ? "dim-accessNickname dim-accessNicknameEmpty" : "dim-accessNickname"
|
||||
}, nickname)
|
||||
),
|
||||
h2(
|
||||
"td",
|
||||
{ className: "dim-accessTablePhone" },
|
||||
phone || h2("span", { className: "dim-accessNicknameEmpty" }, "\u5F85\u8865\u7535\u8BDD")
|
||||
),
|
||||
h2(
|
||||
"td",
|
||||
{ className: "dim-accessTableSource" },
|
||||
(contact.scenes ?? []).join(" / ") || "\u2014"
|
||||
),
|
||||
h2(
|
||||
"td",
|
||||
{ className: "dim-accessTableActions dim-accessContactActions" },
|
||||
phone && !alreadyDirect ? h2("button", {
|
||||
type: "button",
|
||||
className: "dim-deliveryButton",
|
||||
"data-kind": "primary",
|
||||
disabled: saving,
|
||||
onClick: () => {
|
||||
setDraft((current) => {
|
||||
if (current.directMembers.some((m) => m.phone === phone)) return current;
|
||||
return {
|
||||
...current,
|
||||
directMembers: [
|
||||
...current.directMembers,
|
||||
{ phone, canExecuteCommands: true }
|
||||
]
|
||||
}
|
||||
};
|
||||
});
|
||||
setFeedback({ tone: "success", message: "\u5DF2\u52A0\u5165\u79C1\u804A\u6388\u6743\uFF0C\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002" });
|
||||
}
|
||||
}, "\u52A0\u79C1\u804A") : null,
|
||||
...groupTargets.map((groupJid) => {
|
||||
const name2 = groupDisplayName(groupJid, draft.groups);
|
||||
return h2("button", {
|
||||
key: `add-${groupJid}`,
|
||||
type: "button",
|
||||
className: "dim-deliveryButton",
|
||||
disabled: saving || !phone,
|
||||
onClick: () => {
|
||||
setDraft((current) => {
|
||||
const existing = current.groups[groupJid] ?? { title: "", admins: [], members: [] };
|
||||
if (existing.admins.includes(phone) || existing.members.some((m) => m.phone === phone)) {
|
||||
return current;
|
||||
}
|
||||
return {
|
||||
...current,
|
||||
groups: {
|
||||
...current.groups,
|
||||
[groupJid]: {
|
||||
...existing,
|
||||
members: [
|
||||
...existing.members,
|
||||
{ phone, canExecuteCommands: true }
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
setFeedback({
|
||||
tone: "success",
|
||||
message: ["\u5DF2\u52A0\u5165\u7FA4\u6388\u6743\uFF1A", name2, "\u3002\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002"].join("")
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
setFeedback({
|
||||
tone: "success",
|
||||
message: ["\u5DF2\u52A0\u5165\u7FA4\u6388\u6743\uFF1A", name2, "\u3002\u8BB0\u5F97\u70B9\u4FDD\u5B58\u3002"].join("")
|
||||
});
|
||||
}
|
||||
}, ["\u52A0\u5165\u7FA4\uFF1A", name2].join(""));
|
||||
})
|
||||
);
|
||||
}))
|
||||
}, ["\u52A0\u5165\u7FA4\uFF1A", name2].join(""));
|
||||
})
|
||||
)
|
||||
);
|
||||
}))
|
||||
)
|
||||
)
|
||||
),
|
||||
h2(
|
||||
"fieldset",
|
||||
|
|
@ -14764,6 +14799,13 @@ body[data-ds-dark-theme] .dim-page select option, body[data-ds-dark-theme] .dim-
|
|||
.dim-accessTable[data-kind="member"] th:nth-child(2), .dim-accessTable[data-kind="member"] td:nth-child(2) { width: 36%; }
|
||||
.dim-accessTable[data-kind="member"] th:nth-child(3), .dim-accessTable[data-kind="member"] td:nth-child(3) { width: 28%; }
|
||||
.dim-accessTable[data-kind="member"] th:nth-child(4), .dim-accessTable[data-kind="member"] td:nth-child(4) { width: 16%; }
|
||||
.dim-accessTable[data-kind="contact"] th:nth-child(1), .dim-accessTable[data-kind="contact"] td:nth-child(1) { width: 18%; }
|
||||
.dim-accessTable[data-kind="contact"] th:nth-child(2), .dim-accessTable[data-kind="contact"] td:nth-child(2) { width: 26%; }
|
||||
.dim-accessTable[data-kind="contact"] th:nth-child(3), .dim-accessTable[data-kind="contact"] td:nth-child(3) { width: 18%; }
|
||||
.dim-accessTable[data-kind="contact"] th:nth-child(4), .dim-accessTable[data-kind="contact"] td:nth-child(4) { width: 38%; }
|
||||
.dim-accessTableSource { min-width: 0; color: var(--dsw-alias-label-secondary, #646a73); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.dim-accessContactActions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 6px; }
|
||||
.dim-accessContactActions .dim-deliveryButton { min-height: 30px; padding-inline: 10px; }
|
||||
.dim-accessTableNick { min-width: 0; }
|
||||
.dim-accessTableNick .dim-accessNickname { margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||||
.dim-accessTablePhone { min-width: 0; position: relative; z-index: 0; }
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue