瀏覽代碼

2021过年期间

master
qdjjx 3 年之前
父節點
當前提交
039397469e

+ 1
- 1
专题/后端/2020.12.1后端接口格式.md 查看文件

@@ -65,7 +65,7 @@
65 65
 - 200:服务端确认客户端请求成功,一般用于GET和POST请求
66 66
 - 201:服务端创建资源成功
67 67
 - 204:服务端没有内容返回
68
-- 404:客户端要找的资源不存在
68
+- 404:客户端请求的资源不存在
69 69
 - 412:客户端先决条件错误
70 70
 - 413:客户端请求实体过大
71 71
 - 414:客户端请求URL过长

+ 101
- 0
专题/后端/2020.12.7后端培训.md 查看文件

@@ -0,0 +1,101 @@
1
+# 公司方向
2
+
3
+提供以智能照明为基础的物联网解决方案。数据角度来看,想把有关电的数据收集上来,让数据产生价值,提供电力数据服务。
4
+
5
+目前的阶段:原型打造阶段。将来涉及并发,分布式,云原生运用,容器,微服务之类。再往后走,有关大数据处理。 
6
+
7
+# 个人方向
8
+
9
+
10
+
11
+# 公司当前的项目
12
+
13
+- 智能照明版:主要用在商场,目前在做运维、功能更新
14
+- 智能照明版手机端:目前已完成
15
+- 写字楼版:主要用在写字楼,包括手机端端和Web管理端,目前正在做
16
+- 宿舍公寓版:主要用在大学宿舍,目前正在写需求
17
+- 总部大屏:把各个项目数据汇总,并且报警实时推送,目前正在把胶州数据接上来
18
+- 写字楼版大屏:主要以建筑3D为主
19
+- 总部运营后台:
20
+- 项目管理后台
21
+
22
+# 后端要做的事
23
+
24
+- 智能照明版的项目后台:季建新做
25
+- 智能照明版的API接口:季建新做
26
+- 写字楼版API接口:以外协吕亮为主,季建新负责架构,冷坚熟悉了解,写部分接口
27
+- 宿舍公寓版:冷坚和吕亮为主,季建新负责架构
28
+- 总部大屏接口:季建新做
29
+- 写字楼版大屏接口:待定
30
+- 总部运营后台接口:待定
31
+- 项目管理后台接口:待定
32
+
33
+
34
+# 团队开发方式
35
+
36
+SCRUM模式,敏捷迭代式的,小步快走。
37
+
38
+会议
39
+
40
+- 站例会:每天下班之前,某个项目的成员一起站立式会议,介绍今天的进展、遇到的问题、需要的协助,一般在10分钟左右
41
+- 周例会:一般是在周五17:00开始,由项目经理主持,需要提前把周总结发给项目经理。
42
+- 迭代复盘:做得好的和不好的方面
43
+- 分享会:一般是在周五13:00团队成员做一些分享,有时候关于工作,有时候有关其它方面
44
+
45
+工具
46
+
47
+- Teambition项目管理
48
+- gitbash
49
+
50
+# 架构
51
+
52
+![](onion.png)
53
+
54
+# 领域知识
55
+
56
+- Teambition的 `公共组件库`
57
+
58
+# git的原理和常用命令
59
+
60
+原理:
61
+
62
+- 工作区
63
+- 暂存区
64
+- 仓储区
65
+
66
+命令:
67
+```
68
+从远程拉取到本地:git pull origin master
69
+查看工作区有没有更新:git status
70
+从工作区到暂存区:git add -all
71
+暂存区到仓储区:git commit -m "some messages"
72
+```
73
+
74
+`git pull`实际上包含了2个语句:
75
+```
76
+git fetch origin master
77
+git merge
78
+```
79
+
80
+# 其它
81
+
82
+- 下载git bash windows版本
83
+- 加入代码库
84
+```
85
+--分配账号:
86
+--设置公钥
87
+ssh-keygen -t rsa -C "darren@ddingsafe.com"
88
+有时需要安装http://cygwin.com/
89
+私钥的保存位置在:C:\Users\Administrator.ssh\id_rsa.pub
90
+把公钥保存到源代码后台
91
+--git clone 地址
92
+```
93
+- 确认SDK:`dotnet --list-sdks`
94
+- 项目总览
95
+- 需求文档
96
+- 蓝湖:`https://lanhuapp.com/url/y8bBL-k39J5`
97
+- 加入Teambtion项目
98
+- 跑通第一个接口
99
+
100
+
101
+

+ 1485
- 0
专题/后端/2020.2.13领域驱动实战.md
文件差異過大導致無法顯示
查看文件


+ 254
- 0
专题/后端/2021.1.25开放平台开发文档(后端).md 查看文件

