Kaynağa Gözat

智能照明首页接口思路

master
qdjjx 5 yıl önce
ebeveyn
işleme
d0ccdb48ec

+ 281
- 0
后端/项目/08.智能照明首页接口思路.md Dosyayı Görüntüle

@@ -0,0 +1,281 @@
1
+![](./imgs/znzmsy.jpg)
2
+
3
+> 需求
4
+
5
+- **共性提炼**:因为从首页项目,到楼层、区域、电箱展示内容格式相同,视图模型需要提炼出基类。
6
+- **层级扩展**:设计图中给出的是"项目、楼层、区域、电箱",如果有更多的层级如何处理?这里不能针对每个层级硬编码,这样会写很多接口,应该保持尽量少的接口。
7
+- **分页**:如果列表项很多,需要分页。
8
+- **中介模式**:希望控制器方法内代码尽量简洁,把请求交给一套机制,该机制返回响应。这里采用中介者模式。
9
+
10
+> 视图模型设计
11
+
12
+从前端发来的请求,服务端需要通过类来封装。所有的请求都涉及到分页、集团相关、项目相关、连接字符串相关,提炼出一个基类。
13
+
14
+BaseQuery.cs
15
+```
16
+public SieveModel PagingModel{get;set;}
17
+public string GroupId{get;set;}
18
+public string ProjectId{get;set;}
19
+public string ConnKey{get;set;}
20
+```
21
+以上,`SieveModel`来自一个第三方的有关分页的库,叫做`Sieve`。
22
+
23
+考虑到首页和内页不同之处,在基类基础上再设计:
24
+GeneralSumQuery.cs
25
+```
26
+//IRequest<T>来自一个中介者模式的库MediatR
27
+//意思是说,只要给我GeneralSumQuery,我就返回GeneralSumViewModel给外界
28
+//GeneralSumViewModel这个模型是给手机端,手机端拿着这个模型去填充页面
29
+public class GeneralSumQuery : BaseQuery, IRequest<GeneralSumViewModel>
30
+{
31
+    //首页的Project和内页的Location都需要用到
32
+    //当Level=0,就代表首页Project,当Level=1比如代表楼层,以此类推
33
+    public int Level{get;set;}
34
+
35
+    //这个属性是给Location用的,就是根据不同的LocationId去加载其下的子级Location
36
+    //子级Location有一个属性叫做ParentId,这个属性就指向父级的LocationId
37
+    //所有,根据父级的主键,也就是这里的LocationId能获得其下的所有子级Location
38
+    public string LocationId{get;set;}
39
+}
40
+```
41
+
42
+`GeneralSumViewModel`是返回给手机端用的,它代表如下红框中的部分:
43
+
44
+![](./imgs/vm1.png)
45
+
46
+对应代码:
47
+
48
+```
49
+public class GeneralSumViewModel
50
+{
51
+    //一旦有集合属性,一定要在构造函数内初始化,否则容易报null的错
52
+    public GeneralSumViewModel()
53
+        {
54
+
55
+            Items = new List<GeneralSumItemViewModel>();
56
+        }
57
+
58
+    public List<GeneralSumItemViewmodel> Items{get;set;}
59
+}
60
+```
61
+`GeneralSumItemViewmodel`代表这列表项,即如下红框中的部分:
62
+![](./imgs/vm2.png)
63
+
64
+代码如下:
65
+
66
+```
67
+public class GeneralSumItemViewModel : BaseViewModel
68
+    {
69
+        /// <summary>
70
+        /// 名称:项目名称、楼层名称、区域名称、电箱名称
71
+        /// </summary>
72
+        public string Name { get; set; }
73
+
74
+        /// <summary>
75
+        /// 报警颜色:WarningColorEnum
76
+        /// </summary>
77
+        public short Color { get; set; }
78
+
79
+        /// <summary>
80
+        /// 是否可以进入到下一级
81
+        /// </summary>
82
+        public bool IsContinue { get; set; }
83
+
84
+        /// <summary>
85
+        /// 下一个位置层级
86
+        /// </summary>
87
+        public int NextLevel { get; set; }
88
+
89
+        /// <summary>
90
+        /// 本层Location主键,项目的LocationId=-1
91
+        /// </summary>
92
+        public string LocationId { get; set; }
93
+
94
+        /// <summary>
95
+        /// 报警
96
+        /// </summary>
97
+        public GeneralWarningItemViewModel WarningItem { get; set; }
98
+
99
+        /// <summary>
100
+        /// 负荷
101
+        /// </summary>
102
+        public GeneralFuHeItemViewModel FuHeItem { get; set; }
103
+
104
+        /// <summary>
105
+        /// 开关比例
106
+        /// </summary>
107
+        public GeneralKGBLItemViewModel KGBLItem { get; set; }
108
+```
109
+
110
+视图模型的基类:
111
+```
112
+public class BaseViewModel
113
+    {
114
+        public string ProjectId { get; set; }
115
+        public string ConnKey { get; set; }
116
+    }
117
+```
118
+有关报警的视图模型:
119
+
120
+```
121
+public class GeneralWarningItemViewModel : BaseViewModel
122
+    {
123
+        /// <summary>
124
+        /// 报警描述
125
+        /// </summary>
126
+        public string Description { get; set; }
127
+        /// <summary>
128
+        /// 报警颜色:WarningColorEnum
129
+        /// </summary>
130
+        public short Color { get; set; }
131
+        /// <summary>
132
+        /// 报警数
133
+        /// </summary>
134
+        public string WarningNum { get; set; }
135
+    }
136
+```
137
+有关负荷的视图模型:
138
+
139
+```
140
+public class GeneralFuHeItemViewModel : BaseViewModel
141
+    {
142
+        /// <summary>
143
+        /// 负荷值
144
+        /// </summary>
145
+        public string FuHeValue { get; set; }
146
+    }
147
+```
148
+
149
+有关开关比例的视图模型:
150
+
151
+```
152
+public class GeneralKGBLItemViewModel : BaseViewModel
153
+    {
154
+        public string OpenNum { get; set; }
155
+        public string CloseNum { get; set; }
156
+    }
157
+```
158
+以上,包括接口所接受的模型和接口响应给前端的视图模型。
159
+
160
+输入和输出定下来了,现在需要通过中介者模式让处理请求,输出响应。如下:
161
+
162
+![](./imgs/mediator.png)
163
+
164
+> 处理请求和响应,中介者模式
165
+
166
+MediatR是一个有关中介者模式的第三方库,它的作者就是大名鼎鼎的AutopMapper的作者,而AutoMapper是用来建立DTO和Entity Framework模型之间映射的第三方库。
167
+
168
+HomeController.cs
169
+```
170
+ [Route("api/home")]
171
+    public class HomeController : BaseController
172
+    {
173
+
174
+        private readonly IHostingEnvironment _env;
175
+
176
+        public HomeController(IHostingEnvironment env)
177
+        {
178
+            _env = env;
179
+        }
180
+
181
+
182
+        /// <summary>
183
+        /// 获取首页项目列表
184
+        /// </summary>
185
+        /// <returns></returns>
186
+        /// <response code="200">返回首页项目列表</response>
187
+        [Authorize]
188
+        [Route("projects")]
189
+        [HttpPost]
190
+        [ProducesResponseType(200)]
191
+        public async Task<IActionResult> GetProjects(BaseFlatQuery query)
192
+        {
193
+
194
+            var generalQuery = new GeneralSumQuery
195
+            {
196
+                Level = 0,
197
+                LocationId = string.Empty,
198
+                GroupId = User.FindFirst(GlobalSettings.Auth_GroupId).Value,
199
+                ConnKey = string.Empty,
200
+                ProjectId = string.Empty,
201
+                PagingModel = new SieveModel
202
+                {
203
+                    Page=query.Page,
204
+                    PageSize = query.PageSize
205
+                }
206
+            };
207
+
208
+            return Ok(await Mediator.Send(generalQuery));
209
+        }
210
+
211
+        /// <summary>
212
+        /// 获取楼层、区域等列表
213
+        /// </summary>
214
+        /// <returns></returns>
215
+        /// <response code="200">返回楼层、区域等列表</response>
216
+        [Authorize]
217
+        [Route("locations")]
218
+        [HttpPost]
219
+        [ProducesResponseType(200)]
220
+        public async Task<IActionResult> GetLocations(GeneralLocationQuery query)
221
+        {
222
+            var generalQuery = new GeneralSumQuery
223
+            {
224
+                Level = query.Level,
225
+                LocationId = query.LocationId,
226
+                GroupId=string.Empty,
227
+                ConnKey=query.ConnKey,
228
+                ProjectId = query.ProjectId,
229
+                PagingModel = new SieveModel
230
+                {
231
+                    Page = query.Page,
232
+                    PageSize = query.PageSize
233
+                }
234
+            };
235
+
236
+            return Ok(await Mediator.Send(generalQuery));
237
+        }
238
+
239
+
240
+        /// <summary>
241
+        /// 首页测试数据
242
+        /// </summary>
243
+        /// <returns></returns>
244
+        /// <response code="200">返回首页测试数据</response>
245
+        [Authorize]
246
+        [HttpPost]
247
+        [Route("test")]
248
+        [ProducesResponseType(200)]
249
+        public IActionResult Test()
250
+        {           
251
+            //return Ok(new { Id = 1, Name="这里是测试数据"});
252
+            return Ok(User.FindFirst(GlobalSettings.Auth_GroupId).Value);
253
+        }
254
+    }
255
+```
256
+
257
+为什么需要`BaseFlatQuery`这个类?为什么不能用`BaseQuery`这个类?因为`BaseQuery`有些属性不是前端输入的,比如GroupId, ConnKey,这些属性是根据用户的相关信息赋值的,前端的请求不需要这个。而且在`BaseQuery`中有关分页的属性SieveModel中的Page和PageSize是可空的,在空的情况Sieve这个分页库会区找全局设置中的相关设置,即到appsettings.json中去找。总之,`BaseFlatQuery`是用来方便前端输入的,尽量让前端输入最简,并且没有嵌套类。同时,使用`BaseFlatQuery`这个类更安全,因为外界无从知晓服务端类的属性结构。
258
+
259
+MediatR的工作原理:
260
+
261
+- 定义请求:
262
+
263
+```
264
+public class MyQuery : IRequest<MyViewMedel>
265
+{}
266
+```
267
+-  定义处理流程
268
+
269
+```
270
+public class MyQueryHandler : IRequestHandler<MyQuery,MyViewModel>
271
+{
272
+
273
+    public async Task<MyViewMedel> Handler(MyQuery request, CancellationToken cancellationToken)
274
+    {
275
+
276
+
277
+    }
278
+}
279
+```
280
+
281
+MediatR的实现细节略去。

BIN
后端/项目/imgs/mediator.png Dosyayı Görüntüle


BIN
后端/项目/imgs/vm1.png Dosyayı Görüntüle


BIN
后端/项目/imgs/vm2.png Dosyayı Görüntüle


BIN
后端/项目/imgs/znzmsy.jpg Dosyayı Görüntüle


Loading…
İptal
Kaydet