7 Commits

12 changed files with 586 additions and 38 deletions

View File

@@ -7,6 +7,7 @@ use Workerman\Protocols\Http\Response;
require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/vendor/autoload.php';
use EdgeManager\EDataCapture\{ EDataCapture, ENodeConfigure }; use EdgeManager\EDataCapture\{ EDataCapture, ENodeConfigure };
use EdgeManager\EController\EConfigure;
$options = getopt('h::', ['no_dup_code', 'server_name:', 'port::', 'user:', 'password:', 'help::']); $options = getopt('h::', ['no_dup_code', 'server_name:', 'port::', 'user:', 'password:', 'help::']);
@@ -109,6 +110,47 @@ $worker -> onMessage = function(TcpConnection $connection, Request $request) {
))); )));
} }
} }
} else if (
str_ends_with($post -> action, 'server')
or str_ends_with($post -> action, 'device')
) {
$action = $post -> action;
unset($post -> action);
if ($action === 'add_server') {
$task_connection = new AsyncTcpConnection('Text://127.0.0.1:1888');
$task_data = array(
'action' => 'add_server',
'data' => $post,
);
$task_connection -> send(json_encode($task_data));
$task_connection -> onMessage = function(AsyncTcpConnection $task_connection, $task_result) use ($connection) {
$task_connection -> close();
$connection -> send($task_result);
};
// 执行异步连接
$task_connection->connect();
} else {
$e_configure = new EConfigure($dbconn, post: $post);
$res = $e_configure -> $action();
if ($res === true)
$connection -> send(json_encode(array(
'code' => 0,
'msg' => 'Success'
)));
else if ($res === "REMAINING") {
$connection -> send(json_encode(array(
'code' => 1,
'msg' => '该服务中仍有关联的设备,不允许删除!'
)));
} else if ($res === false) {
$connection -> send(json_encode(array(
'code' => 1,
'msg' => '服务器内部逻辑错误,请联系开发者!'
)));
}
}
} else if ($post -> action === 'set_node_data') { } else if ($post -> action === 'set_node_data') {
$data_capture = new EDataCapture($dbconn, no_dup_code: $options['no_dup_code'] ?? true, post: $post); $data_capture = new EDataCapture($dbconn, no_dup_code: $options['no_dup_code'] ?? true, post: $post);
if ($data_capture -> check_res === 'WRONG_WORKING_SUBCLASS') { if ($data_capture -> check_res === 'WRONG_WORKING_SUBCLASS') {
@@ -117,7 +159,7 @@ $worker -> onMessage = function(TcpConnection $connection, Request $request) {
], json_encode(array( ], json_encode(array(
'action' => 'result_set_node_data', 'action' => 'result_set_node_data',
'errcode' => 4002, 'errcode' => 4002,
'errmsg' => '未登记过的工序单元!' 'errmsg' => '工序单元有误,请检查是否未指定或未登记'
))); )));
$connection -> send($response); $connection -> send($response);
} else if ($data_capture -> check_res === 'MISMATCH_TYPE') { } else if ($data_capture -> check_res === 'MISMATCH_TYPE') {
@@ -176,7 +218,7 @@ $worker -> onMessage = function(TcpConnection $connection, Request $request) {
if (is_null($nodes)) if (is_null($nodes))
$connection -> send(json_encode(array( $connection -> send(json_encode(array(
'code' => 1, 'code' => 1,
'msg' => 'no node data yet' 'msg' => '未添加过节点!'
))); )));
else else
$connection -> send(json_encode(array( $connection -> send(json_encode(array(
@@ -227,6 +269,19 @@ $worker -> onMessage = function(TcpConnection $connection, Request $request) {
'code' => 0, 'code' => 0,
'data' => $data 'data' => $data
))); )));
} else if ($get['query'] == 'servers') {
$e_configure = new EConfigure($dbconn, get: $get);
$nodes = $e_configure -> get_servers();
if (is_null($nodes))
$connection -> send(json_encode(array(
'code' => 1,
'msg' => '未添加过服务!'
)));
else
$connection -> send(json_encode(array(
'code' => 0,
'data' => $nodes
)));
} else { } else {
$connection -> send(json_encode(array( $connection -> send(json_encode(array(
'code' => 1, 'code' => 1,
@@ -273,6 +328,26 @@ $consumer -> onMessage = function(TcpConnection $connection, $task_data) {
'msg' => '服务器内部逻辑错误,请联系开发者!' 'msg' => '服务器内部逻辑错误,请联系开发者!'
))); )));
} }
} else if ($task_data -> action === 'add_server') {
$e_configure = new EConfigure($consumer_dbconn, post: $task_data -> data);
$res = $e_configure -> add_server();
if ($res === true)
$connection -> send(json_encode(array(
'code' => 0,
'msg' => 'Success'
)));
else if ($res === "REPLICATED")
$connection -> send(json_encode(array(
'code' => 1,
'msg' => '该地址或名称已注册过服务!'
)));
else if ($res === false) {
$connection -> send(json_encode(array(
'code' => 1,
'msg' => '服务器内部逻辑错误,请联系开发者!'
)));
}
} }
}; };