@@ -0,0 +1,254 @@
1
+鼎鼎所有售出模块的数据会统一指向到开放平台。所以,针对模块的所有操作围绕开放平台接口进行。本文档针对.NET Core后端开发人员。
2
+
3
+> 原理
4
+
5
+所有模块目前被记录在总部数据库的`TestMac`表,该表记录着模块和项目的映射关系。当通过项目寻找模块,通过`HeaderQuarterRepository`找到项目下的模块。
6
+
7
+如何找到模块下的开关呢?通过开放平台接口(`api/breaker/data`)就可以。
8
+
9
+> 开放平台:获取模块实时数据接口
10
+
11
+请求
12
+```
13
+POST http://47.103.61.198:5008/api/breaker/data
14
+
15
+Headers:
16
+
17
+Content-Type: application/json
18
+DD-Open-Key: d2ca79f1-4666-4ad5-953b-7ba5ee480fe0
19
+
20
+Body:
21
+
22
+{
23
+	"mac":"187ED53338C4"
24
+}
25
+```
26
+
27
+响应:
28
+```
29
+{
30
+    "data": {
31
+        "serverinfo": {
32
+            "port": "12345",
33
+            "hardware": "T25",
34
+            "execleakcheck": "false",
35
+            "protocol_ver": "19",
36
+            "mac": "187ED53338C4",
37
+            "loginid": "187ED53338C4",
38
+            "gate": "",
39
+            "ip": "192.168.8.134",
40
+            "version": "1.3.08",
41
+            "loginpwd": "7a57a5a743894ae4",
42
+            "ssidpwd": "2803f88db851c67a",
43
+            "ssid": "DDINGW",
44
+            "timezoneId": "Asia/Shanghai",
45
+            "ServerProtocol": "2",
46
+            "server": "47.103.61.198:5008/ebx-bishop/data/carry",
47
+            "datetime": "2021-01-25 14:24:56",
48
+            "leakcheckdate": "3,13,33",
49
+            "lastleakcheckdate": "2017-01-01 10:00:00"
50
+        },
51
+        "distributbox": {
52
+            "breakers": {
53
+                "1": {
54
+                    "version": "1.03",
55
+                    "title": "总路",
56
+                    "model": "JZK2L100-BL6523",
57
+                    "alarm": 0,
58
+                    "enableNetCtrl": true,
59
+                    "mxdw": 0,
60
+                    "mxgg": 14080,
61
+                    "mxgl": 96,
62
+                    "mxgw": 90,
63
+                    "mxgy": 260,
64
+                    "mxld": 30,
65
+                    "mxqy": 0,
66
+                    "openClose": true,
67
+                    "addr": 1,
68
+                    "power": 0,
69
+                    "specification": "64",
70
+                    "control": 1,
71
+                    "visibility": 1,
72
+                    "totalChannelId": -1,
73
+                    "lineType": "220",
74
+                    "a_A": 0,
75
+                    "a_T": 32.1,
76
+                    "a_V": 226,
77
+                    "a_WP": 0,
78
+                    "a_LD": 0.5,
79
+                    "a_PF": 0,
80
+                    "g_A": 0,
81
+                    "g_T": 0,
82
+                    "g_V": 0,
83
+                    "g_WP": 0,
84
+                    "g_LD": 0,
85
+                    "g_PF": 0,
86
+                    "b_A": 0,
87
+                    "b_T": 0,
88
+                    "b_V": 0,
89
+                    "b_WP": 0,
90
+                    "b_PF": 0,
91
+                    "c_A": 0,
92
+                    "c_T": 0,
93
+                    "c_V": 0,
94
+                    "c_WP": 0,
95
+                    "c_PF": 0,
96
+                    "n_A": 0,
97
+                    "n_T": 0
98
+                },
99
+                "2": {
100
+                    "version": "1.03",
101
+                    "title": "线路1",
102
+                    "model": "JZK2L100-BL6523",
103
+                    "alarm": 0,
104
+                    "enableNetCtrl": true,
105
+                    "mxdw": 0,
106
+                    "mxgg": 100,
107
+                    "mxgl": 30,
108
+                    "mxgw": 90,
109
+                    "mxgy": 260,
110
+                    "mxld": 30,
111
+                    "mxqy": 175,
112
+                    "openClose": true,
113
+                    "addr": 2,
114
+                    "power": 0,
115
+                    "specification": "20",
116
+                    "control": 1,
117
+                    "visibility": 1,
118
+                    "totalChannelId": 1,
119
+                    "lineType": "220",
120
+                    "a_A": 0,
121
+                    "a_T": 35,
122
+                    "a_V": 226,
123
+                    "a_WP": 0,
124
+                    "a_LD": 0,
125
+                    "a_PF": 0,
126
+                    "g_A": 0,
127
+                    "g_T": 0,
128
+                    "g_V": 0,
129
+                    "g_WP": 0,
130
+                    "g_LD": 0,
131
+                    "g_PF": 0,
132
+                    "b_A": 0,
133
+                    "b_T": 0,
134
+                    "b_V": 0,
135
+                    "b_WP": 0,
136
+                    "b_PF": 0,
137
+                    "c_A": 0,
138
+                    "c_T": 0,
139
+                    "c_V": 0,
140
+                    "c_WP": 0,
141
+                    "c_PF": 0,
142
+                    "n_A": 0,
143
+                    "n_T": 0
144
+                },
145
+                "3": {
146
+                    "version": "1.03",
147
+                    "title": "线路2",
148
+                    "model": "JZK2L100-BL6523",
149
+                    "alarm": 0,
150
+                    "enableNetCtrl": true,
151
+                    "mxdw": 0,
152
+                    "mxgg": 4400,
153
+                    "mxgl": 30,
154
+                    "mxgw": 90,
155
+                    "mxgy": 260,
156
+                    "mxld": 30,
157
+                    "mxqy": 175,
158
+                    "openClose": true,
159
+                    "addr": 3,
160
+                    "power": 0,
161
+                    "specification": "20",
162
+                    "control": 1,
163
+                    "visibility": 1,
164
+                    "totalChannelId": 1,
165
+                    "lineType": "220",
166
+                    "a_A": 0,
167
+                    "a_T": 35,
168
+                    "a_V": 226,
169
+                    "a_WP": 0,
170
+                    "a_LD": 0,
171
+                    "a_PF": 0,
172
+                    "g_A": 0,
173
+                    "g_T": 0,
174
+                    "g_V": 0,
175
+                    "g_WP": 0,
176
+                    "g_LD": 0,
177
+                    "g_PF": 0,
178
+                    "b_A": 0,
179
+                    "b_T": 0,
180
+                    "b_V": 0,
181
+                    "b_WP": 0,
182
+                    "b_PF": 0,
183
+                    "c_A": 0,
184
+                    "c_T": 0,
185
+                    "c_V": 0,
186
+                    "c_WP": 0,
187
+                    "c_PF": 0,
188
+                    "n_A": 0,
189
+                    "n_T": 0
190
+                }
191
+            },
192
+            "change": null
193
+        }
194
+    },
195
+    "isError": false,
196
+    "message": "success",
197
+    "code": 200
198
+}
199
+```
200
+
201
+在Application层,按如下方式调用:
202
+```
203
+using Flurl.Http;
204
+using DD.Libs.Devices.ManDun;
205
+
206
+string url = "http://47.103.61.198:5008/api/breaker/data";
207
+
208
+var dto = new SomeClass{ mac="187ED53338C4"};
209
+
210
+
211
+var response = await url
212
+            .WithHeader("Content-Type", "application/json")
213
+            .WithHeader("DD-Open-Key", "d2ca79f1-4666-4ad5-953b-7ba5ee480fe0")
214
+            .PostJsonAsync(dto)
215
+            .ReceiveJson<RealtimeData>();
216
+
217
+```
218
+
219
+> 开放平台:合闸或分断
220
+
221
+请求
222
+```
223
+POST http://47.103.61.198:5008/api/breaker/oc
224
+
225
+Headers:
226
+
227
+Content-Type: application/json
228
+DD-Open-Key: d2ca79f1-4666-4ad5-953b-7ba5ee480fe0
229
+
230
+Body:
231
+
232
+{
233
+	"cmd":"OCSWITCH",
234
+	"value1":"open",
235
+	"value2":"1,2,3",
236
+	"mac":"187ED53338C4",
237
+	"extra":""
238
+}
239
+```
240
+
241
+在Application层,按如下方式调用:
242
+```
243
+using Flurl.Http;
244
+
245
+string url = "http://47.103.61.198:5008/api/breaker/oc";
246
+
247
+var dto = new SomeClass{ cmd="",value1="",value2="",mac="",extra=""};
248
+
249
+var response = await url
250
+            .WithHeader("Content-Type", "application/json")
251
+            .WithHeader("DD-Open-Key", "d2ca79f1-4666-4ad5-953b-7ba5ee480fe0")
252
+            .PostJsonAsync(dto);
253
+
254
+```

