mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-09 00:33:20 +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
|
|
@ -679,90 +679,106 @@ export function AccessGrantSettingsPage({ channel, account, rpcCall, onSaved })
|
|||
}, '添加群'))),
|
||||
h('fieldset', { className: 'dim-accessScene', disabled: saving },
|
||||
h('legend', null, '最近联系人(自动沉淀)'),
|
||||
h('p', { className: 'dim-accessUsersEmpty' },
|
||||
h('p', { className: 'dim-accessHint' },
|
||||
'仅记录私聊机器人,或在群里 @ 机器人的人。已有对应权限的人会自动隐藏;电话是唯一授权键,可一键加入私聊/本群授权。'),
|
||||
actionableContacts.length === 0
|
||||
? h('div', { className: 'dim-accessUsersEmpty' },
|
||||
contacts.length === 0
|
||||
? '暂无联系人。有人私聊或 @ 机器人后会出现在此。'
|
||||
: '当前联系人均已具备对应权限,无需再授权。')
|
||||
: h('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 h('li', {
|
||||
key: `${contact.phone ?? ''}-${(contact.lids ?? []).join(',')}`,
|
||||
className: 'dim-accessUserRow',
|
||||
},
|
||||
h('div', { className: 'dim-accessField' },
|
||||
h('strong', null, contactLabel(contact)),
|
||||
h('span', null, (contact.scenes ?? []).join(' / ')),
|
||||
phone ? null : h('span', null, '待补电话')),
|
||||
phone && !alreadyDirect ? h('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: '已加入私聊授权,记得点保存。' });
|
||||
},
|
||||
}, '加私聊') : null,
|
||||
...groupTargets.map((groupJid) => {
|
||||
const group = draft.groups[groupJid] ?? { admins: [], members: [] };
|
||||
const name = groupDisplayName(groupJid, draft.groups);
|
||||
return h('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: ['已加入群授权:', name, '。记得点保存。'].join(''),
|
||||
: h('div', { className: 'dim-accessTableWrap' },
|
||||
h('table', { className: 'dim-accessTable', 'data-kind': 'contact' },
|
||||
h('thead', null,
|
||||
h('tr', null,
|
||||
h('th', { scope: 'col' }, '昵称'),
|
||||
h('th', { scope: 'col' }, '电话'),
|
||||
h('th', { scope: 'col' }, '来源'),
|
||||
h('th', { scope: 'col', className: 'dim-accessTableActions' }, '操作'))),
|
||||
h('tbody', null, actionableContacts.slice(0, 30).map((contact) => {
|
||||
const phone = contact.phone || '';
|
||||
const nickname = (typeof contact.pushName === 'string' && contact.pushName.trim())
|
||||
? contact.pushName.trim()
|
||||
: '暂无昵称';
|
||||
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 h('tr', {
|
||||
key: `${contact.phone ?? ''}-${(contact.lids ?? []).join(',')}`,
|
||||
},
|
||||
}, ['加入群:', name].join(''));
|
||||
}));
|
||||
}))),
|
||||
h('td', { className: 'dim-accessTableNick' },
|
||||
h('span', {
|
||||
className: nickname === '暂无昵称'
|
||||
? 'dim-accessNickname dim-accessNicknameEmpty'
|
||||
: 'dim-accessNickname',
|
||||
}, nickname)),
|
||||
h('td', { className: 'dim-accessTablePhone' },
|
||||
phone || h('span', { className: 'dim-accessNicknameEmpty' }, '待补电话')),
|
||||
h('td', { className: 'dim-accessTableSource' },
|
||||
(contact.scenes ?? []).join(' / ') || '—'),
|
||||
h('td', { className: 'dim-accessTableActions dim-accessContactActions' },
|
||||
phone && !alreadyDirect ? h('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: '已加入私聊授权,记得点保存。' });
|
||||
},
|
||||
}, '加私聊') : null,
|
||||
...groupTargets.map((groupJid) => {
|
||||
const name = groupDisplayName(groupJid, draft.groups);
|
||||
return h('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: ['已加入群授权:', name, '。记得点保存。'].join(''),
|
||||
});
|
||||
},
|
||||
}, ['加入群:', name].join(''));
|
||||
})));
|
||||
}))))),
|
||||
h('fieldset', { className: 'dim-accessScene', disabled: saving },
|
||||
h('legend', null, '群会话策略'),
|
||||
h('label', { className: 'dim-accessField' },
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ const EN = Object.freeze({
|
|||
'机器人设置页签': 'Bot settings tabs',
|
||||
'投递设置': 'Delivery settings',
|
||||
'访问设置': 'Access settings',
|
||||
"—": "—",
|
||||
"来源": "Source",
|
||||
"暂无管理员,可点下方新增。": "No admins yet. Add one below.",
|
||||
"暂无用户,可点下方新增。": "No users yet. Add one below.",
|
||||
"不可删除": "Locked",
|
||||
|
|
|
|||
|
|
@ -484,6 +484,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; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue