dsh-im-ops/plugin-src/client/index.js
2026-08-15 16:24:20 +08:00

106 lines
4 KiB
JavaScript

import * as React from 'react';
import { DingtalkLogoGlyph, FeishuLogoGlyph, WeixinLogoGlyph } from './channel-logos.js';
import { DINGTALK_RPC_CHANNEL } from './channels/dingtalk/api.js';
import { DingtalkSettingsTab } from './channels/dingtalk/index.js';
import { FeishuSettingsTab } from './channels/feishu/index.js';
import { FEISHU_RPC_CHANNEL } from './channels/feishu/api.js';
import { installFeishuStyles } from './channels/feishu/styles.js';
import { WeixinSettingsTab } from './channels/weixin/index.js';
import { WEIXIN_RPC_CHANNEL } from './channels/weixin/api.js';
import { installWeixinStyles } from './channels/weixin/styles.js';
import { installImStyles } from './styles.js';
const h = React.createElement;
export const name = 'im-settings';
export const inject = ['slots', 'connection'];
const CHANNELS = Object.freeze([
{ id: 'weixin', label: '微信' },
{ id: 'feishu', label: '飞书' },
{ id: 'dingtalk', label: '钉钉' },
]);
function WeixinLogo() {
return h('span', { className: 'dim-logo dim-logoWeixin', 'aria-hidden': 'true' },
h(WeixinLogoGlyph));
}
function FeishuLogo() {
return h('span', { className: 'dim-logo dim-logoFeishu', 'aria-hidden': 'true' },
h(FeishuLogoGlyph));
}
function DingtalkLogo() {
return h('span', { className: 'dim-logo dim-logoDingtalk', 'aria-hidden': 'true' },
h(DingtalkLogoGlyph));
}
function ChannelLogo({ channel }) {
if (channel === 'weixin') return h(WeixinLogo);
if (channel === 'feishu') return h(FeishuLogo);
return h(DingtalkLogo);
}
export function IMSettingsTab({ dingtalkRpcCall, feishuRpcCall, weixinRpcCall }) {
const [selected, setSelected] = React.useState('weixin');
const active = CHANNELS.find((channel) => channel.id === selected) ?? CHANNELS[0];
return h('section', { className: 'dim-page', 'aria-label': 'IM机器人设置' },
h('header', { className: 'dim-title' },
h('p', null, '通过扫码把机器人接入 DeepSeek Harness'),
),
h('div', { className: 'dim-layout' },
h('nav', { className: 'dim-rail', role: 'tablist', 'aria-label': 'IM 渠道' },
CHANNELS.map((channel) => h('button', {
key: channel.id,
type: 'button',
role: 'tab',
id: `dim-tab-${channel.id}`,
className: 'dim-channel',
'aria-selected': channel.id === active.id,
'aria-controls': `dim-panel-${channel.id}`,
onClick: () => setSelected(channel.id),
},
h(ChannelLogo, { channel: channel.id }),
h('span', { className: 'dim-channelCopy' },
h('strong', null, channel.label),
)))),
h('div', { className: 'dim-divider', 'aria-hidden': 'true' }),
h('main', {
className: 'dim-panel',
role: 'tabpanel',
id: `dim-panel-${active.id}`,
'aria-labelledby': `dim-tab-${active.id}`,
}, active.id === 'weixin'
? h(WeixinSettingsTab, { rpcCall: weixinRpcCall })
: active.id === 'feishu'
? h(FeishuSettingsTab, { rpcCall: feishuRpcCall })
: h(DingtalkSettingsTab, { rpcCall: dingtalkRpcCall })),
),
);
}
export function apply(ctx) {
ctx.effect(() => {
const disposers = [installFeishuStyles(), installWeixinStyles(), installImStyles()];
return () => {
for (const dispose of disposers.reverse()) dispose();
};
}, 'im-settings: install combined channel styles');
const feishuRpcCall = (endpoint, payload, signal) =>
ctx.connection.rpc.call(FEISHU_RPC_CHANNEL, endpoint, payload, signal);
const weixinRpcCall = (endpoint, payload, signal) =>
ctx.connection.rpc.call(WEIXIN_RPC_CHANNEL, endpoint, payload, signal);
const dingtalkRpcCall = (endpoint, payload, signal) =>
ctx.connection.rpc.call(DINGTALK_RPC_CHANNEL, endpoint, payload, signal);
ctx.slots.inject('settings.plugins.tab', () => ctx.slots.register({
name: 'settings.plugins.tab',
id: 'im',
order: 20,
label: 'IM机器人',
inject: () => ({ dingtalkRpcCall, feishuRpcCall, weixinRpcCall }),
}, IMSettingsTab));
}