+ 5
- 0
专题/后端/2021.2.3好用的sql语句.md 查看文件

@@ -0,0 +1,5 @@
1
+```
2
+BEGIN
3
+SELECT SUM(power),yyyymmdd FROM powers WHERE monthweekday="HOURS" AND StartTime<=STR_TO_DATE(yyyymmdd,'%Y%m%d%H') AND EndTime>=STR_TO_DATE(yyyymmdd,'%Y%m%d%H') GROUP BY yyyymmdd;
4
+END
5
+```

+ 519
- 0
专题/后端/2021.2.3极光推送原理.md 查看文件

@@ -0,0 +1,519 @@
1
+
2
+# 引用包
3
+```
4
+<PackageReference Include="Flurl" Version="2.8.2" />
5
+<PackageReference Include="Flurl.Http" Version="2.4.2" />
6
+```
7
+
8
+# 触发时间
9
+
10
+- 触发原理:当用户在手机上点击了某个按钮,我们需要把延迟的时间记录到Quartz.Net数据表里。
11
+- QuartzNet运作原理:创建一个`IJob`作业,把设置保存到QuartzNet专有的表。当触发的时候,QuartzNet会调用我们定义好的接口,发送极光推送以及把一条通知记录保存到数据库的Noti表。
12
+
13
+首先有关配置。
14
+```
15
+namespace DD.Libs.TasksManager
16
+{
17
+    /// <summary>
18
+    /// 极光配置
19
+    /// </summary>
20
+    public class JobSetting : IOptions<JobSetting>
21
+    {
22
+        public JobSetting Value => this;
23
+
24
+        /// <summary>
25
+        /// 执行场景任务的url
26
+        /// http://47.103.61.198:5002/api/tasks/cj/
27
+        /// </summary>
28
+        public string sceneUrl { get; set; }
29
+
30
+        /// <summary>
31
+        /// 定时任务的url
32
+        /// http://47.103.61.198:5002/api/tasks/ds/ 
33
+        public string timingUrl { get; set; }
34
+
35
+        /// <summary>
36
+        /// 连接字符串的一部分
37
+        /// Port=3306;Database=quartznet;Uid=root;Pwd=pass;SslMode=none
38
+        /// </summary>
39
+        public string quartz { get; set; }
40
+
41
+        /// <summary>
42
+        /// 连接字符串的一部分
43
+        /// 192.168.9.108
44
+        /// </summary>
45
+        public string server { get; set; }
46
+    }
47
+}
48
+```
49
+
50
+在`appSetting.json`中配置
51
+```
52
+  "Tasks": { //场景和定时
53
+    "sceneUrl": "http://47.103.61.198:5005/api/tasks/noti/", //写字楼版QuartzNet触发发生时调用的接口
54
+    "timingUrl": "", //定时地址
55
+    "server": "47.103.61.198",
56
+    "quartz": "Port=3306;Database=ddquartz1;Uid=root;Pwd=TecheDing2019;SslMode=none"
57
+  },
58
+```
59
+
60
+接口实现:
61
+```
62
+namespace DD.Warning.WebUI.Controllers
63
+{
64
+    /// <summary>
65
+    /// 场景和定时在这里执行
66
+    /// </summary>
67
+    [AllowAnonymous]
68
+    [Produces("application/json")]
69
+    [Route("api/tasks")]
70
+    public class TaiHeRealController : Controller
71
+    {
72
+
73
+        private readonly IMediator _mediator; //中介者
74
+        private readonly ILogger<TaiHeRealController> _logger;
75
+
76
+        public TaiHeRealController(IMediator mediator, ILogger<TaiHeRealController> logger)
77
+        {
78
+            _mediator = mediator;
79
+            _logger = logger;
80
+        }
81
+
82
+        /// <summary>
83
+        /// 场景执行
84
+        /// </summary>
85
+        /// <param name="extra"></param>
86
+        /// <returns></returns>
87
+        [HttpGet("cj/{extra}")]
88
+        public async Task<IActionResult> cj(string extra)
89
+        {
90
+            //rlq_nuode,SceneId,SceneScheduleId
91
+            string[] tempArr = extra.Split(',');
92
+
93
+            var innerCommand = new AutoTriggerSceneCommand
94
+            {
95
+                SceneId = tempArr[1],
96
+                SceneScheudleId = tempArr[2],
97
+                ConnKey=tempArr[0]
98
+            };
99
+
100
+            _logger.LogWarning($"正在触发场景:{extra}{WarningConstants.LogPlaceholder}", WarningConstants.LogTest);
101
+
102
+            await _mediator.Send(innerCommand);
103
+            return Ok();
104
+        }
105
+
106
+    }
107
+}
108
+```
109
+
110
+
111
+定义一个`IJob`
112
+```
113
+namespace DD.Libs.TasksManager
114
+{
115
+    public class SceneJob : IJob
116
+    {
117
+        private readonly IOptions<JobSetting> _settings;
118
+
119
+        public SceneJob(IOptions<JobSetting> settings)
120
+        {
121
+            _settings = settings;
122
+        }
123
+        public async Task Execute(IJobExecutionContext context)
124
+        {
125
+            //获取job上下文中传来的额外参数
126
+            string extra = context.JobDetail.JobDataMap.GetString("extra");
127
+
128
+            using(var client = new HttpClient())
129
+            {
130
+                client.Timeout = TimeSpan.FromSeconds(1200);
131
+                //"http://47.103.61.198:5002/api/tasks/cj/
132
+                string url = $"{_settings.Value.sceneUrl }{extra}";
133
+                await client.GetAsync(url);
134
+            }
135
+        }
136
+    }
137
+}
138
+```
139
+
140
+在`Startup`中注册:
141
+```
142
+#region 场景定时任务,Quartz
143
+services.Configure<JobSetting>(Configuration.GetSection("Tasks"));
144
+services.AddTransient<SceneJob>();
145
+
146
+
147
+NameValueCollection props = new NameValueCollection {
148
+        { "quartz.threadPool.threadCount","100"},
149
+        { "quartz.jobStore.type","Quartz.Impl.AdoJobStore.JobStoreTX, Quartz"},
150
+        { "quartz.jobStore.driverDelegateType","Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz"},
151
+        { "quartz.jobStore.dataSource","myDS"},
152
+        { "quartz.dataSource.myDS.connectionString",$"Server={Configuration["Tasks:server"]};{Configuration["Tasks:quartz"]}"},
153
+        //{ "quartz.dataSource.myDS.connectionString",$"server={Configuration["App:redis"]};port=3306;database=quartznet;user=root;password=lcDb_!@34%^_Mantunsci;SslMode=none"},
154
+        { "quartz.dataSource.myDS.provider","MySql"},
155
+        { "quartz.serializer.type","json"}
156
+        //{ "quartz.jobStore.useProperties","true"}
157
+    };
158
+
159
+//计划工厂
160
+var schedulerFactory = new StdSchedulerFactory(props);
161
+services.AddSingleton<ISchedulerFactory>(schedulerFactory); //计划工厂
162
+
163
+//job工厂
164
+services.AddSingleton<IJobFactory, SimpleInjectorJobFactory>();//Job工厂
165
+
166
+//帮助类
167
+services.AddSingleton<DDJobScheduler>((ctx) => {
168
+
169
+    var tempSchedulerFactory = ctx.GetRequiredService<ISchedulerFactory>();
170
+    var tempJobFactory = ctx.GetRequiredService<IJobFactory>();
171
+
172
+    var tempScheduler = tempSchedulerFactory.GetScheduler().Result;
173
+    tempScheduler.JobFactory = tempJobFactory;
174
+    var tempJobScheduler = new DDJobScheduler(tempScheduler);
175
+    return tempJobScheduler;
176
+
177
+});
178
+#endregion
179
+```
180
+
181
+在请求管道中注册:
182
+```
183
+#region 场景定时任务
184
+var scheduler = serviceProvider.GetService<DDJobScheduler>();
185
+scheduler.Init();
186
+#endregion
187
+```
188
+
189
+如何使用呢?
190
+```
191
+public class AddSceneSchedulesCommandHandler : IRequestHandler<AddSceneSchedulesCommand, ResponseWrapperBase>
192
+{
193
+
194
+    private readonly DDJobScheduler _scheduler;
195
+
196
+    public AddSceneSchedulesCommandHandler(DDJobScheduler scheduler)
197
+    {
198
+        _scheduler = scheduler;
199
+    }
200
+    public async Task<ResponseWrapperBase> Handle(AddSceneSchedulesCommand request, CancellationToken cancellationToken)
201
+    {
202
+        await _scheduler.DeleteJob(delJoinName, delGroupName);
203
+        string cron = JobUtil.GetCronByTime(newSceneSchedule.Hour, newSceneSchedule.Minute, newSceneSchedule.Second, (TimingWeekEnum)newSceneSchedule.Week);
204
+        await _scheduler.AddSceneJob(joinName, groupName, cron, joinName);
205
+
206
+        return await Task.FromResult(result);
207
+    }
208
+
209
+```
210
+
211
+
212
+# 调用极光
213
+
214
+- 确定别名
215
+- 往数据库的Noti存入一条记录
216
+```
217
+对应的领域模型是:
218
+
219
+/// <summary>
220
+/// 通知
221
+/// </summary>
222
+public class Noti : Entity<Guid>, IAggregateRoot
223
+{
224
+    /// <summary>
225
+    /// 通知标题
226
+    /// </summary>
227
+    public string Title { get; private set; }
228
+    /// <summary>
229
+    /// 通知内容
230
+    /// </summary>
231
+    public string Content { get; private set; }
232
+    /// <summary>
233
+    /// 是否已读
234
+    /// </summary>
235
+    public string IsRead { get;private set; }
236
+
237
+    /// <summary>
238
+    /// 通知类型
239
+    /// 报警通知的Type=0
240
+    /// 延迟断电通知的Type=alert
241
+    /// </summary>
242
+    public string Type { get; private set; }
243
+
244
+    /// <summary>
245
+    /// 报警通知用的报警级别描述
246
+    /// </summary>
247
+    public string Level { get; private set; }
248
+
249
+    /// <summary>
250
+    /// 传递的主键
251
+    /// 用来点击某个通知跳转到某个地方
252
+    /// </summary>
253
+    public string ExtraId { get; private set; }
254
+
255
+    /// <summary>
256
+    /// 创建方式1
257
+    /// </summary>
258
+    /// <param name="title"></param>
259
+    /// <param name="content"></param>
260
+    public Noti(string title, string content)
261
+    {
262
+        if (string.IsNullOrEmpty(title)) throw new ArgumentNullException("title cannot be null");
263
+        if (string.IsNullOrEmpty(content)) throw new ArgumentNullException("content cannot be null");
264
+
265
+        Title = title;
266
+        Content = content;
267
+
268
+        CreateTime = DateTime.Now.ToFullTimeStr();
269
+        Id = Guid.NewGuid();
270
+        LastUpdateTime = DateTime.Now.ToFullTimeStr();
271
+        IsLogicDel = CommonConstants.LogicDelNo;
272
+    }
273
+
274
+    /// <summary>
275
+    /// 创建方式2
276
+    /// </summary>
277
+    /// <param name="title"></param>
278
+    /// <param name="content"></param>
279
+    /// <param name="type"></param>
280
+    /// <param name="extraId"></param>
281
+    public Noti(string title, string content, string type, string extraId)
282
+    {
283
+        if (string.IsNullOrEmpty(title)) throw new ArgumentNullException("title cannot be null");
284
+        if (string.IsNullOrEmpty(content)) throw new ArgumentNullException("content cannot be null");
285
+        if (string.IsNullOrEmpty(extraId)) throw new ArgumentNullException("extraId cannot be null");
286
+
287
+        Title = title;
288
+        Content = content;
289
+        Type = type;
290
+        ExtraId = extraId;
291
+
292
+        CreateTime = DateTime.Now.ToFullTimeStr();
293
+        Id = Guid.NewGuid();
294
+        LastUpdateTime = DateTime.Now.ToFullTimeStr();
295
+        IsLogicDel = CommonConstants.LogicDelNo;
296
+    }
297
+
298
+    /// <summary>
299
+    /// 设置报警级别
300
+    /// </summary>
301
+    /// <param name="level"></param>
302
+    public void SetLevel(string level)
303
+    {
304
+        Level = level;
305
+    }
306
+
307
+    /// <summary>
308
+    /// 标记已读
309
+    /// </summary>
310
+    /// <param name="regId"></param>
311
+    public void MarkRead(string regId)
312
+    {
313
+        if (string.IsNullOrEmpty(regId)) throw new ArgumentNullException("title cannot be null");
314
+
315
+        if(string.IsNullOrEmpty(IsRead))
316
+        {
317
+            IsRead = regId;
318
+        }
319
+        else
320
+        {
321
+            var currentRegIds = regId.Split(',').ToList();
322
+            currentRegIds.Add(regId);
323
+            IsRead = string.Join(',', currentRegIds);
324
+        }
325
+    }
326
+}
327
+
328
+//对应的仓储
329
+private readonly INotiRepository _notiRepo;
330
+
331
+public SomeRequestHandler(INotiRepository notiRepo)
332
+{
333
+    _notiRepo = notiRepo;
334
+}
335
+
336
+
337
+//大致用法
338
+var newNoti = new Noti("title","content", "alert", string.Empty);
339
+_notiRepo.Add(newNoti);
340
+await _notiRepo.UnitOfWork.SaveChangesAsync(cancellationToken);
341
+
342
+```
343
+- 极光推送
344
+```
345
+var request = new JiGuanPushRequest
346
+    {
347
+        platform = "all",
348
+        //audience = "all",//针对所有
349
+        audience = new Audience
350
+        {
351
+            alias = tempAlias
352
+        },
353
+        notification = new Notification
354
+        {
355
+            alert = $"{locationDesc},{kgDesc},{warningDesc}",
356
+            android = new Android
357
+            {
358
+                extras = new Extras
359
+                {
360
+                    android_key1 = string.Empty,
361
+                    kaiGuanId = cloudKaiGuan.Id.ToString(),
362
+                    connKey = cloudKaiGuan.ConnKey,
363
+                    startTime = startEndTime,
364
+                    warningType = ((short)type).ToString(),
365
+                    projectId = _appOptions.Value.projectid,
366
+                    notiType = "0", //通知消息类型
367
+                    notiId = notis.Id.ToString()
368
+                }
369
+            },
370
+            ios = new Ios
371
+            {
372
+                sound = "sound.caf",
373
+                badge = "+1",
374
+                extras = new Extras2
375
+                {
376
+                    ios_key1 = string.Empty,
377
+                    kaiGuanId = cloudKaiGuan.Id.ToString(),
378
+                    connKey = cloudKaiGuan.ConnKey,
379
+                    startTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
380
+                    warningType = ((short)type).ToString(),
381
+                    projectId = _appOptions.Value.projectid,
382
+                    notiType = "0", //通知消息类型
383
+                    notiId = notis.Id.ToString()
384
+                }
385
+            }
386
+        },
387
+        options = new JiGuangs.Options
388
+        {
389
+            apns_production = true
390
+        }
391
+    };
392
+
393
+    var response = await _appOptions.Value.jiguang
394
+        .WithHeader("Content-Type", "application/json")
395
+        .WithHeader("Authorization", "Basic M2ZhOTE0NTUzNmEwMDFmY2UwYjg3NjU5OjIxYjE0ZGM0OGZkZjRmMDk4NzZiMTg0MQ==")
396
+        .PostJsonAsync(request);
397
+
398
+
399
+//相关Dto
400
+    public class JiGuanPushRequest
401
+    {
402
+        [JsonProperty("platform")]
403
+        public string platform { get; set; }
404
+
405
+        //[JsonProperty("audience")]
406
+        //public string audience { get; set; }
407
+
408
+        [JsonProperty("audience")]
409
+        public Audience audience { get; set; }
410
+
411
+        [JsonProperty("notification")]
412
+        public Notification notification { get; set; }
413
+
414
+        [JsonProperty("options")]
415
+        public Options options { get; set; }
416
+    }
417
+
418
+    public class Audience
419
+    {
420
+        [JsonProperty("alias")]
421
+        public List<string> alias { get; set; } = new List<string>();
422
+    }
423
+
424
+    public class Android
425
+    {
426
+        [JsonProperty("extras")]
427
+        public Extras extras { get; set; }
428
+    }
429
+
430
+    public class Extras
431
+    {
432
+        [JsonProperty("android-key1")]
433
+        public string android_key1 { get; set; }
434
+
435
+        [JsonProperty("kaiGuanId")]
436
+        public string kaiGuanId { get; set; }
437
+
438
+        [JsonProperty("warningType")]
439
+        public string warningType { get; set; }
440
+
441
+        [JsonProperty("startTime")]
442
+        public string startTime { get; set; }
443
+
444
+        [JsonProperty("connKey")]
445
+        public string connKey { get; set; }
446
+
447
+        [JsonProperty("notiType")]
448
+        public string notiType { get; set; }
449
+
450
+        [JsonProperty("projectId")]
451
+        public string projectId { get; set; }
452
+
453
+        [JsonProperty("notiId")]
454
+        public string notiId { get; set; }
455
+    }
456
+
457
+    public class Extras2
458
+    {
459
+        [JsonProperty("ios-key1")]
460
+        public string ios_key1 { get; set; }
461
+        [JsonProperty("kaiGuanId")]
462
+        public string kaiGuanId { get; set; }
463
+
464
+        [JsonProperty("warningType")]
465
+        public string warningType { get; set; }
466
+
467
+        [JsonProperty("startTime")]
468
+        public string startTime { get; set; }
469
+
470
+        [JsonProperty("connKey")]
471
+        public string connKey { get; set; }
472
+
473
+        [JsonProperty("notiType")]
474
+        public string notiType { get; set; }
475
+
476
+        [JsonProperty("projectId")]
477
+        public string projectId { get; set; }
478
+
479
+        [JsonProperty("notiId")]
480
+        public string notiId { get; set; }
481
+    }
482
+
483
+    public class Ios
484
+    {
485
+        [JsonProperty("sound")]
486
+        public string sound { get; set; }
487
+
488
+        [JsonProperty("badge")]
489
+        public string badge { get; set; }
490
+
491
+        [JsonProperty("extras")]
492
+        public Extras2 extras { get; set; }
493
+    }
494
+
495
+    public class Notification
496
+    {
497
+        [JsonProperty("alert")]
498
+        public string alert { get; set; }
499
+
500
+        [JsonProperty("android")]
501
+        public Android android { get; set; }
502
+
503
+        [JsonProperty("ios")]
504
+        public Ios ios { get; set; }
505
+    }
506
+
507
+    public class Options
508
+    {
509
+        [JsonProperty("apns_production")]
510
+        public bool apns_production { get; set; }
511
+    }
512
+
513
+
514
+    public class TempRegIdsAndAlias
515
+    {
516
+        public string RegId { get; set; }
517
+        public string Alias { get; set; }
518
+    }
519
+```