View File

@@ -0,0 +1,100 @@
<?php
namespace EdgeManager\EController;
class EConfigure {
function __construct(
protected $dbconn,
protected $post = NULL,
protected $get = NULL,
) {}
function add_server() {
pg_query($this -> dbconn, "BEGIN");
$addr_exists = pg_query($this -> dbconn, sprintf(
"SELECT EXISTS (
SELECT 1 FROM hf_mes_scada_edgeserver_controller_server
WHERE url = '%s'
AND port = '%s'
)",
$this -> post -> url,
$this -> post -> port
));
$name_exists = pg_query($this -> dbconn, sprintf(
"SELECT EXISTS (
SELECT 1 FROM hf_mes_scada_edgeserver_controller_server
WHERE name = '%s'
)",
$this -> post -> name
));
if (
pg_fetch_assoc($addr_exists)['exists'] === 't'
or pg_fetch_assoc($name_exists)['exists'] === 't'
) {
pg_query($this -> dbconn, "ROLLBACK");
return "REPLICATED";
} else {
$res = pg_insert(
$this -> dbconn,
'hf_mes_scada_edgeserver_controller_server',
(array) $this -> post
);
if ($res) {
pg_query($this -> dbconn, "COMMIT");
return true;
} else {
pg_query($this -> dbconn, "ROLLBACK");
return false;
}
}
}
function remove_server() {
pg_query($this -> dbconn, "BEGIN");
$exists = pg_query($this -> dbconn, sprintf(
"SELECT EXISTS(
SELECT 1 FROM hf_mes_scada_edgeserver_controller_device
WHERE server_id = '%s'
)", $this -> post -> id
));
if (pg_fetch_assoc($exists)['exists'] === 't') {
pg_query($this -> dbconn, "ROLLBACK");
return "REMAINING";
} else {
$res = pg_delete(
$this -> dbconn,
'hf_mes_scada_edgeserver_controller_server',
(array) $this -> post,
);
if ($res) {
pg_query($this -> dbconn, "COMMIT");
return true;
} else {
pg_query($this -> dbconn, "ROLLBACK");
return false;
}
}
}
function update_server() {
return pg_update(
$this -> dbconn,
'hf_mes_scada_edgeserver_controller_server',
(array) $this -> post,
['id' => $this -> post -> id]
);
}
function get_servers() {
$res = pg_query($this -> dbconn, "SELECT * FROM hf_mes_scada_edgeserver_controller_server");
return pg_fetch_all($res);
}
function add_device() {
return pg_insert(
$this -> dbconn,
'hf_mes_scada_edgeserver_controller_server',
(array) $this -> post
);
}
}

View File

