init
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* 神之一手(one_divine_lot)客户端插件
|
||||
*
|
||||
* 注册:
|
||||
* - conversation.view tabs:全部持仓 / 交易记录 / 关注列表(通用,按 tabConfig 显隐)+ 策略 tabs(按策略配置)
|
||||
* - settings.section:神之一手设置菜单(通用设置 + 策略分组)
|
||||
*
|
||||
* 迭代 02:
|
||||
* - O2 策略 tab 动态化:策略配置驱动注册
|
||||
* - 设置 tab 化扩展:三个通用 tab(全部持仓/交易记录/关注列表)由 tabConfig 控制显隐
|
||||
* - 刷新页面 = 插件重载 = 按最新配置重新注册(无事件机制)
|
||||
*/
|
||||
|
||||
import { createElement } from 'react';
|
||||
import { AllPositionsTab } from './views/AllPositionsTab.jsx';
|
||||
import { StrategyTab } from './views/StrategyTab.jsx';
|
||||
import { PlaceholderTab } from './views/PlaceholderTab.jsx';
|
||||
import { SettingsSection } from './views/SettingsSection.jsx';
|
||||
import { ConnectionProvider } from './views/connection.jsx';
|
||||
|
||||
export const inject = ['slots', 'connection'];
|
||||
|
||||
async function fetchStrategies() {
|
||||
try {
|
||||
const res = await fetch('/odl/api/strategies', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
const data = await res.json();
|
||||
return data && data.ok ? data.value : [];
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchTabConfig() {
|
||||
try {
|
||||
const res = await fetch('/odl/api/tabs', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({}),
|
||||
});
|
||||
const data = await res.json();
|
||||
if (data && data.ok) {
|
||||
return {
|
||||
allPositions: data.value.allPositions !== false,
|
||||
tradeRecords: data.value.tradeRecords !== false,
|
||||
watchlist: data.value.watchlist !== false,
|
||||
};
|
||||
}
|
||||
} catch (e) { /* ignore */ }
|
||||
return { allPositions: true, tradeRecords: true, watchlist: true };
|
||||
}
|
||||
|
||||
function strategyTabId(strategyId) {
|
||||
return 'odl-strategy-' + strategyId;
|
||||
}
|
||||
|
||||
const GENERAL_TABS = [
|
||||
{ key: 'allPositions', id: 'odl-all-positions', label: '全部持仓', order: 10,
|
||||
render: (withConnection) => withConnection((props) => createElement(AllPositionsTab, props)) },
|
||||
{ key: 'tradeRecords', id: 'odl-trade-records', label: '交易记录', order: 11,
|
||||
render: (withConnection) => withConnection((props) => createElement(PlaceholderTab, { ...props, title: '交易记录' })) },
|
||||
{ key: 'watchlist', id: 'odl-watchlist', label: '关注列表', order: 12,
|
||||
render: (withConnection) => withConnection((props) => createElement(PlaceholderTab, { ...props, title: '关注列表' })) },
|
||||
];
|
||||
|
||||
export function apply(ctx) {
|
||||
const connection = ctx.get('connection');
|
||||
if (!connection) {
|
||||
ctx.logger?.warn?.('[one-divine-lot] connection 服务不可用');
|
||||
}
|
||||
|
||||
const withConnection = (render) => (props) =>
|
||||
createElement(ConnectionProvider, { connection }, render(props));
|
||||
|
||||
ctx.slots.register({
|
||||
name: 'settings.section',
|
||||
id: 'one-divine-lot',
|
||||
order: 50,
|
||||
label: () => '神之一手',
|
||||
}, withConnection((props) => createElement(SettingsSection, props)));
|
||||
|
||||
let tabDisposers = [];
|
||||
let disposed = false;
|
||||
|
||||
const disposeAllTabs = () => {
|
||||
for (const d of tabDisposers) {
|
||||
try { d(); } catch (e) { /* ignore */ }
|
||||
}
|
||||
tabDisposers = [];
|
||||
};
|
||||
|
||||
const registerGeneralTabs = (tabConfig) => {
|
||||
for (const tab of GENERAL_TABS) {
|
||||
if (tabConfig[tab.key] === false) continue;
|
||||
const dispose = ctx.slots.register({
|
||||
name: 'conversation.view',
|
||||
id: tab.id,
|
||||
order: tab.order,
|
||||
label: () => tab.label,
|
||||
}, tab.render(withConnection));
|
||||
tabDisposers.push(dispose);
|
||||
}
|
||||
};
|
||||
|
||||
const registerStrategyTabs = (strategies) => {
|
||||
const visible = strategies.filter((s) => s.visible !== false);
|
||||
visible.forEach((s, idx) => {
|
||||
const dispose = ctx.slots.register({
|
||||
name: 'conversation.view',
|
||||
id: strategyTabId(s.id),
|
||||
order: 13 + idx,
|
||||
label: () => s.name,
|
||||
}, withConnection((props) => createElement(StrategyTab, { ...props, strategyId: s.id, strategyName: s.name })));
|
||||
tabDisposers.push(dispose);
|
||||
});
|
||||
return visible.length;
|
||||
};
|
||||
|
||||
const registerAllTabs = async () => {
|
||||
const [strategies, tabConfig] = await Promise.all([fetchStrategies(), fetchTabConfig()]);
|
||||
if (disposed) return;
|
||||
disposeAllTabs();
|
||||
registerGeneralTabs(tabConfig);
|
||||
const n = registerStrategyTabs(strategies);
|
||||
ctx.logger?.info?.('[one-divine-lot] 已注册通用 tabs + ' + n + ' 个策略 tab');
|
||||
};
|
||||
|
||||
registerAllTabs();
|
||||
|
||||
ctx.effect(() => {
|
||||
return () => {
|
||||
disposed = true;
|
||||
disposeAllTabs();
|
||||
};
|
||||
}, 'one-divine-lot.client');
|
||||
}
|
||||
Reference in New Issue
Block a user