+ 1
- 0
专题/后端/2021.2.7不把本地文件修改放入暂存区.md 查看文件

@@ -0,0 +1 @@
1
+正确的做法应该是:git rm --cached logs/xx.log,然后更新 .gitignore 忽略掉目标文件,最后 git commit -m "We really don't want Git to track this anymore!"

二進制
专题/后端/ddd1.png 查看文件


二進制
专题/后端/ddd10.png 查看文件


二進制
专题/后端/ddd11.png 查看文件


二進制
专题/后端/ddd2.png 查看文件


二進制
专题/后端/ddd3.png 查看文件


二進制
专题/后端/ddd4.png 查看文件


二進制
专题/后端/ddd5.png 查看文件


二進制
专题/后端/ddd6.png 查看文件


二進制
专题/后端/ddd7.png 查看文件


二進制
专题/后端/ddd8.png 查看文件


二進制
专题/后端/ddd9.png 查看文件


二進制
专题/后端/onion.png 查看文件


二進制
团队/2020年度总结.xlsx 查看文件


+ 21
- 0
团队/2021.1.7基础设施层架构培训.md 查看文件

@@ -0,0 +1,21 @@
1
+- 领域模型:在`DD.Libs`类库中
2
+- 上下文:在`DD.Infra`类库中
3
+```
4
+--本质上上下文派生了Entity Framework Core的DbContext, 同时也实现了工作者单元接口IUnitOfWork
5
+--上下文中的DbSet对应数据库的表
6
+```
7
+- 为了完成数据库迁移,需要在`DD.OfficeBuilding.Web`项目中引入迁移所需的几个关键组件
8
+```
9
+ <PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.0" />
10
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.0">
11
+      <PrivateAssets>all</PrivateAssets>
12
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
13
+    </PackageReference>
14
+    <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.0.0-rc1.final" />
15
+    <PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design" Version="1.1.2" />
16
+```
17
+- 在`DD.OfficeBuilding.Web`项目中开始迁移
18
+```
19
+--生成迁移文件:dotnet ef migrations add initial -c DDOfficeContext
20
+--生成数据库:dotnet ef database update -c DDOfficeContext
21
+```

