mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-08-19 08:50:58 +00:00
feat: system.json 的可视化编辑
This commit is contained in:
@@ -44,7 +44,11 @@ class SettingsRouterGroup(group.RouterGroup):
|
|||||||
async def _(manager_name: str) -> str:
|
async def _(manager_name: str) -> str:
|
||||||
data = await quart.request.json
|
data = await quart.request.json
|
||||||
manager = self.ap.settings_mgr.get_manager(manager_name)
|
manager = self.ap.settings_mgr.get_manager(manager_name)
|
||||||
manager.data = data['data']
|
# manager.data = data['data']
|
||||||
|
for k, v in data['data'].items():
|
||||||
|
manager.data[k] = v
|
||||||
|
|
||||||
|
await manager.dump_config()
|
||||||
return self.success(data={
|
return self.success(data={
|
||||||
"data": manager.data
|
"data": manager.data
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ class LoadConfigStage(stage.BootingStage):
|
|||||||
ap.settings_mgr.register_manager(
|
ap.settings_mgr.register_manager(
|
||||||
name="pipeline.json",
|
name="pipeline.json",
|
||||||
description="消息处理流水线配置",
|
description="消息处理流水线配置",
|
||||||
manager=ap.pipeline_cfg
|
manager=ap.pipeline_cfg,
|
||||||
|
schema=schema.CONFIG_PIPELINE_SCHEMA
|
||||||
)
|
)
|
||||||
|
|
||||||
ap.settings_mgr.register_manager(
|
ap.settings_mgr.register_manager(
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ def load_schema(schema_path: str) -> dict:
|
|||||||
|
|
||||||
|
|
||||||
CONFIG_SYSTEM_SCHEMA = load_schema("templates/schema/system.json")
|
CONFIG_SYSTEM_SCHEMA = load_schema("templates/schema/system.json")
|
||||||
|
CONFIG_PIPELINE_SCHEMA = load_schema("templates/schema/pipeline.json")
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"layout": "expansion-panels",
|
||||||
|
"properties": {
|
||||||
|
"access-control": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "访问控制",
|
||||||
|
"properties": {
|
||||||
|
"mode": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "访问控制模式",
|
||||||
|
"description": "访问控制模式,支持黑名单和白名单",
|
||||||
|
"enum": ["blacklist", "whitelist"]
|
||||||
|
},
|
||||||
|
"blacklist": {
|
||||||
|
"type": "array",
|
||||||
|
"title": "黑名单",
|
||||||
|
"description": "黑名单中的会话将无法使用机器人,仅在访问控制模式为黑名单时有效",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "regex",
|
||||||
|
"pattern": "^(person|group)_(\\d)*$"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"whitelist": {
|
||||||
|
"type": "array",
|
||||||
|
"title": "白名单",
|
||||||
|
"description": "仅白名单中的会话可以使用机器人,仅在访问控制模式为白名单时有效",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "regex",
|
||||||
|
"pattern": "^(person|group)_(\\d)*$"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["mode"]
|
||||||
|
},
|
||||||
|
"respond-rules": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "群内响应规则",
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "默认响应规则",
|
||||||
|
"properties": {
|
||||||
|
"at": {
|
||||||
|
"type": "boolean",
|
||||||
|
"title": "是否响应 @ 消息",
|
||||||
|
"layout": {
|
||||||
|
"comp": "switch",
|
||||||
|
"props": {
|
||||||
|
"color": "primary"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"prefix": {
|
||||||
|
"type": "array",
|
||||||
|
"title": "前缀响应",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"regexp": {
|
||||||
|
"type": "array",
|
||||||
|
"title": "正则表达式响应",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "regex"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"random": {
|
||||||
|
"type": "number",
|
||||||
|
"title": "随机响应概率",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 1,
|
||||||
|
"step": 0.01,
|
||||||
|
"layout": {
|
||||||
|
"comp": "slider",
|
||||||
|
"props": {
|
||||||
|
"color": "primary"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patternProperties": {
|
||||||
|
"^(person|group).*$": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"at": {
|
||||||
|
"type": "boolean",
|
||||||
|
"title": "是否响应 @ 消息",
|
||||||
|
"layout": {
|
||||||
|
"comp": "switch",
|
||||||
|
"props": {
|
||||||
|
"color": "primary"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"prefix": {
|
||||||
|
"type": "array",
|
||||||
|
"title": "前缀响应",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"regexp": {
|
||||||
|
"type": "array",
|
||||||
|
"title": "正则表达式响应",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "regex"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"random": {
|
||||||
|
"type": "number",
|
||||||
|
"title": "随机响应概率",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 1,
|
||||||
|
"step": 0.01,
|
||||||
|
"layout": {
|
||||||
|
"comp": "slider",
|
||||||
|
"props": {
|
||||||
|
"color": "primary"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+104
-72
@@ -1,80 +1,112 @@
|
|||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
"layout": "expansion-panels",
|
||||||
"properties": {
|
"properties": {
|
||||||
"admin-sessions": {
|
"admin-sessions": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"title": "管理员会话",
|
||||||
"type": "string"
|
"description": "",
|
||||||
}
|
"items": {
|
||||||
},
|
"type": "string",
|
||||||
"network-proxies": {
|
"format": "regex",
|
||||||
"type": "object",
|
"pattern": "^(person|group)_(\\d)*$"
|
||||||
"properties": {
|
}
|
||||||
"http": {
|
},
|
||||||
"type": "string"
|
"network-proxies": {
|
||||||
},
|
"type": "object",
|
||||||
"https": {
|
"title": "网络代理",
|
||||||
"type": "string"
|
"properties": {
|
||||||
}
|
"http": {
|
||||||
}
|
|
||||||
},
|
|
||||||
"report-usage": {
|
|
||||||
"type": "boolean"
|
|
||||||
},
|
|
||||||
"logging-level": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"session-concurrency": {
|
"https": {
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"default": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"patternProperties": {
|
|
||||||
"^(person|group).*$": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pipeline-concurrency": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"qcg-center-url": {
|
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
}
|
||||||
"help-message": {
|
}
|
||||||
"type": "string"
|
},
|
||||||
},
|
"report-usage": {
|
||||||
"http-api": {
|
"type": "boolean",
|
||||||
"type": "object",
|
"title": "是否上报遥测数据",
|
||||||
"properties": {
|
"layout": {
|
||||||
"enable": {
|
"comp": "switch",
|
||||||
"type": "boolean"
|
"props": {
|
||||||
},
|
"color": "primary"
|
||||||
"host": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"port": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"persistence": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"sqlite": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"path": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"use": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"logging-level": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "日志等级"
|
||||||
|
},
|
||||||
|
"session-concurrency": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "会话并行消息数",
|
||||||
|
"properties": {
|
||||||
|
"default": {
|
||||||
|
"type": "integer",
|
||||||
|
"title": "会话默认并行消息数"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"patternProperties": {
|
||||||
|
"^(person|group).*$": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"pipeline-concurrency": {
|
||||||
|
"type": "integer",
|
||||||
|
"title": "全局并行消息数"
|
||||||
|
},
|
||||||
|
"qcg-center-url": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "遥测服务器地址"
|
||||||
|
},
|
||||||
|
"help-message": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "help 命令消息",
|
||||||
|
"layout": "textarea"
|
||||||
|
},
|
||||||
|
"http-api": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "HTTP 接口",
|
||||||
|
"properties": {
|
||||||
|
"enable": {
|
||||||
|
"type": "boolean",
|
||||||
|
"layout": {
|
||||||
|
"comp": "switch",
|
||||||
|
"props": {
|
||||||
|
"color": "primary"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "是否启用"
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"persistence": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "持久化设置",
|
||||||
|
"properties": {
|
||||||
|
"sqlite": {
|
||||||
|
"type": "object",
|
||||||
|
"title": "sqlite",
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"use": {
|
||||||
|
"type": "string",
|
||||||
|
"title": "所使用的数据库",
|
||||||
|
"enum": ["sqlite"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+77
-12
@@ -18,12 +18,12 @@
|
|||||||
<v-tooltip :text="currentManagerSchema == null ? '仅配置文件管理器提供了 JSON Schema 时支持可视化配置' : '切换编辑模式'" location="top">
|
<v-tooltip :text="currentManagerSchema == null ? '仅配置文件管理器提供了 JSON Schema 时支持可视化配置' : '切换编辑模式'" location="top">
|
||||||
<template v-slot:activator="{ props }">
|
<template v-slot:activator="{ props }">
|
||||||
|
|
||||||
<v-btn-toggle id="config-type-toggle" color="primary" v-model="configType" mandatory v-bind="props">
|
<v-btn-toggle id="config-type-toggle" color="primary" v-model="configType" mandatory v-bind="props" density="compact">
|
||||||
|
|
||||||
<v-btn class="config-type-toggle-btn" value="ui" :readonly="currentManagerSchema == null">
|
<v-btn class="config-type-toggle-btn" value="ui" :readonly="currentManagerSchema == null" density="compact">
|
||||||
<v-icon>mdi-view-dashboard-edit-outline</v-icon>
|
<v-icon>mdi-view-dashboard-edit-outline</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-btn class="config-type-toggle-btn" value="json" :readonly="currentManagerSchema == null">
|
<v-btn class="config-type-toggle-btn" value="json" :readonly="currentManagerSchema == null" density="compact">
|
||||||
<v-icon>mdi-code-json</v-icon>
|
<v-icon>mdi-code-json</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</v-btn-toggle>
|
</v-btn-toggle>
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
<div id="config-tab-content-ui" v-if="configType == 'ui'">
|
<div id="config-tab-content-ui" v-if="configType == 'ui'">
|
||||||
<v-form id="config-tab-content-ui-form">
|
<v-form id="config-tab-content-ui-form">
|
||||||
<vjsf id="config-tab-content-ui-form-vjsf" :schema="currentManagerSchema" v-model="currentManagerData" :options="{}" />
|
<vjsf id="config-tab-content-ui-form-vjsf" :schema="currentManagerSchema" v-model="currentManagerData" :options="VJSFOptions" />
|
||||||
</v-form>
|
</v-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -71,18 +71,84 @@ const currentManagerDataEditorString = ref('')
|
|||||||
const currentManagerSchema = ref(null)
|
const currentManagerSchema = ref(null)
|
||||||
const modified = ref(false)
|
const modified = ref(false)
|
||||||
|
|
||||||
|
const VJSFOptions = {
|
||||||
|
"context": {},
|
||||||
|
"width": 1208,
|
||||||
|
"readOnly": false,
|
||||||
|
"summary": false,
|
||||||
|
"density": "comfortable",
|
||||||
|
"indent": true,
|
||||||
|
"titleDepth": 4,
|
||||||
|
"validateOn": "input",
|
||||||
|
"initialValidation": "withData",
|
||||||
|
"updateOn": "input",
|
||||||
|
"debounceInputMs": 300,
|
||||||
|
"defaultOn": "empty",
|
||||||
|
"removeAdditional": "error",
|
||||||
|
"autofocus": false,
|
||||||
|
"readOnlyPropertiesMode": "show",
|
||||||
|
"pluginsOptions": {},
|
||||||
|
"locale": "en",
|
||||||
|
"messages": {
|
||||||
|
"errorOneOf": "请选择一个",
|
||||||
|
"errorRequired": "必填信息",
|
||||||
|
"addItem": "添加",
|
||||||
|
"delete": "删除",
|
||||||
|
"edit": "编辑",
|
||||||
|
"close": "关闭",
|
||||||
|
"duplicate": "复制",
|
||||||
|
"sort": "排序",
|
||||||
|
"up": "向上移动",
|
||||||
|
"down": "向下移动",
|
||||||
|
"showHelp": "显示帮助信息",
|
||||||
|
"mdeLink1": "[链接标题",
|
||||||
|
"mdeLink2": "](链接地址)",
|
||||||
|
"mdeImg1": "",
|
||||||
|
"mdeTable1": "",
|
||||||
|
"mdeTable2": "\n\n| 列 1 | 列 2 | 列 3 |\n| -------- | -------- | -------- |\n| 文本 | 文本 | 文本 |\n\n",
|
||||||
|
"bold": "加粗",
|
||||||
|
"italic": "斜体",
|
||||||
|
"heading": "标题",
|
||||||
|
"quote": "引用",
|
||||||
|
"unorderedList": "无序列表",
|
||||||
|
"orderedList": "有序列表",
|
||||||
|
"createLink": "创建链接",
|
||||||
|
"insertImage": "插入图片",
|
||||||
|
"createTable": "创建表格",
|
||||||
|
"preview": "预览",
|
||||||
|
"mdeGuide": "文档",
|
||||||
|
"undo": "撤销",
|
||||||
|
"redo": "重做"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const refresh = () => {
|
const refresh = () => {
|
||||||
proxy.$axios.get('/settings').then(response => {
|
proxy.$axios.get('/settings').then(response => {
|
||||||
managerList.value = response.data.data.managers
|
managerList.value = response.data.data.managers
|
||||||
|
|
||||||
if (proxy.$store.state.settingsPageTab != '') {
|
if (proxy.$store.state.settingsPageTab != '') {
|
||||||
fetchCurrentManagerData(proxy.$store.state.settingsPageTab)
|
fetchCurrentManagerData(proxy.$store.state.settingsPageTab)
|
||||||
|
} else {
|
||||||
|
proxy.$store.state.settingsPageTab = managerList.value[0].name
|
||||||
|
fetchCurrentManagerData(proxy.$store.state.settingsPageTab)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
firstJumpEditorAfterChangeTab()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const onTabChange = (tab) => {
|
const onTabChange = (tab) => {
|
||||||
fetchCurrentManagerData(tab)
|
fetchCurrentManagerData(tab)
|
||||||
|
firstJumpEditorAfterChangeTab()
|
||||||
|
}
|
||||||
|
|
||||||
|
const firstJumpEditorAfterChangeTab = () => {
|
||||||
|
if (currentManagerSchema.value != null) {
|
||||||
|
configType.value = 'ui'
|
||||||
|
} else {
|
||||||
|
configType.value = 'json'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchCurrentManagerData = (tab) => {
|
const fetchCurrentManagerData = (tab) => {
|
||||||
@@ -91,11 +157,6 @@ const fetchCurrentManagerData = (tab) => {
|
|||||||
currentManagerData.value = currentManager.value.data
|
currentManagerData.value = currentManager.value.data
|
||||||
currentManagerDataEditorString.value = JSON.stringify(currentManager.value.data, null, 2)
|
currentManagerDataEditorString.value = JSON.stringify(currentManager.value.data, null, 2)
|
||||||
currentManagerSchema.value = currentManager.value.schema
|
currentManagerSchema.value = currentManager.value.schema
|
||||||
if (currentManagerSchema.value != null) {
|
|
||||||
configType.value = 'ui'
|
|
||||||
} else {
|
|
||||||
configType.value = 'json'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +178,11 @@ const saveAndApply = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
currentManagerData.value = JSON.stringify(currentManager.value.data, null, 2)
|
if (configType.value == 'json') {
|
||||||
|
currentManagerData.value = JSON.stringify(currentManager.value.data, null, 2)
|
||||||
|
} else {
|
||||||
|
fetchCurrentManagerData(currentManager.value.name)
|
||||||
|
}
|
||||||
modified.value = false
|
modified.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +220,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
.config-tab-toolbar {
|
.config-tab-toolbar {
|
||||||
margin: 0.5rem;
|
margin: 0.5rem;
|
||||||
height: 4rem;
|
height: 3.2rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -202,7 +267,7 @@ onMounted(async () => {
|
|||||||
|
|
||||||
#config-tab-content-ui-form-vjsf {
|
#config-tab-content-ui-form-vjsf {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: calc(100% - 1.2rem);
|
width: calc(100% - 1rem);
|
||||||
}
|
}
|
||||||
|
|
||||||
#config-tab-content-json {
|
#config-tab-content-json {
|
||||||
|
|||||||
Reference in New Issue
Block a user