@@ -13,29 +13,31 @@ class EDataCapture {
protected $data = [], protected $data = [],
) { ) {
if (!is_null($this -> post)) { if (!is_null($this -> post)) {
if (!in_array( if(isset($this -> post -> param -> working_subclass)){
$this -> post -> param -> working_subclass, if (!in_array(
ENodeConfigure::get_working_subclasses($this -> dbconn) $this -> post -> param -> working_subclass,
)) { ENodeConfigure::get_working_subclasses($this -> dbconn)
$this -> check_res = 'WRONG_WORKING_SUBCLASS'; )) {
return; $this -> check_res = 'WRONG_WORKING_SUBCLASS';
} else { return;
$this -> working_subclass = $this -> post -> param -> working_subclass; } else {
$this -> working_subclass = $this -> post -> param -> working_subclass;
}
}else{
if ($this -> no_dup_code) {
$this -> check_res = 'WRONG_WORKING_SUBCLASS';
return;
}
$working_subclass = ENodeConfigure::get_working_subclasses_by_codes($this -> dbconn, $this -> post -> param -> data[0] -> code);
$this -> working_subclass = $working_subclass['working_subclass'];
} }
if ($this -> no_dup_code) { $res = pg_fetch_all(pg_query($this -> dbconn, sprintf(
$res = pg_fetch_all(pg_query($this -> dbconn, "SELECT code, type
"SELECT code, type FROM hf_mes_scada_data_capture_node_configure
FROM hf_mes_scada_data_capture_node_configure" WHERE working_subclass = '%s'",
)); $this -> working_subclass
} else { )));
$res = pg_fetch_all(pg_query($this -> dbconn, sprintf(
"SELECT code, type
FROM hf_mes_scada_data_capture_node_configure
WHERE working_subclass = '%s'",
$this -> post -> param -> working_subclass
)));
}
$code_type = &$this -> code_type; $code_type = &$this -> code_type;
array_walk($res, function(&$v, $k) use (&$code_type) { array_walk($res, function(&$v, $k) use (&$code_type) {

View File

@@ -16,15 +16,15 @@ class ENodeConfigure {
"SELECT EXISTS( "SELECT EXISTS(
SELECT 1 FROM hf_mes_scada_data_capture_node_configure SELECT 1 FROM hf_mes_scada_data_capture_node_configure
WHERE code = '%s' WHERE code = '%s'
)", $this -> post -> code AND working_subclass = '%s'
)", $this -> post -> code, $this -> post -> working_subclass
)); ));
} else { } else {
$exists = pg_query($this -> dbconn, sprintf( $exists = pg_query($this -> dbconn, sprintf(
"SELECT EXISTS( "SELECT EXISTS(
SELECT 1 FROM hf_mes_scada_data_capture_node_configure SELECT 1 FROM hf_mes_scada_data_capture_node_configure
WHERE code = '%s' WHERE code = '%s'
AND working_subclass = '%s' )", $this -> post -> code
)", $this -> post -> code, $this -> post -> working_subclass
)); ));
} }
@@ -111,7 +111,7 @@ class ENodeConfigure {
$this -> dbconn, $this -> dbconn,
'hf_mes_scada_data_capture_node_configure', 'hf_mes_scada_data_capture_node_configure',
(array) $this -> post, (array) $this -> post,
['code' => $this -> post -> code] ['id' => $this -> post -> id]
); );
} }
@@ -125,6 +125,16 @@ class ENodeConfigure {
return pg_fetch_all_columns($res, 0); return pg_fetch_all_columns($res, 0);
} }
static function get_working_subclasses_by_codes($dbconn, $code) {
$res = pg_query($dbconn, sprintf(
"SELECT working_subclass
FROM hf_mes_scada_data_capture_node_configure
WHERE code = '%s'",
$code
));
return pg_fetch_assoc($res);
}
function get_codes_by_working_subclasses() { function get_codes_by_working_subclasses() {
$res = pg_query($this -> dbconn, sprintf( $res = pg_query($this -> dbconn, sprintf(
"SELECT code "SELECT code

View File

@@ -25,12 +25,25 @@ function init_db($server_name, $port, $user, $password) {
id serial2 primary key, id serial2 primary key,
code text, code text,
name text NOT NULL, name text NOT NULL,
ip text NOT NULL, url text NOT NULL,
port int2 NOT NULL, port int2 NOT NULL,
sync_addr text NOT NULL, address text NOT NULL,
create_date timestamp NOT NULL DEFAULT NOW(), create_date timestamp NOT NULL DEFAULT NOW(),
note text note text
)"); )");
pg_query($dbconn, "CREATE TABLE IF NOT EXISTS hf_mes_scada_edgeserver_controller_device (
id serial2 primary key,
code text,
name text NOT NULL,
server_id serial2 references hf_mes_scada_edgeserver_controller_server(id),
conf json,
create_date timestamp NOT NULL DEFAULT NOW(),
note text,
status bool,
success_count int8,
failed_count int8,
duration int8
)");
pg_query($dbconn, "CREATE TABLE IF NOT EXISTS hf_mes_scada_edgeserver_controller_command ( pg_query($dbconn, "CREATE TABLE IF NOT EXISTS hf_mes_scada_edgeserver_controller_command (
id serial8 primary key, id serial8 primary key,
server_id serial2 references hf_mes_scada_edgeserver_controller_server(id), server_id serial2 references hf_mes_scada_edgeserver_controller_server(id),

View File

@@ -0,0 +1,38 @@
import { handlePost } from '../tools'
export default ({ service, request, serviceForMock, requestForMock, mock, faker, tools }) => ({
/**
* @description 方法名称
* @param {Object} data 请求携带的信息
*/
VERIFY_SERVER (url, username, password) {
return request({
auth: {
username: username,
password: password
},
method: 'post',
url: url + '/Admin/ServerSettingsRequest'
})
},
MODIFY_SERVER (url, username, password, data) {
return request({
auth: {
username: username,
password: password
},
data: data,
method: 'post',
url: url + '/Admin/ServerSettingsModify'
})
},
ADD_SERVER: (data) => handlePost(request, data),
UPDATE_SERVER: (data) => handlePost(request, data),
REMOVE_SERVER: (data) => handlePost(request, data),
QUERY_SERVERS () {
return request({ url: '?query=servers' })
}
})

View File

@@ -1,8 +1,4 @@
const handlePost = (request, data) => (request({ import { handlePost } from '../tools'
url: '',
method: 'post',
data
}))
export default ({ service, request, serviceForMock, requestForMock, mock, faker, tools }) => ({ export default ({ service, request, serviceForMock, requestForMock, mock, faker, tools }) => ({
/** /**
@@ -14,7 +10,7 @@ export default ({ service, request, serviceForMock, requestForMock, mock, faker,
UPDATE_NODE: (data) => handlePost(request, data), UPDATE_NODE: (data) => handlePost(request, data),
REMOVE_NODE: (data) => handlePost(request, data), REMOVE_NODE: (data) => handlePost(request, data),
QUERY_NODE () { QUERY_NODES () {
return request({ url: '?query=nodes' }) return request({ url: '?query=nodes' })
}, },

View File

@@ -84,3 +84,9 @@ export function errorCreate (msg) {
errorLog(error) errorLog(error)
throw error throw error
} }
export const handlePost = (request, data) => (request({
url: '',
method: 'post',
data
}))

View File

@@ -23,5 +23,12 @@ export const menuAside = supplementPath([
{ path: '/scada_configure', title: 'SCADA节点配置' }, { path: '/scada_configure', title: 'SCADA节点配置' },
{ path: '/scada_query', title: 'SCADA数据查询' } { path: '/scada_query', title: 'SCADA数据查询' }
] ]
},
{
title: '采集服务管理',
children: [
{ path: '/edge_server_configure', title: '服务配置' },
{ path: '/edge_server_monitor', title: '服务监控' }
]
} }
]) ])

View File

@@ -39,6 +39,24 @@ const frameIn = [
}, },
component: _import('scada/scadaQuery') component: _import('scada/scadaQuery')
}, },
{
path: 'edge_server_configure',
name: 'edge_server_configure',
meta: {
title: '服务配置',
auth: true
},
component: _import('edgeServer/edgeServerConfigure')
},
{
path: 'edge_server_monitor',
name: 'edge_server_monitor',
meta: {
title: '服务监控',
auth: true
},
component: _import('edgeServer/edgeServerMonitor')
},
// 系统 前端日志 // 系统 前端日志
{ {
path: 'log', path: 'log',

View File

@@ -0,0 +1,283 @@
<template>
<d2-container>
<d2-crud
ref="d2Crud"
:columns="columns"
:data="data"
:rowHandle="rowHandle"
add-title="新增服务"
edit-title="修改服务配置"
:add-template="addTemplate"
:edit-template="editTemplate"
:form-options="formOptions"
:add-rules="addRules"
@row-add="handleRowAdd"
@row-edit="handleRowEdit"
@row-remove="handleRowRemove"
@dialog-cancel="handleDialogCancel">
<el-button slot="header" style="margin-bottom: 5px" @click="addRow">新增</el-button>
</d2-crud>
</d2-container>
</template>
<script>
import { assign, each } from 'lodash'
const genRanHex = size => [...Array(size)].map(() => Math.floor(Math.random() * 16).toString(16).toUpperCase()).join('')
export default {
data () {
return {
columns: [
{
title: '序号',
key: 'id'
},
{
title: '名称',
key: 'name'
},
{
title: 'URL',
key: 'url'
},
{
title: '端口',
key: 'port'
},
{
title: '绑定地址',
key: 'address'
},
{
title: '创建时间',
key: 'create_date'
},
{
title: '备注',
key: 'note'
}
],
data: [],
serverSettings: {},
rowHandle: {
minWidth: '200',
edit: {
icon: 'el-icon-edit',
text: '编辑',
size: 'small',
show (index, row) {
if (row.showEditButton) {
return true
}
return false
}
},
remove: {
icon: 'el-icon-delete',
size: 'small',
fixed: 'right',
confirm: true,
show (index, row) {
if (row.showRemoveButton) {
return true
}
return false
}
}
},
addTemplate: {
deviceName: {
title: '服务名称',
value: 'Edge:' + genRanHex(12)
},
uniqueID: {
title: '唯一标识',
value: '',
component: {
disabled: true,
placeholder: '采集服务唯一标识,测试成功后返回'
}
},
url: {
title: 'URL',
value: '',
component: {
span: 12
}
},
port: {
title: '端口',
value: 522,
component: {
span: 12
}
},
userName: {
title: '用户名',
value: 'admin',
component: {
span: 12
}
},
password: {
title: '密码',
value: '123456',
component: {
span: 12,
'show-password': true
}
},
address: {
title: '绑定地址',
value: '',
component: {
placeholder: '请填入绑定EdgeManager实例的地址比如http://xxx.xxx:xxxx'
}
}
},
editTemplate: {
address: {
title: '绑定地址',
component: {
placeholder: '仅可以修改已绑定EdgeManager实例的地址'
}
}
},
formOptions: {
labelWidth: '80px',
labelPosition: 'left',
saveLoading: false,
saveButtonText: '测试',
saveButtonType: 'text'
},
addRules: {
deviceName: [{ required: true, type: 'string', message: '服务名称不可为空', trigger: 'blur' }],
url: [{ required: true, type: 'string', message: '服务地址不可为空', trigger: 'blur' }],
port: [{ required: true, type: 'integer', transform: v => +v, message: '端口号必须指定,且需为(0, 65535]内的正整数', trigger: 'blur' }],
userName: [{ required: true, message: '用户名不可为空', trigger: 'blur' }],
password: [{ required: true, type: 'string', message: '密码不可为空', trigger: 'blur' }],
address: [{ type: 'url', message: '绑定地址必须为合法URL', trigger: 'blur' }]
}
}
},
methods: {
async getServers () {
try {
const res = await this.$api.QUERY_SERVERS()
this.data = each(res, (o) => (
assign(o, {
showEditButton: true,
showRemoveButton: true
})
))
} catch (e) {
console.log(e)
}
},
// 普通的新增
addRow () {
this.$refs.d2Crud.showDialog({
mode: 'add'
})
},
async handleRowAdd (row, done) {
this.formOptions.saveLoading = true
try {
// 定义测试动作
if (this.formOptions.saveButtonText === '测试') {
this.serverSettings = await this.$api.VERIFY_SERVER('http://' + row.url + ':' + row.port, row.userName, row.password)
if (this.serverSettings) {
this.$message({
message: '测试通过!',
type: 'success'
})
}
this.formOptions.saveLoading = false
each(Object.keys(row), (p) => {
this.addTemplate[p].value = row[p]
})
this.addTemplate.uniqueID.value = this.serverSettings.Content.ServerInfoConfig.UniqueId
this.$refs.d2Crud.showDialog({
mode: 'add'
})
this.formOptions.saveButtonText = '添加'
this.formOptions.saveButtonType = 'success'
// 定义添加动作
} else {
this.serverSettings.Content.ServerInfoConfig.DeviceName = row.deviceName
this.serverSettings.Content.ServerInfoConfig.CaptureURL = row.address
console.log(this.serverSettings.Content.ServerInfoConfig)
await this.$api.MODIFY_SERVER(
'http://' + row.url + ':' + row.port,
row.userName,
row.password,
{ data: this.serverSettings.Content }
)
await this.$api.ADD_SERVER({
action: 'add_server',
name: row.deviceName,
url: row.url,
port: row.port,
address: row.address
})
this.$message({
message: '添加成功',
type: 'success'
})
this.getServers()
done()
}
} catch (e) {
this.$message({
message: '测试/添加失败!',
type: 'error'
})
console.log(e)
}
},
async handleRowEdit ({ index, row }, done) {
this.formOptions.saveLoading = true
this.serverSettings.Content.ServerInfoConfig.CaptureURL = row.address
await this.$api.MODIFY_SERVER(
'http://' + row.url + ':' + row.port,
row.userName,
row.password,
{ data: this.serverSettings.Content }
)
await this.$api.UPDATE_SERVER({
action: 'update_server',
id: row.id,
address: row.address
})
this.$message({
message: '编辑成功',
type: 'success'
})
done()
this.formOptions.saveLoading = false
},
async handleRowRemove ({ index, row }, done) {
await this.$api.REMOVE_SERVER({
action: 'remove_server',
id: row.id
})
this.$message({
message: '删除成功',
type: 'success'
})
done()
},
handleDialogCancel (done) {
this.$message({
message: '用户放弃改动',
type: 'warning'
})
done()
}
},
mounted () {
this.getServers()
}
}
</script>

View File

@@ -193,7 +193,7 @@ export default {
methods: { methods: {
async getNodes () { async getNodes () {
try { try {
const res = await this.$api.QUERY_NODE() const res = await this.$api.QUERY_NODES()
this.data = each(res, (o) => ( this.data = each(res, (o) => (
assign(o, { assign(o, {
showEditButton: true, showEditButton: true,