二進制
团队/微信图片_20210207172524.png 查看文件


+ 13
- 0
实践/安装/2021.1.12开放平台模块设置.md 查看文件

@@ -0,0 +1,13 @@
1
+- 确定上传地址:`47.103.61.198:5008/ebx-bishop/data/carry`
2
+- 确定模块号:187ED532A924
3
+- 重置模块:按着最下方的键14秒以上
4
+- 等待模块恢复正常:最上面的UART指示灯蓝灯闪烁
5
+- 释放模块热点:按着最下方的键几秒以上,直到WIFI指示灯常亮
6
+- 手机联模块热点:名称是模块号,密码是88888888
7
+- 打开"曼顿电博士",添加新电箱,电箱密码是admin
8
+- 设置模块的wifi:
9
+- 确认手机可以在局域网内控制
10
+- 确认本机的IP:192.168.8.113
11
+- 使用局域网内IP搜索工具确定模块的IP:192.168.9.126
12
+- 登录模块:192.168.9.126:82
13
+- 修改指向

+ 106
- 0
实践/安装/2021胶州开启时序数据库.md 查看文件

@@ -0,0 +1,106 @@
1
+- 准备好接收时序数据库的邮箱
2
+```
3
+https://exmail.qq.com/login
4
+darren@ddingsafe.com
5
+TecheDing2019
6
+```
7
+- 安装时序数据库
8
+```
9
+--登录网址:https://www.taosdata.com/cn/getting-started/
10
+--下载deb包
11
+--确认安装位置:/home/dingding/下载/
12
+--在下载位置打开命令行终端
13
+--开始安装:sudo dpkg -i TDengine-server-2.0.13.0-Linux-x64.deb
14
+--检查状态:sudo systemctl status taosd
15
+--启动:sudo systemctl start taosd
16
+```
17
+- 来到配置文件,查看配置:etc/taos/taos.cfg
18
+```
19
+时序数据库API地址:http://127.0.0.1:6020/rest/sql
20
+时序数据库用户名:root
21
+时序数据库密码:taosdata
22
+时序数据库名称:rlq_jiaozhou_10_12(集团编号_项目编号)
23
+```
24
+- 小试
25
+```
26
+create database db;
27
+show databases;
28
+use db;
29
+create table t(ts timestamp, cdata int);
30
+insert into t values ('2019-07-15 00:00:00');
31
+select * from t;
32
+```
33
+- 应用程序配置连接字符串
34
+```
35
+"cloudgo": "0", //云端关系数据库是否开通
36
+"shixugo": "1", //云端时序数据库是否开通
37
+"groupid": "10", //集团编号
38
+"projectid": "12", //集团项目编号
39
+  "TDegnine": {
40
+    "DataSource": "http://127.0.0.1:6041/rest/sql",
41
+    "Username": "root",
42
+    "Password": "taosdata",
43
+    "Database": "rlq_jiaozhou_10_12",
44
+    "PlanInterval": 5000,
45
+    "CDataSource": "http://47.102.145.164:6020/rest/sql",
46
+    "CUsername": "root",
47
+    "CPassword": "taosdata",
48
+    "CDatabase": "rlq_huaian_7_10"
49
+  },
50
+```
51
+- 局域网时序数据库的原理
52
+```
53
+--RealDataToTDengine,每5分钟运行一次
54
+--时序数据库
55
+--时序超级表
56
+--时序子表
57
+```
58
+
59
+- 修改RealDataToTDengine,只支持本地数据库
60
+- 修改批量创建子表:ShiXuChild
61
+- 修改创建超级表:SuperTable
62
+
63
+- 开始实施
64
+```
65
+--更新程序
66
+--更新设置,除了shixugo之外的先更新
67
+
68
+"cloudgo": "0", //云端关系数据库是否开通
69
+"shixugo": "0", //云端时序数据库是否开通
70
+"groupid": "10", //集团编号
71
+"projectid": "12", //集团项目编号
72
+  "TDegnine": {
73
+    "DataSource": "http://127.0.0.1:6041/rest/sql",
74
+    "Username": "root",
75
+    "Password": "taosdata",
76
+    "Database": "rlq_jiaozhou_10_12",
77
+    "PlanInterval": 5000,
78
+    "CDataSource": "http://47.102.145.164:6020/rest/sql",
79
+    "CUsername": "root",
80
+    "CPassword": "taosdata",
81
+    "CDatabase": "rlq_huaian_7_10"
82
+  },
83
+-- 启动程序:dotnet DD.Local.Web.dll
84
+-- 创建数据库:create database rlq_jiaozhou_10_12 KEEP 365;
85
+-- 创建超级表
86
+-- 确定超级表是否存在:show stables;
87
+-- 创建所有SuperReal的子表
88
+-- 确认子表是否创建:describe real_187ed532492c;
89
+-- 开启本地时序
90
+"cloudgo": "0", //云端关系数据库是否开通
91
+"shixugo": "1", //云端时序数据库是否开通
92
+-- 开启程序
93
+-- 验证是否成功
94
+日志:上传实时时序数据第{i}
95
+187ED532492C,187ED5329AEC,187ED53218F4,187ED53297F0,187ED53298B0,187ED5328B40,187ED5329A0C,187ED53287F8,187ED5324FAC,187ED5329C44上传实时时序数据第0次成功
96
+select * from real_187ed532492c where ts > now - 1d;
97
+select * from real_187ed5329aec where ts > now - 1d;
98
+select * from real_187ed53218f4 where ts > now - 1d;
99
+select * from real_187ed53297f0 where ts > now - 1d;
100
+select * from real_187ed53298b0 where ts > now - 1d;
101
+select * from real_187ed5328b40 where ts > now - 1d;
102
+select * from real_187ed5329a0c where ts > now - 1d;
103
+select * from real_187ed53287f8 where ts > now - 1d;
104
+select * from real_187ed5324fac where ts > now - 1d;
105
+select * from real_187ed5329c44 where ts > now - 1d;
106
+```

Loading…
取消
儲存