Windows魔盒Web管理工具项目说明
项目目录
Vinno.FIS.Sonopost
├───Assets Web前端
│ ├───wwwroot 前端项目代码
│ │ ├───components 组件目录
│ │ ├───css 样式目录
│ │ ├───images 图片目录
│ │ ├───js 脚本目录
│ │ ├───lang 翻译文件目录
│ │ ├───libs 第三方库目录
│ │ ├───pages 页面目录
│ │ ├───favicon.ico
│ │ ├───index.html
│ │ └───README.md /* Current Document */
│ └───ViewEngine.cs 前端资源引擎
├───Features
│ └───Web
│ └───WebPreviewHandler.cs 基于Websocket的设备采集画面预览服务
├───WebApi Web后端
│ ├───Controllers 业务Controller目录
│ │ ├───DicomController.cs
│ │ ├───LiveController.cs
│ │ ├───NetworkController.cs
│ │ ├───ServerController.cs
│ │ ├───SystemController.cs
│ ├───Models 实体目录
│ ├───BaseController.cs Controller基类
│ ├───WebApiAttribute.cs WebAPI实体目录
│ └───WebApiEngine.cs WebAPI处理引擎
└───WebHost.cs Web宿主
Web 后端
采用魔盒启动时,开启自宿主Http服务来承载Web管理工具的页面和服务,在App.xmal.cs的OnStartup()最后调用`new WebHost().Start()`开启Web功能(端口设置在Setting文件的Web节点下)。
`Start()`运行后开启两个HttpListener监听Web请求:
1. Http
此Listener会同时监听80端口和8080端口(备用),监听处理Get和Post请求
其中Get请求交由ViewEngine.cs查找并输出web静态资源,Post请求交由WebApiEngine.cs处理WebAPI接口请求
2. WebSocket
此Listener会监听50012端口,负责基于WebSocket的采集画面预览请求,建立与浏览器的长连接
前端资源引擎
Web 前端
浏览器支持
为了高效开发和代码整洁,使用了现代浏览器支持的 Map、Array.map、Array.filter、Promise、async/await 等 ES6~ES8 特性和语法,所以放弃支持老旧的IE等浏览器。
针对非现代浏览器访问本工具的处理办法:
1. 检测浏览器版本
在加载应用和运行时(index.js)之前,会先加载执行prepare.js脚本,通过封装的isBrowserSupport() 检测
2. 页面提示
页面展示提示用户当前浏览器不被支持,并提供MicroSoft Edge下载地址
3. 移动端处理
与1、2点类似,检测为移动端环境时,页面展示提示用户仅在PC上访问
自建运行时
本项目模拟 App 设计了一套包含 App 单例和公共 Runtime 能力支持的开发方案。
项目设计为 单页应用 ,通过切换内容区域的`HTML`和`function Page()`实现页面的切换,`HTML`和`function Page()`及页面样式统一写在`pages`目录下单个`.html`文件中。
`function Page()` 默认支持两个入参:`app` 和 `runtime`,这两个入参都是对象类型,各自包含如下属性:
1. app 参数
属性 |
描述 |
el |
应用实例 JQuery Dom |
currentPage |
当前内容页面function Page() 实例 |
store |
状态管理,支持通过defineProp 定义带有get() ,set 的属性 |
router |
路由 (注: 在 index.js 的generateRoutes() 内注册页面路由) |
1.1 router 属性明细
属性 |
描述 |
current |
当前页面路由 |
getByPath() |
根据 hash 路由 path 获取路由信息 |
goto(name,isManual) |
切换页面 |
routes |
路由注册表 |
2. runtime 参数
属性 |
描述 |
locale |
本地化(翻译)功能实例 |
componentLoader |
组件管理功能实例: install() 和uninstall() |
$api(controller,action,request,timeout=5000) |
WebAPI 请求方法 |
$t(code) |
locale.translate() 的缩写代理 |
$c(...componentNames) |
componentLoader.install() 的代理和扩展 |
$loading() |
全局 Loading |
2.1 locale 属性明细
属性 |
描述 |
currentLanguage() |
获取当前语言 |
isCurrentChinese() |
当前语言是否中文 |
translate(code) |
根据 code 获取翻译文字 |
translatePage(page) |
整页翻译 |
changeLanguage(lang) |
全局切换语言 |
页面生命周期
回调方法 |
描述 |
onload() |
页面加载 |
beforeDestroy() |
页面销毁前 |
onLanguageChanged(lang) |
全局语言切换后 |
onResize() |
全局尺寸变化 |
关于组件
由于新增组件的场景少,且设计较为简单,不多说明。如有需要,请翻看源码,谢谢!
简单示例
<style>
#pageDemo {
/* ... */
}
#page .layui-form-item {
padding-bottom: 5px;
}
</style>
<div id="pageDemo">
<div class="layui-form page-form" lay-filter="FormDemo">
<div class="layui-form-item">
<label class="layui-form-label" data-content="Name"></label>
<div class="layui-input-block">
<input
type="text"
class="layui-input"
name="Name"
lay-filter="Name"
/>
</div>
</div>
<div>
<button
class="layui-btn layui-btn-normal"
lay-submit
lay-filter="Save"
data-content="Save"
></button>
</div>
<div id="cc"></div>
</div>
</div>
<script>
function Page(app, runtime) {
const { store, router } = app;
const { $api, $t, $c, $loading } = runtime;
const { form, layer } = layui;
const formFilter = "FormDemo";
this.onload = async function () {
initForm();
// 引入组件
await $c("Component01", "Component02");
let c01 = new Component01();
let c02 = new Component02();
c01.addTo("#cc");
c02.addTo("#cc");
form.on("submit(Save)",async function(data){
let index = $loading();
// 请求WebAPI
let res = await $api("Demo", "Test", data.field);
layer.close(index);
if(res.IsSuccess){
store.uniqueId = res.Data.UniqueId;
layer.msg.success($t("Success"));
// 通过路由跳转页面
router.goto("Page02", true);
}else{
layer.msg.error($t(res.Code));
}
});
};
this.beforeDestroy = function () {
console.log("Page demo closing...");
// await runtime.componentLoader.uninstall("Component01"); // 卸载组件
};
this.onLanguageChanged(lang){
layer.msg(`${$t("CurrentLanguage")}: ${lang}`);
}
// 页面私有方法必须定义在Page方法体内!
function initForm(){
form.val(formFilter, {
Name: "Test"
});
}
}
</script>