1
This commit is contained in:
@@ -15,7 +15,6 @@
|
||||
| `device_monitor.js` | 设备状态管理 | `/admin_api/device` | 设备状态的查询、监控、配置 |
|
||||
| `chat_records.js` | 聊天记录管理 | `/admin_api/chat` | 聊天记录的查询、统计、删除 |
|
||||
| `task_status.js` | 任务状态管理 | `/admin_api/task` | 任务状态的查询、更新、删除 |
|
||||
| `system_config.js` | 系统配置管理 | `/admin_api/config` | 系统配置的CRUD操作 |
|
||||
| `dashboard.js` | 数据统计面板 | `/admin_api/dashboard` | 综合数据统计 |
|
||||
| `sys_user.js` | 系统用户管理 | `/admin_api/user` | 用户管理 |
|
||||
|
||||
@@ -158,26 +157,6 @@
|
||||
- ✅ 按类型和状态统计
|
||||
|
||||
---
|
||||
|
||||
### 8️⃣ 系统配置管理 (`system_config.js`)
|
||||
|
||||
**路由前缀**: `/admin_api/config`
|
||||
|
||||
| 接口 | 方法 | 说明 |
|
||||
|------|------|------|
|
||||
| `/list` | POST | 分页获取配置列表 |
|
||||
| `/get` | GET | 获取配置详情 |
|
||||
| `/add` | POST | 添加配置 |
|
||||
| `/update` | POST | 更新配置 |
|
||||
| `/delete` | POST | 删除配置 |
|
||||
| `/categories` | GET | 获取配置分类 |
|
||||
| `/reset` | POST | 重置配置为默认值 |
|
||||
| `/batch-update` | POST | 批量更新配置 |
|
||||
|
||||
**主要功能**:
|
||||
- ✅ 完整的 CRUD 操作
|
||||
- ✅ 支持多种配置类型(string/number/boolean/json)
|
||||
- ✅ 配置加密存储
|
||||
- ✅ 批量更新
|
||||
|
||||
---
|
||||
|
||||
@@ -1,498 +0,0 @@
|
||||
/**
|
||||
* 系统配置管理API - 后台管理
|
||||
* 提供系统配置的CRUD操作
|
||||
*/
|
||||
|
||||
const Framework = require("../../framework/node-core-framework.js");
|
||||
|
||||
const normalizeConfigValue = (config) => {
|
||||
if (!config) {
|
||||
return config;
|
||||
}
|
||||
|
||||
const normalized = { ...config };
|
||||
|
||||
if (normalized.configType === 'json' && normalized.configValue) {
|
||||
normalized.configValue = JSON.parse(normalized.configValue);
|
||||
} else if (normalized.configType === 'boolean') {
|
||||
normalized.configValue = normalized.configValue === 'true' || normalized.configValue === '1';
|
||||
} else if (normalized.configType === 'number') {
|
||||
normalized.configValue = parseFloat(normalized.configValue) || 0;
|
||||
}
|
||||
|
||||
return normalized;
|
||||
};
|
||||
|
||||
const formatConfigValueForSave = (configType, configValue) => {
|
||||
if (configType === 'json' && typeof configValue === 'object') {
|
||||
return JSON.stringify(configValue);
|
||||
}
|
||||
|
||||
if (configType === 'boolean') {
|
||||
return configValue ? 'true' : 'false';
|
||||
}
|
||||
|
||||
return String(configValue);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
* @swagger
|
||||
* /admin_api/config/list:
|
||||
* post:
|
||||
* summary: 获取配置列表
|
||||
* description: 分页获取系统配置列表
|
||||
* tags: [后台-系统配置]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* page:
|
||||
* type: integer
|
||||
* description: 页码
|
||||
* pageSize:
|
||||
* type: integer
|
||||
* description: 每页数量
|
||||
* category:
|
||||
* type: string
|
||||
* description: 配置分类(可选)
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 获取成功
|
||||
*/
|
||||
'POST /config/list': async (ctx) => {
|
||||
const models = Framework.getModels();
|
||||
const { system_config, op } = models;
|
||||
const body = ctx.getBody();
|
||||
const { category, searchText} = ctx.getBody();
|
||||
|
||||
// 获取分页参数
|
||||
const { limit, offset, page, pageSize } = ctx.getPageSize();
|
||||
|
||||
const where = {};
|
||||
if (category) where.category = category;
|
||||
|
||||
// 支持搜索配置键或名称
|
||||
if (searchText) {
|
||||
where[op.or] = [
|
||||
{ configKey: { [op.like]: `%${searchText}%` } },
|
||||
{ configName: { [op.like]: `%${searchText}%` } }
|
||||
];
|
||||
}
|
||||
|
||||
const result = await system_config.findAndCountAll({
|
||||
where,
|
||||
limit,
|
||||
offset,
|
||||
order: [
|
||||
['category', 'ASC'],
|
||||
['sortOrder', 'ASC'],
|
||||
['id', 'ASC']
|
||||
]
|
||||
});
|
||||
|
||||
const list = result.rows.map(item => normalizeConfigValue(item.toJSON()));
|
||||
|
||||
return ctx.success({
|
||||
total: result.count,
|
||||
page,
|
||||
pageSize,
|
||||
list
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /admin_api/config/get:
|
||||
* get:
|
||||
* summary: 获取配置详情
|
||||
* description: 根据配置键获取配置详情
|
||||
* tags: [后台-系统配置]
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: configKey
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* description: 配置键
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 获取成功
|
||||
*/
|
||||
'GET /config/get': async (ctx) => {
|
||||
const models = Framework.getModels();
|
||||
const { system_config } = models;
|
||||
const { configKey } = ctx.query;
|
||||
|
||||
if (!configKey) {
|
||||
return ctx.fail('配置键不能为空');
|
||||
}
|
||||
|
||||
const config = await system_config.findOne({ where: { configKey } });
|
||||
|
||||
if (!config) {
|
||||
return ctx.fail('配置不存在');
|
||||
}
|
||||
|
||||
const configData = normalizeConfigValue(config.toJSON());
|
||||
|
||||
return ctx.success(configData);
|
||||
},
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /admin_api/config/add:
|
||||
* post:
|
||||
* summary: 添加配置
|
||||
* description: 添加新的系统配置
|
||||
* tags: [后台-系统配置]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - configKey
|
||||
* - configValue
|
||||
* - category
|
||||
* properties:
|
||||
* configKey:
|
||||
* type: string
|
||||
* description: 配置键
|
||||
* configValue:
|
||||
* type: string
|
||||
* description: 配置值
|
||||
* configType:
|
||||
* type: string
|
||||
* description: 配置类型
|
||||
* category:
|
||||
* type: string
|
||||
* description: 配置分类
|
||||
* configName:
|
||||
* type: string
|
||||
* description: 配置名称
|
||||
* description:
|
||||
* type: string
|
||||
* description: 配置描述
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 添加成功
|
||||
*/
|
||||
'POST /config/add': async (ctx) => {
|
||||
const models = Framework.getModels();
|
||||
const { system_config } = models;
|
||||
const body = ctx.getBody();
|
||||
const {
|
||||
configKey,
|
||||
configValue,
|
||||
configType = 'string',
|
||||
category,
|
||||
configName,
|
||||
description,
|
||||
defaultValue,
|
||||
sortOrder = 0,
|
||||
isActive = true,
|
||||
isSystem = false
|
||||
} = body;
|
||||
|
||||
if (!configKey || configValue === undefined || !category) {
|
||||
return ctx.fail('配置键、配置值和分类不能为空');
|
||||
}
|
||||
|
||||
const existingConfig = await system_config.findOne({ where: { configKey } });
|
||||
|
||||
if (existingConfig) {
|
||||
return ctx.fail('配置键已存在');
|
||||
}
|
||||
|
||||
const finalValue = formatConfigValueForSave(configType, configValue);
|
||||
|
||||
await system_config.create({
|
||||
configKey,
|
||||
configValue: finalValue,
|
||||
configType,
|
||||
category,
|
||||
configName: configName || configKey,
|
||||
description: description || '',
|
||||
defaultValue: defaultValue || finalValue,
|
||||
sortOrder,
|
||||
isActive,
|
||||
isSystem,
|
||||
isVisible: true,
|
||||
});
|
||||
|
||||
return ctx.success({ message: '配置添加成功' });
|
||||
},
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /admin_api/config/update:
|
||||
* post:
|
||||
* summary: 更新配置
|
||||
* description: 更新系统配置
|
||||
* tags: [后台-系统配置]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - configKey
|
||||
* properties:
|
||||
* configKey:
|
||||
* type: string
|
||||
* description: 配置键
|
||||
* configValue:
|
||||
* type: string
|
||||
* description: 配置值
|
||||
* description:
|
||||
* type: string
|
||||
* description: 配置描述
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 更新成功
|
||||
*/
|
||||
'POST /config/update': async (ctx) => {
|
||||
const models = Framework.getModels();
|
||||
const { system_config } = models;
|
||||
const body = ctx.getBody();
|
||||
const {
|
||||
configKey,
|
||||
configValue,
|
||||
configName,
|
||||
description,
|
||||
sortOrder,
|
||||
isActive
|
||||
} = body;
|
||||
|
||||
if (!configKey) {
|
||||
return ctx.fail('配置键不能为空');
|
||||
}
|
||||
|
||||
const config = await system_config.findOne({ where: { configKey } });
|
||||
|
||||
if (!config) {
|
||||
return ctx.fail('配置不存在');
|
||||
}
|
||||
|
||||
const updateData = {};
|
||||
|
||||
if (configValue !== undefined) {
|
||||
updateData.configValue = formatConfigValueForSave(config.configType, configValue);
|
||||
}
|
||||
|
||||
if (configName) updateData.configName = configName;
|
||||
if (description) updateData.description = description;
|
||||
if (sortOrder !== undefined) updateData.sortOrder = sortOrder;
|
||||
if (isActive !== undefined) updateData.isActive = isActive;
|
||||
|
||||
await system_config.update(updateData, { where: { configKey } });
|
||||
|
||||
return ctx.success({ message: '配置更新成功' });
|
||||
},
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /admin_api/config/delete:
|
||||
* post:
|
||||
* summary: 删除配置
|
||||
* description: 删除系统配置(系统配置不可删除)
|
||||
* tags: [后台-系统配置]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - configKey
|
||||
* properties:
|
||||
* configKey:
|
||||
* type: string
|
||||
* description: 配置键
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 删除成功
|
||||
*/
|
||||
'POST /config/delete': async (ctx) => {
|
||||
const models = Framework.getModels();
|
||||
const { system_config } = models;
|
||||
const body = ctx.getBody();
|
||||
const { configKey } = body;
|
||||
|
||||
if (!configKey) {
|
||||
return ctx.fail('配置键不能为空');
|
||||
}
|
||||
|
||||
|
||||
const config = await system_config.findOne({ where: { configKey } });
|
||||
|
||||
if (!config) {
|
||||
return ctx.fail('配置不存在');
|
||||
}
|
||||
|
||||
if (config.isSystem) {
|
||||
return ctx.fail('系统配置不可删除');
|
||||
}
|
||||
|
||||
await system_config.destroy({ where: { configKey } });
|
||||
|
||||
return ctx.success({ message: '配置删除成功' });
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /admin_api/config/categories:
|
||||
* get:
|
||||
* summary: 获取配置分类列表
|
||||
* description: 获取所有配置分类
|
||||
* tags: [后台-系统配置]
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 获取成功
|
||||
*/
|
||||
'GET /config/categories': async (ctx) => {
|
||||
const models = Framework.getModels();
|
||||
const { system_config } = models;
|
||||
|
||||
|
||||
const categories = await system_config.findAll({
|
||||
attributes: [
|
||||
'category',
|
||||
[models.sequelize.fn('COUNT', models.sequelize.col('*')), 'count']
|
||||
],
|
||||
group: ['category'],
|
||||
raw: true
|
||||
});
|
||||
|
||||
return ctx.success(categories);
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /admin_api/config/reset:
|
||||
* post:
|
||||
* summary: 重置配置为默认值
|
||||
* description: 将配置重置为默认值
|
||||
* tags: [后台-系统配置]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - configKey
|
||||
* properties:
|
||||
* configKey:
|
||||
* type: string
|
||||
* description: 配置键
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 重置成功
|
||||
*/
|
||||
'POST /config/reset': async (ctx) => {
|
||||
const models = Framework.getModels();
|
||||
const { system_config } = models;
|
||||
const body = ctx.getBody();
|
||||
const { configKey } = body;
|
||||
|
||||
if (!configKey) {
|
||||
return ctx.fail('配置键不能为空');
|
||||
}
|
||||
|
||||
|
||||
const config = await system_config.findOne({ where: { configKey } });
|
||||
|
||||
if (!config) {
|
||||
return ctx.fail('配置不存在');
|
||||
}
|
||||
|
||||
if (!config.defaultValue) {
|
||||
return ctx.fail('该配置没有默认值');
|
||||
}
|
||||
|
||||
await system_config.update({
|
||||
configValue: config.defaultValue,
|
||||
}, { where: { configKey } });
|
||||
|
||||
return ctx.success({ message: '配置已重置为默认值' });
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /admin_api/config/batch-update:
|
||||
* post:
|
||||
* summary: 批量更新配置
|
||||
* description: 批量更新多个配置
|
||||
* tags: [后台-系统配置]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - configs
|
||||
* properties:
|
||||
* configs:
|
||||
* type: array
|
||||
* description: 配置数组
|
||||
* responses:
|
||||
* 200:
|
||||
* description: 更新成功
|
||||
*/
|
||||
'POST /config/batch-update': async (ctx) => {
|
||||
const models = Framework.getModels();
|
||||
const { system_config } = models;
|
||||
const body = ctx.getBody();
|
||||
const { configs } = body;
|
||||
|
||||
if (!configs || !Array.isArray(configs) || configs.length === 0) {
|
||||
return ctx.fail('配置数组不能为空');
|
||||
}
|
||||
|
||||
let successCount = 0;
|
||||
let failedCount = 0;
|
||||
|
||||
for (const item of configs) {
|
||||
const { configKey, configValue } = item;
|
||||
|
||||
if (!configKey || configValue === undefined) {
|
||||
failedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const config = await system_config.findOne({ where: { configKey } });
|
||||
|
||||
if (!config) {
|
||||
failedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const finalValue = formatConfigValueForSave(config.configType, configValue);
|
||||
|
||||
await system_config.update({
|
||||
configValue: finalValue,
|
||||
}, { where: { configKey } });
|
||||
|
||||
successCount++;
|
||||
}
|
||||
|
||||
return ctx.success({
|
||||
message: '批量更新完成',
|
||||
total: configs.length,
|
||||
success: successCount,
|
||||
failed: failedCount
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,27 +5,7 @@
|
||||
|
||||
const Framework = require("../../framework/node-core-framework.js");
|
||||
|
||||
const normalizeConfigValue = (config) => {
|
||||
if (!config) {
|
||||
return config;
|
||||
}
|
||||
|
||||
const normalized = { ...config };
|
||||
|
||||
if (normalized.configType === 'json' && normalized.configValue) {
|
||||
try {
|
||||
normalized.configValue = JSON.parse(normalized.configValue);
|
||||
} catch (e) {
|
||||
// 解析失败,保持原值
|
||||
}
|
||||
} else if (normalized.configType === 'boolean') {
|
||||
normalized.configValue = normalized.configValue === 'true' || normalized.configValue === '1';
|
||||
} else if (normalized.configType === 'number') {
|
||||
normalized.configValue = parseFloat(normalized.configValue) || 0;
|
||||
}
|
||||
|
||||
return normalized;
|
||||
};
|
||||
// sys_parameter 表直接存储字符串值,不需要类型转换
|
||||
|
||||
module.exports = {
|
||||
/**
|
||||
@@ -55,7 +35,7 @@ module.exports = {
|
||||
'GET /config/get': async (ctx) => {
|
||||
try {
|
||||
const models = await Framework.getModels();
|
||||
const { system_config, op } = models;
|
||||
const { sys_parameter, op } = models;
|
||||
const { configKey, configKeys } = ctx.query;
|
||||
|
||||
// 如果没有提供配置键,返回失败
|
||||
@@ -75,10 +55,10 @@ module.exports = {
|
||||
return ctx.fail('配置键不能为空');
|
||||
}
|
||||
|
||||
// 查询配置
|
||||
const configs = await system_config.findAll({
|
||||
// 查询配置(使用 sys_parameter 表)
|
||||
const configs = await sys_parameter.findAll({
|
||||
where: {
|
||||
configKey: {
|
||||
param_key: {
|
||||
[op.in]: keys
|
||||
},
|
||||
is_delete: 0
|
||||
@@ -91,17 +71,17 @@ module.exports = {
|
||||
|
||||
// 如果只有一个配置键,返回单个配置值
|
||||
if (keys.length === 1) {
|
||||
const config = normalizeConfigValue(configs[0].toJSON());
|
||||
const config = configs[0].toJSON();
|
||||
return ctx.success({
|
||||
[config.configKey]: config.configValue
|
||||
[config.param_key]: config.param_value
|
||||
});
|
||||
}
|
||||
|
||||
// 多个配置键,返回对象
|
||||
const result = {};
|
||||
configs.forEach(config => {
|
||||
const normalized = normalizeConfigValue(config.toJSON());
|
||||
result[normalized.configKey] = normalized.configValue;
|
||||
const configData = config.toJSON();
|
||||
result[configData.param_key] = configData.param_value;
|
||||
});
|
||||
|
||||
return ctx.success(result);
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
const Sequelize = require('sequelize');
|
||||
|
||||
/**
|
||||
* 系统配置表模型
|
||||
* 存储系统的各种配置参数
|
||||
*/
|
||||
module.exports = (db) => {
|
||||
const system_config= db.define("system_config", {
|
||||
// 配置基本信息
|
||||
configKey: {
|
||||
comment: '配置键(唯一)',
|
||||
type: Sequelize.STRING(100),
|
||||
allowNull: false,
|
||||
unique: true
|
||||
},
|
||||
configValue: {
|
||||
comment: '配置值',
|
||||
type: Sequelize.TEXT,
|
||||
allowNull: true,
|
||||
defaultValue: ''
|
||||
},
|
||||
configType: {
|
||||
comment: '配置类型: string-字符串, number-数字, boolean-布尔, json-JSON对象',
|
||||
type: Sequelize.STRING(20),
|
||||
allowNull: false,
|
||||
defaultValue: 'string'
|
||||
},
|
||||
|
||||
// 分类信息
|
||||
category: {
|
||||
comment: '配置分类: system-系统, ai-AI服务, mqtt-MQTT, schedule-调度, platform-平台',
|
||||
type: Sequelize.STRING(50),
|
||||
allowNull: false,
|
||||
defaultValue: 'system'
|
||||
},
|
||||
|
||||
// 描述信息
|
||||
configName: {
|
||||
comment: '配置名称',
|
||||
type: Sequelize.STRING(200),
|
||||
allowNull: true,
|
||||
defaultValue: ''
|
||||
},
|
||||
description: {
|
||||
comment: '配置描述',
|
||||
type: Sequelize.TEXT,
|
||||
allowNull: true,
|
||||
defaultValue: ''
|
||||
},
|
||||
|
||||
// 默认值
|
||||
defaultValue: {
|
||||
comment: '默认值',
|
||||
type: Sequelize.TEXT,
|
||||
allowNull: true,
|
||||
defaultValue: ''
|
||||
},
|
||||
|
||||
// 验证规则
|
||||
validationRule: {
|
||||
comment: '验证规则(JSON)',
|
||||
type: Sequelize.TEXT,
|
||||
allowNull: true,
|
||||
defaultValue: ''
|
||||
},
|
||||
|
||||
// 状态信息
|
||||
isActive: {
|
||||
comment: '是否启用',
|
||||
type: Sequelize.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
},
|
||||
isSystem: {
|
||||
comment: '是否系统配置(系统配置不可删除)',
|
||||
type: Sequelize.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false
|
||||
},
|
||||
isEncrypted: {
|
||||
comment: '是否加密存储',
|
||||
type: Sequelize.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: false
|
||||
},
|
||||
|
||||
// 排序和显示
|
||||
sortOrder: {
|
||||
comment: '排序顺序',
|
||||
type: Sequelize.INTEGER,
|
||||
allowNull: true,
|
||||
defaultValue: 0
|
||||
},
|
||||
isVisible: {
|
||||
comment: '是否在界面显示',
|
||||
type: Sequelize.BOOLEAN,
|
||||
allowNull: false,
|
||||
defaultValue: true
|
||||
},
|
||||
|
||||
|
||||
}, {
|
||||
timestamps: false,
|
||||
indexes: [
|
||||
{
|
||||
unique: true,
|
||||
fields: ['configKey']
|
||||
},
|
||||
{
|
||||
unique: false,
|
||||
fields: ['category']
|
||||
},
|
||||
{
|
||||
unique: false,
|
||||
fields: ['isActive']
|
||||
},
|
||||
{
|
||||
unique: false,
|
||||
fields: ['sortOrder']
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
// system_config.sync({ force: true });
|
||||
|
||||
return system_config
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user