using Azure.Cosmos; using Azure.Messaging.ServiceBus; using Azure.Storage.Blobs.Models; using Azure.Storage.Sas; using Microsoft.Azure.Documents; using System; using System.Collections.Generic; using System.Net.Http; using System.Text; using System.Text.Json; using System.Threading.Tasks; using TEAMModelOS.SDK.DI; using TEAMModelOS.SDK.Extension; using TEAMModelOS.SDK; using TEAMModelOS.SDK.Models; using TEAMModelOS.SDK.Models.Cosmos; using TEAMModelOS.SDK.Models.Cosmos.Common; using TEAMModelOS.SDK.Models.Cosmos.Common.Inner; using TEAMModelOS.SDK.Module.AzureBlob.Configuration; using TEAMModelOS.SDK.Models.Service; using HTEXLib.COMM.Helpers; using Microsoft.Extensions.Configuration; using System.Linq; using TEAMModelOS.SDK.Models.Service.BI; using Newtonsoft.Json; namespace TEAMModelOS.FunctionV4 { public class TriggerSurvey { public static async Task Trigger(CoreAPIHttpService _coreAPIHttpService,AzureServiceBusFactory _serviceBus, AzureStorageFactory _azureStorage, DingDing _dingDing, CosmosClient client, JsonElement input, TriggerData tdata, AzureRedisFactory _azureRedis, IConfiguration _configuration) { try { if ((tdata.status != null && tdata.status.Value == 404) ) { await client.GetContainer(Constant.TEAMModelOS, "Common").DeleteItemStreamAsync(tdata.id, new PartitionKey(tdata.code)); ActivityList data = input.ToObject(); //await IESActivityService.DeleteActivity(_coreAPIHttpService, client, _dingDing, data); _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Record:{tdata.id}"); _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Submit:{tdata.id}"); var table_cancel = _azureStorage.GetCloudTableClient().GetTableReference("ChangeRecord"); List records = await table_cancel.FindListByDict(new Dictionary() { { "RowKey", tdata.id } }); foreach (var record in records) { try { await table_cancel.DeleteSingle(record.PartitionKey, record.RowKey); await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), record.sequenceNumber); } catch (Exception) { continue; } } await BIStats.SetTypeAddStats(client, _dingDing, tdata.school, "Survey", -1, careDate: tdata.startTime);//BI统计增/减量 return; } var adid = tdata.id; var adcode = ""; string blobcntr = null; if (tdata.scope.Equals("school")) { adcode = $"Activity-{tdata.school}"; blobcntr = tdata.school; } else { adcode = $"Activity-{tdata.creatorId}"; blobcntr = tdata.creatorId; } Survey survey = await client.GetContainer(Constant.TEAMModelOS, "Common").ReadItemAsync(tdata.id, new Azure.Cosmos.PartitionKey($"{tdata.code}")); if (survey != null) { var table = _azureStorage.GetCloudTableClient().GetTableReference("ChangeRecord"); string PartitionKey = string.Format("{0}{1}{2}", survey.code, "-", survey.progress); List changeRecords = await table.FindListByDict(new Dictionary() { { "RowKey", tdata.id }, { "PartitionKey", PartitionKey } }); switch (survey.progress) { case "pending": var messageSurvey = new ServiceBusMessage(new { tdata.id, progress = "going", tdata.code }.ToJsonString()); messageSurvey.ApplicationProperties.Add("name", "Survey"); if (changeRecords.Count > 0) { try { await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber); } catch (Exception) { } long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageSurvey, DateTimeOffset.FromUnixTimeMilliseconds(tdata.startTime)); changeRecords[0].sequenceNumber = start; await table.SaveOrUpdate(changeRecords[0]); } else { long start = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageSurvey, DateTimeOffset.FromUnixTimeMilliseconds(tdata.startTime)); ChangeRecord changeRecord = new() { RowKey = tdata.id, PartitionKey = PartitionKey, sequenceNumber = start, msgId = messageSurvey.MessageId }; await table.Save(changeRecord); } break; case "going": List<(string pId, List gid)> ps = new List<(string pId, List gid)>(); if (survey.groupLists.Count > 0) { var group = survey.groupLists; foreach (var gp in group) { foreach (KeyValuePair> pp in gp) { ps.Add((pp.Key, pp.Value)); } } } List classes = ExamService.getClasses(survey.classes, survey.stuLists); (List tmdIds, List classLists) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, classes, survey.school); var addStudentsCls = tmdIds.FindAll(x => x.type == 2); var addTmdidsCls = tmdIds.FindAll(x => x.type == 1); #if DEBUG await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查{tdata.id}写入学生表作为活动列表!", GroupNames.醍摩豆服務運維群組); #endif /* List stuActivities = new List(); List tmdActivities = new List(); List tchActivities = new List(); List sub = new(); if (survey.tchLists.Count == 0) { if (survey.targets.Count > 0) { foreach (var course in survey.targets) { var info = course.ToObject>(); if (info.Count > 1) { sub.Add(info[0]); } } } } if (addTmdidsCls.IsNotEmpty()) { addTmdidsCls.ForEach(x => { HashSet classIds = new HashSet(); classLists.ForEach(z => { z.members.ForEach(y => { if (y.id.Equals(x.id)&& y.type==1) { classIds.Add(z.id); } }); }); tmdActivities.Add(new StuActivity { pk = "Activity", id = survey.id, code = $"Activity-{x.id}", type = "Survey", name = survey.name, startTime = survey.startTime, endTime = survey.endTime, scode = survey.code, scope = survey.scope, school = survey.school, creatorId = survey.creatorId, subjects = sub, blob = survey.blob, owner = survey.owner, isSub = survey.isSub, createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), taskStatus = -1, classIds = classIds.ToList() }); }); } if (addStudentsCls.IsNotEmpty()) { addStudentsCls.ForEach(x => { HashSet classIds = new HashSet(); classLists.ForEach(z => { z.members.ForEach(y => { if (y.id.Equals(x.id)&& y.code.Equals(survey.school) && y.type == 2) { classIds.Add(z.id); } }); }); stuActivities.Add(new StuActivity { pk = "Activity", id = survey.id, code = $"Activity-{x.code.Replace("Base-", "")}-{x.id}", type = "Survey", name = survey.name, startTime = survey.startTime, endTime = survey.endTime, scode = survey.code, scope = survey.scope, school = survey.school, creatorId = survey.creatorId, subjects = sub, blob = survey.blob, owner = survey.owner, isSub = survey.isSub, createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), taskStatus = -1, classIds = classIds.ToList() }); }); } */ (List tchList, List classInfos) = await GroupListService.GetMemberByListids(_coreAPIHttpService, client, _dingDing, survey.tchLists, survey.school, ps); (string standard, List tmdids, string school, List update, int statistics) list = (null, null, null, new List { StatisticsService.TeacherSurvey }, 0); if (tchList.IsNotEmpty()) { list.tmdids = tchList.Select(x => x.id).ToList(); School school = null; if (!string.IsNullOrEmpty(survey.school)) { school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync(survey.school, new Azure.Cosmos.PartitionKey("Base")); list.school = school.id; list.standard = school.standard; } /* tchList.ForEach(x => { HashSet classIds = new HashSet(); classInfos.ForEach(z => { z.members.ForEach(y => { if (y.id.Equals(x.id) && y.type == 1) { classIds.Add(z.id); } }); }); tchActivities.Add(new StuActivity { pk = "Activity", id = survey.id, code = $"Activity-{x.id}", type = "Survey", name = survey.name, startTime = survey.startTime, endTime = survey.endTime, scode = survey.code, scope = survey.scope, school = survey.school, creatorId = survey.creatorId, subjects = new List { "" }, blob = survey.blob, owner = survey.owner, isSub = survey.isSub, createTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), taskStatus = -1, classIds = classIds.ToList() }); }); */ } // await IESActivityService.SaveStuActivity(client, _dingDing, stuActivities, tmdActivities, tchActivities); await StatisticsService.SendServiceBus(list, _configuration, _serviceBus, client); //向学生或醍摩豆账号发起通知 #region //Notice notice = new Notice() //{ // creation = survey.startTime, // expire = survey.endTime, // creatorId = survey.creatorId, // stuids = students, // tmdids = tmdids, // type = "notice",//问卷参加参加通知 // priority = "normal", // //data = new { }.ToJsonString() // msgId = survey.id, // school = survey.school, // scope = survey.scope, // body = new Body { sid = survey.id, scode = survey.code, spk = survey.pk, biztype = "survey-join" } //}; //var messageBlob = new ServiceBusMessage(notice.ToJsonString()); //messageBlob.ApplicationProperties.Add("name", "Notice"); //await _serviceBus.GetServiceBusClient().SendMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageBlob); #endregion #if DEBUG await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查{tdata.id}写入完成!", GroupNames.醍摩豆服務運維群組); #endif var messageSurveyEnd = new ServiceBusMessage(new { id = tdata.id, progress = "finish", code = tdata.code }.ToJsonString()); messageSurveyEnd.ApplicationProperties.Add("name", "Survey"); string pkey = string.Format("{0}{1}{2}", survey.code, "-", "pending"); await table.DeleteSingle(pkey, tdata.id); if (changeRecords.Count > 0) { long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageSurveyEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.endTime)); try { await _serviceBus.GetServiceBusClient().CancelMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), changeRecords[0].sequenceNumber); } catch (Exception) { } changeRecords[0].sequenceNumber = end; await table.SaveOrUpdate(changeRecords[0]); } else { long end = await _serviceBus.GetServiceBusClient().SendScheduleMessageAsync(Environment.GetEnvironmentVariable("Azure:ServiceBus:ActiveTask"), messageSurveyEnd, DateTimeOffset.FromUnixTimeMilliseconds(tdata.endTime)); ChangeRecord changeRecord = new ChangeRecord { RowKey = tdata.id, PartitionKey = PartitionKey, sequenceNumber = end, msgId = messageSurveyEnd.MessageId }; await table.Save(changeRecord); } #if DEBUG await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查{tdata.id}将于:{tdata.endTime}完成并结算!", GroupNames.醍摩豆服務運維群組); #endif break; case "finish": #if DEBUG await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查{tdata.id}开始结算{tdata.endTime}!", GroupNames.醍摩豆服務運維群組); #endif var records = await _azureRedis.GetRedisClient(8).HashGetAllAsync($"Survey:Record:{survey.id}"); var submits = await _azureRedis.GetRedisClient(8).SetMembersAsync($"Survey:Submit:{survey.id}"); List recs = new List(); foreach (var rcd in records) { var value = rcd.Value.ToString().ToObject(); recs.Add(new { index = rcd.Name.ToString(), ans = value }); } List userids = new List(); foreach (var submit in submits) { var value = submit.ToString(); userids.Add(value); } List questionRecords = new List(); //结算每道题的答题情况 var ContainerClient = _azureStorage.GetBlobContainerClient(blobcntr); List> tasks = new List>(); //获取 List surveyRecords = new List(); try { List items = await ContainerClient.List($"survey/{survey.id}/urecord"); foreach (string item in items) { var Download = await _azureStorage.GetBlobContainerClient(blobcntr).GetBlobClient(item).DownloadAsync(); var json = await JsonDocument.ParseAsync(Download.Value.Content); var Record = json.RootElement.ToObject(); surveyRecords.Add(Record); } #if DEBUG await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查问题结算数据{surveyRecords.ToJsonString()}", GroupNames.醍摩豆服務運維群組); #endif for (int index = 0; index < survey.answers.Count; index++) { string url = $"{survey.id}/qrecord/{index}.json"; QuestionRecord question = new QuestionRecord() { index = index }; foreach (SurveyRecord record in surveyRecords) { if (record.ans.Count == survey.answers.Count) { foreach (var an in record.ans[index]) { // if (question.opt.ContainsKey(an)) { if (question.opt[an] != null) { question.opt[an].Add(record.userid); } else { question.opt[an] = new HashSet() { record.userid }; } } else { if (survey.answers[index].Contains(an)) { //如果是客观题code question.opt.Add(an, new HashSet { record.userid }); } else { //如果不是客观code question.other[record.userid] = an; } } } } } questionRecords.Add(question); tasks.Add(_azureStorage.GetBlobContainerClient(blobcntr).UploadFileByContainer(question.ToJsonString(), "survey", url)); } await Task.WhenAll(tasks); } catch (Exception ex) { await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查问题结算异常{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組); } List answerRecords = new List(); if (questionRecords.IsNotEmpty()) { foreach (var questionRecord in questionRecords) { AnswerRecord answerRecord = new AnswerRecord(); answerRecord.index = questionRecord.index.ToString(); foreach (var opt in questionRecord.opt) { if (!answerRecord.ans.ContainsKey(opt.Key)) { answerRecord.ans[opt.Key] = 0; } answerRecord.ans[opt.Key] += opt.Value.Count; } answerRecords.Add(answerRecord); } //string resultJson = JsonConvert.SerializeObject(answerRecords, Formatting.Indented); } var cods = new { records = answerRecords, userids, question = questionRecords, urecord = surveyRecords }; //问卷整体情况 await _azureStorage.GetBlobContainerClient(blobcntr).UploadFileByContainer(cods.ToJsonString(), "survey", $"{survey.id}/record.json"); List<(string pId, List gid)> gls = new List<(string pId, List gid)>(); if (survey.groupLists.Count > 0) { var group = survey.groupLists; foreach (var gp in group) { foreach (KeyValuePair> pp in gp) { gls.Add((pp.Key, pp.Value)); } } } //处理问卷调查活动结束统计账户信息 List idsList = await GroupListService.GetFinishMemberInfo(_coreAPIHttpService, client, _dingDing, survey.school, survey.classes, survey.stuLists, survey.tchLists,gls); survey.staffIds = idsList; if (string.IsNullOrEmpty(survey.recordUrl)) { survey.recordUrl = $"/survey/{survey.id}/record.json"; await client.GetContainer(Constant.TEAMModelOS, "Common").ReplaceItemAsync(survey, survey.id, new Azure.Cosmos.PartitionKey(survey.code)); } else { _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Record:{survey.id}"); _azureRedis.GetRedisClient(8).KeyDelete($"Survey:Submit:{survey.id}"); break; } string pk = string.Format("{0}{1}{2}", survey.code, "-", "going"); await table.DeleteSingle(pk, tdata.id); //更新结束状态 //data.progress = "finish"; //if (survey.scope .Equals("school")) //{ // await client.GetContainer(Constant.TEAMModelOS, "School").ReplaceItemAsync(data, data.id, new Azure.Cosmos.PartitionKey(data.code)); //} //else if (survey.scope .Equals("private")) //{ // await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReplaceItemAsync(data, data.id, new Azure.Cosmos.PartitionKey(data.code)); //} break; } } } catch (CosmosException e) { await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}-CosmosDB异常{e.Message}\n{e.StackTrace}\n{e.Status}", GroupNames.醍摩豆服務運維群組); } catch (Exception ex) { await _dingDing.SendBotMsg($"{Environment.GetEnvironmentVariable("Option:Location")}问卷调查{ex.Message}\n{ex.StackTrace}\n", GroupNames.醍摩豆服務運維群組); } } } /** * {survey.id}/qrecord/{index}.json { "opt": { "A": [ "userid1", "userid2", "userid3" ], "B": [ "userid1", "userid2", "userid3" ] }, "other": { "userid1": "建议XXXX1", "userid2": "建议XXXX2" } } **/ }