Browse Source

合并冲突

XW 3 years ago
parent
commit
3ba8e0771e

+ 3 - 4
TEAMModelBI/ClientApp/src/view/areaServe/areamanage.vue

@@ -436,6 +436,7 @@ export default {
     }
     //获取当前未加入区的所有学校
     function getNotjoin () {
+      loadingSchoolList.value=true
       console.log(currentlySelect.value.id)
       proxy.$api
         .getNotjoinSchool({ areaId: currentlySelect.value.id })
@@ -575,10 +576,8 @@ export default {
           if (action === 'confirm') {
             instance.confirmButtonLoading = true
             instance.confirmButtonText = 'Loading...'
-
             let data = {
-              tmdId: user.tmdId,
-              tmdName: user.tmdName,
+              areaId:currentlySelect.value.id,
               schoolId: datas.id,
               isDefault:states,
             }
@@ -1083,7 +1082,7 @@ export default {
 
 .cuttable .el-table--fit {
   width: 100%;
-  height: 58vh;
+  height: 50vh;
   overflow: auto;
 }
 

+ 19 - 5
TEAMModelBI/ClientApp/src/view/created/created.vue

@@ -735,15 +735,29 @@ export default {
                 ElMessage.success(proxy.$t(`commonMsg.batchCreatedSuccess`))
                 // batchList.value = false;
                 // batchData.value = []; 
-                // router.push({ path: '/home/schoolmanage' })
+                 router.push({ path: '/home/schoolmanage' })
             }else if(res.state ===201){
             for(let i in res.schools){
                 let ndata=res.schools[i]
-                for(let x in batchData.value){
-                    batchData.value[x].state=true
-                    ndata.name === batchData.value[x].name &&  ndata.type ===batchData.value[x].type ? batchData.value[x].state =false:''
-                }
+              let result= batchData.value.filter((item)=>{
+                return  ndata.name === item.name &&  ndata.type ===item.type
+              })
+              console.log(result)
+              if(result.length >0){
+                batchData.value[i].state =false
+              }else{
+                batchData.value[i].state =true
+              }
+                // for(let x in batchData.value){
+                //     batchData.value[x].state=true
+                //     console.log(ndata.name,batchData.value[x].name,ndata.type,batchData.value[x].type)
+                //     ndata.name === batchData.value[x].name &&  ndata.type ===batchData.value[x].type ? batchData.value[x].state=false:''
+                //     console.log(batchData.value[x].state)
+                // }
             }
+            //  batchData.value.forEach((x)=>{
+            //     x.state !==false ? x.state=true:''
+            //  })
             ElMessage.warning('部分学校已存在,请不要重新创建!')
             // batchCreatedResult.value=batchData.value
             batchCreatedSchool.value=true

File diff suppressed because it is too large
+ 2465 - 2201
TEAMModelBI/ClientApp/src/view/index/index.vue


+ 25 - 16
TEAMModelBI/ClientApp/src/view/participation/setAbility.vue

@@ -289,18 +289,15 @@
                                 </i>
                             </div>
                         </div>
-                        <div v-else-if="taskFormLabel.task[0].titles.length === 0"><span class="zw-title">{{
-                                $t(`abilityManages.practice.editPractice.nodata`)
-                        }}</span><span class="tj-title" @click="addordelegrade('add', 'excellent')">{{
-        $t(`abilityManages.practice.editPractice.add`)
-}}</span>
+                        <div v-else-if="taskFormLabel.task[0].titles.length === 0">
+                        <span class="zw-title">{{$t(`abilityManages.practice.editPractice.nodata`)}}</span>
+                        <span class="tj-title" @click="addordelegrade('add', 'excellent')">{{$t(`abilityManages.practice.editPractice.add`)}}</span>
                         </div>
                     </el-form-item>
                     <el-form-item>
                         <div class="std-title-grade">{{ $t(`abilityManages.practice.editPractice.qualified`) }}</div>
                         <!-- <div class="std-title-item" v-for="(items,index) in taskFormLabel.task[0].titles"> -->
-                        <div class="std-title-item" v-for="(items, index) in taskFormLabel.task[0].score"
-                            v-if="taskFormLabel.task[0].score.length !== 0">
+                        <div class="std-title-item" v-for="(items, index) in taskFormLabel.task[0].score"  v-if="taskFormLabel.task[0].score.length !== 0">
                             <div class="taskvalue" v-if="items.value == '2'">
                                 <span>{{ index + 1 }}.</span>
                                 <div class="content-input">
@@ -828,16 +825,26 @@ export default {
             addTask.value = false
             console.log(data, newData, '处理过后的')
         }
-        onMounted(() => {
-            console.log(store.state.point.length)
+        function init(){
             store.state.point.length
                 ? abilityProject.push(...store.state.point)
                 : proxy.$api.getCapacity({}).then((res) => {
-                    res.areas.splice(2)
+                     res.areas.splice(2)
                     abilityProject.push(...res.areas)
-                    store.commit('getPoint', res.areas)
+                    // store.commit('getPoint', res.areas)
                 })
-        })
+        }
+        // onMounted(() => {
+        //     console.log(store.state.point.length)
+        //     store.state.point.length
+        //         ? abilityProject.push(...store.state.point)
+        //         : proxy.$api.getCapacity({}).then((res) => {
+        //             res.areas.splice(2)
+        //             abilityProject.push(...res.areas)
+        //             // store.commit('getPoint', res.areas)
+        //         })
+        // })
+        init()
         watch(
             showPattern,
             (newValue) => {
@@ -893,7 +900,8 @@ export default {
             areaIds,
             NowformLabelAlign,
             showPattern,
-            redactImg
+            redactImg,
+            init
         }
     },
 }
@@ -911,6 +919,7 @@ export default {
 }
 .cardbox {
     width: 19%;
+    height:270px;
     display: inline-block;
     padding: 5px 10px;
     margin-top:10px;
@@ -1424,7 +1433,7 @@ export default {
 .cardlist-card {
     width: 100%;
     /* padding: 1%; */
-    overflow: auto;
+    overflow: hidden;
     display: flex;
     flex-wrap: wrap;
     justify-content: flex-start;
@@ -1472,7 +1481,7 @@ export default {
 .mask1{
     position: absolute;
     width: 94%;
-    height: 96%;
+    height: 98%;
     background:rgba(178, 190, 195,0.9);
     opacity: 0;
     border-radius: 15px;
@@ -1493,7 +1502,7 @@ export default {
     width:100%;
     display:flex;
     flex-wrap: wrap;
-    overflow: auto;
+    /* overflow: auto; */
 }
 @keyframes mymove {
     0% {

+ 1 - 1
TEAMModelBI/ClientApp/src/view/schoolServe/school.vue

@@ -969,7 +969,7 @@ export default {
     margin-top:5px;
 }
 .updatebtn{
-    margin-top:5%;
+    margin-top:3%;
 }
 .schoolNums,.createschools{
     display: inline-block;

+ 74 - 6
TEAMModelBI/Controllers/BIHome/AnalyseFileController.cs

@@ -1,4 +1,6 @@
-using Microsoft.AspNetCore.Hosting;
+using Azure.Storage.Blobs;
+using Azure.Storage.Blobs.Models;
+using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using System;
@@ -8,6 +10,7 @@ using System.Linq;
 using System.Text;
 using System.Text.Json;
 using System.Threading.Tasks;
+using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models.Cosmos.BI;
 
@@ -18,10 +21,12 @@ namespace TEAMModelBI.Controllers.BIHome
     public class AnalyseFileController : ControllerBase
     {
         private readonly IWebHostEnvironment _environment; //读取文件流
+        private readonly AzureStorageFactory _azureStorage;
 
-        public AnalyseFileController(IWebHostEnvironment environment) 
+        public AnalyseFileController(IWebHostEnvironment environment, AzureStorageFactory azureStorage) 
         {
             _environment = environment;
+            _azureStorage = azureStorage;
         }
 
         [HttpPost("get-visitjson")]
@@ -45,21 +50,84 @@ namespace TEAMModelBI.Controllers.BIHome
             streamReader.Close();
             string input = visits.ToString();
             List<AGInfo> aGInfos = input.ToObject<List<AGInfo>>();
+            DateTimeOffset dtime = DateTimeOffset.UtcNow;
+            string cHour = dtime.ToString("yyyyMMddHH");
+            string cDay = dtime.ToString("yyyyMMdd");
+            if (aGInfos.Count > 0) 
+            {
+                cHour = aGInfos.Select(s => DateTimeOffset.Parse(s.time).ToString("yyyyMMddHH")).First();
+                cDay = aGInfos.Select(s => DateTimeOffset.Parse(s.time).ToString("yyyyMMdd")).First();
+            }
 
+            RecCnt saveCnts = new();
             //var ipGroup = aGInfos.GroupBy(g => g.properties.clientIp).ToDictionary(k => k.Key, k => k.Count()).ToList();
 
-            List<RecGWInfo> recInfo = aGInfos.Select(s => new RecGWInfo { hour = DateTimeOffset.Parse(s.time).ToString("yyyyMMddHH"), ip = s.properties.clientIp, api = s.properties.requestUri.Split("?").ToList().Count() > 1 ? s.properties.requestUri.Split("?").ToList()[0] : s.properties.requestUri, hostName = s.properties.hostname }).ToList();
+            List<RecGWInfo> recInfo = aGInfos.Select(s => new RecGWInfo { hour = cHour, ip = s.properties.clientIp, api = s.properties.requestUri.Split("?").ToList().Count() > 1 ? s.properties.requestUri.Split("?").ToList()[0] : s.properties.requestUri, hostName = s.properties.hostname }).ToList();
+
+            List<RecApiCnt> apiCnt = recInfo.GroupBy(a => a.api).Select(g => new RecApiCnt { api = g.Key, count = g.Count(), hour = cHour, hostName = g.Select(h => h.hostName).Distinct().ToList(), ip = g.Select(i => i.ip).Distinct().ToList() }).ToList();
+            saveCnts.apiCnt= apiCnt;
 
-            var apiCnt = recInfo.GroupBy(a => a.api).Select(g => new { api = g.Key, count = g.Count(), hour = g.Select(h => h.hour).First(), hostName = g.Select(h => h.hostName).First(), ip = g.Select(i => i.ip).First() }).ToList();
+            List<RecIpCnt> ipCnt = recInfo.GroupBy(a => a.ip).Select(g => new RecIpCnt { ip = g.Key, count = g.Count(), hour = cHour, hostName = g.Select(h => h.hostName).Distinct().ToList(), api = g.Select(i => i.api).Distinct().ToList() }).ToList();
+            saveCnts.ipCnt = ipCnt;
 
+            ////保存存至Blob文件
+            var url = await _azureStorage.UploadFileByContainer("0-public", saveCnts.ToJsonString(), $"visitCnt/{cDay}", $"{cHour}.json");
+            var blob = _azureStorage.GetBlobContainerClient($"0-public");
 
-            var ipCnt = recInfo.GroupBy(a => a.ip).Select(g => new { ip = g.Key, count = g.Count(), hour = g.Select(h => h.hour).First(), hostName = g.Select(h => h.hostName).First(), api = g.Select(i => i.api).First() }).ToList();
+            List<RecCnt> recCnts = new();
+            await foreach (BlobItem blobItem in blob.GetBlobsAsync(BlobTraits.None, BlobStates.None, $"visitCnt/{cDay}"))
+            {
+
+                BlobClient blobClient = blob.GetBlobClient(blobItem.Name);
+                if (await blobClient.ExistsAsync()) 
+                {
+                    using (var meomoryStream = new MemoryStream())
+                    {
+                        var response = blob.GetBlobClient($"{blobItem.Name}").DownloadTo(meomoryStream);
+                        //var response = await blob.GetBlobClient($"{blobItem.Name}").DownloadToAsync(meomoryStream);
+
+                        var temps = meomoryStream.ToString();
+                        var temp1 = Encoding.UTF8.GetString(meomoryStream.ToArray());
+                        var temp = Encoding.UTF8.GetString(meomoryStream.ToArray()).ToObject<RecCnt>();
+
+                        RecCnt recCnt = Encoding.UTF8.GetString(meomoryStream.ToArray()).ToString().ToObject<RecCnt>();
+                        recCnts.Add(recCnt);
+                    }
+                }
+            }
 
 
-            return Ok(new { state = 200, apiCon = apiCnt.Count(), apiSum = apiCnt.Select(ap => ap.count).Sum(), ipCount = ipCnt.Count, ipSum = ipCnt.Select(ip => ip.count).Sum(), ipCnt, apiCnt }); ;
+            //var url = await _azureStorage.UploadFileByContainer("0-public", kvList.ToList().ToJsonString(), $"visitCnt/{cDay}", $"{cHour}.json");
+            return Ok(new { state = 200, recCnts,  apiCon = apiCnt.Count(), apiSum = apiCnt.Select(ap => ap.count).Sum(), ipCount = ipCnt.Count, ipSum = ipCnt.Select(ip => ip.count).Sum(), ipCnt, apiCnt }); ;
 
             //return Ok(new { state = 200, cnt = recInfo.Count, apiCon = apiCnt.Count(), apiSum = apiCnt.Select(ap=> ap.count).Sum(), ipCount = ipCnt.Count, ipSum = ipCnt.Select(ip=>ip.count).Sum(), ipCnt,apiCnt, recInfo   });;
         }
+
+        public record RecCnt
+        {
+            public List<RecApiCnt> apiCnt { get; set; }
+            public List<RecIpCnt> ipCnt { get; set; }
+        }
+
+        public record RecCntBas
+        {
+            public int count { get; set; }
+            public string hour { get; set; }
+            public List<string> hostName { get; set; }
+        }
+
+        public record RecIpCnt : RecCntBas
+        {
+            public string ip { get; set; }
+            public List<string> api { get; set; }
+        }
+
+        public record RecApiCnt : RecCntBas
+        {
+            public string api { get; set; }
+            public List<string> ip { get; set; }
+        }
+
         public record RecGWInfo
         {
             public string hour { get; set; }

+ 6 - 6
TEAMModelBI/JsonFile/Preset/LangSchoolConfig.json

@@ -2,13 +2,13 @@
     "Lang": "en-US",
     "semester": [
       {
-        "term": "Last Semester",
+        "term": "Next Semester",
         "start": 0,
         "month": 3,
         "day": 1
       },
       {
-        "term": "Next Semester",
+        "term": "Last Semester",
         "start": 1,
         "month": 9,
         "day": 1
@@ -59,13 +59,13 @@
     "Lang": "zh-CN",
     "semester": [
       {
-        "term": "学期",
+        "term": "学期",
         "start": 0,
         "month": 3,
         "day": 1
       },
       {
-        "term": "学期",
+        "term": "学期",
         "start": 1,
         "month": 9,
         "day": 1
@@ -116,13 +116,13 @@
     "Lang": "zh-TW",
     "semester": [
       {
-        "term": "學期",
+        "term": "學期",
         "start": 0,
         "month": 3,
         "day": 1
       },
       {
-        "term": "學期",
+        "term": "學期",
         "start": 1,
         "month": 9,
         "day": 1

+ 39 - 7
TEAMModelOS.SDK/Models/Cosmos/School/SchoolProduct.cs

@@ -109,25 +109,57 @@ namespace TEAMModelOS.SDK.Models
         public string model { get; set; }
     }
 
-    //服務各產品資訊購買紀錄(前端用)
+    //服務各產品資訊可用資訊(前端用)
     public class SchoolProductOrder
     {
         public string prodCode { get; set; }
-        public List<SchoolProductOrderList> order { get; set; }
         public int avaliable { get; set; }
         public long avaliableStartDate { get; set; }
         public long avaliableEndDate { get; set; }
     }
-    //產品購買紀錄(前端顯示用)
-    public class SchoolProductOrderList
+
+    //IES5 學校產品購買紀錄 前端顯示用
+    public class SchoolOrder
     {
         public string id { get; set; }
-        public long orderDate { get; set; }
-        public long startDate { get; set; }
-        public long endDate { get; set; }
+        public long date { get; set; }
+        public List<SchoolOrderSerial> serial { get; set; }
+        public List<SchoolOrderService> service { get; set; }
+        public List<SchoolOrderHard> hard { get; set; }
+    }
+    //IES5 學校產品購買紀錄 前端顯示用 序號部分
+    public class SchoolOrderSerial
+    {
+        public string prodCode { get; set; }
+        public string type { get; set; }
+        public string ymwd { get; set; }
+        public long sdate { get; set; }
+        public long edate { get; set; }
+        public int cqty { get; set; }
+        public int device { get; set; }
+        public object aprule { get; set; }
+        public List<string> sn { get; set; }
+    }
+    //IES5 學校產品購買紀錄 前端顯示用 服務部分
+    public class SchoolOrderService
+    {
+        public string prodCode { get; set; }
+        public string type { get; set; }
+        public long sdate { get; set; }
+        public long edate { get; set; }
         public int number { get; set; }
         public string unit { get; set; }
     }
+    //IES5 學校產品購買紀錄 前端顯示用 硬體部分
+    public class SchoolOrderHard
+    {
+        public string prodCode { get; set; }
+        public List<string> sn { get; set; }
+    }
+
+
+
+
 
     //序號資訊(含deviceId、classId、OS等硬體資訊)
     public class SerialInfoBaseWithdeviceBoundExt : SchoolProductSerial

+ 124 - 149
TEAMModelOS/Controllers/School/SchoolController.cs

@@ -301,6 +301,7 @@ namespace TEAMModelOS.Controllers
         /// <returns></returns>
         [ProducesDefaultResponseType]
         [HttpPost("get-school-product")]
+        [AuthToken(Roles = "admin,teacher")]
         [Authorize(Roles = "IES")]
         public async Task<IActionResult> GetSchoolProductInfo(JsonElement request)
         {
@@ -435,179 +436,154 @@ namespace TEAMModelOS.Controllers
                 }
 
                 //服務
-                long teacherSize = 0;
-                bool buySpaceFlg = false;
-                Dictionary<string, double> spaceinfo = new Dictionary<string, double>();
-                spaceinfo["student"] = 0;
-                spaceinfo["record"] = 0;
-                spaceinfo["doc"] = 0;
-                spaceinfo["video"] = 0;
-                spaceinfo["image"] = 0;
-                spaceinfo["res"] = 0;
-                spaceinfo["video"] = 0;
-                spaceinfo["audio"] = 0;
-                spaceinfo["vote"] = 0;
-                spaceinfo["survey"] = 0;
-                spaceinfo["item"] = 0;
-                spaceinfo["paper"] = 0;
-                spaceinfo["syllabus"] = 0;
-                spaceinfo["avatar"] = 0;
-                spaceinfo["record"] = 0;
-                spaceinfo["other"] = 0;
-                spaceinfo["student"] = 0;
-                spaceinfo["teacher"] = teacherSize;
-                SortedSetEntry[] Scores = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Blob:Catalog:{school_code}");
-                if (Scores != null)
+                List<SchoolProductSumDataService> service = new List<SchoolProductSumDataService>();
+                await foreach (var items in clientContainer.GetItemQueryStreamIterator(queryText: $"SELECT * FROM c WHERE c.id = '{school_code}'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"ProductSum") }))
                 {
-                    foreach (var score in Scores)
+                    using var json = await JsonDocument.ParseAsync(items.ContentStream);
+                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                     {
-                        double val = score.Score;
-                        string key = score.Element.ToString();
-                        spaceinfo[key] = val;
+                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                        {
+                            SchoolProductSum schoolProductSum = obj.ToObject<SchoolProductSum>();
+                            service = schoolProductSum.service;
+                        }
                     }
                 }
-
-
-                ////取得教師分配空間
-                var querysp = $"SELECT SUM(c.size) as size FROM c";
-                await foreach (var item in clientContainer.GetItemQueryStreamIterator(queryText: querysp, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
+                if(service.Count > 0)
                 {
-                    var jsonts = await JsonDocument.ParseAsync(item.ContentStream);
-                    foreach (var obj in jsonts.RootElement.GetProperty("Documents").EnumerateArray())
+                    foreach(SchoolProductSumDataService serviceRow in service)
                     {
-                        teacherSize = obj.GetProperty("size").GetInt64() * 1073741824;//G換算成bytes
+                        SchoolProductOrder spOrderRow = new SchoolProductOrder();
+                        spOrderRow.prodCode = serviceRow.prodCode;
+                        spOrderRow.avaliable = serviceRow.avaliable;
+                        spOrderRow.avaliableStartDate = serviceRow.startDate;
+                        spOrderRow.avaliableEndDate = serviceRow.endDate;
+                        serviceOrder.Add(spOrderRow);
                     }
                 }
-                SchoolProductSumData spaceDum = serviceSum.Where(svsum => svsum.prodCode.Equals("IPALJ6NY")).FirstOrDefault(); //取得目前學校空間可用數
-                spaceinfo["avaliable"] = (spaceDum != null) ? Convert.ToInt64(spaceDum.avaliable) * 1073741824 : 0; //G換算成bytes
-                spaceinfo["startDate"] = 0;
-                spaceinfo["endDate"] = 0;
-
-                ////取得學校空間使用狀況
-                //var blobClient = _azureStorage.GetBlobContainerClient(school_code.ToString());
-                //long? docSize = await blobClient.GetBlobsSize("doc");
-                //long? imageSize = await blobClient.GetBlobsSize("image");
-                //long? resSize = await blobClient.GetBlobsSize("res");
-                //long? videoSize = await blobClient.GetBlobsSize("video");
-                //long? audioSize = await blobClient.GetBlobsSize("audio");
-                //long? examSize = await blobClient.GetBlobsSize("exam");
-                //long? voteSize = await blobClient.GetBlobsSize("vote");
-                //long? surveySize = await blobClient.GetBlobsSize("survey");
-                //long? itemSize = await blobClient.GetBlobsSize("item");
-                //long? paperSize = await blobClient.GetBlobsSize("paper");
-                //long? syllabusSize = await blobClient.GetBlobsSize("syllabus");
-                //long? avatarSize = await blobClient.GetBlobsSize("avatar");
-                //long? recordSize = await blobClient.GetBlobsSize("records");
-                //long? otherSize = await blobClient.GetBlobsSize("other");
-                //long? studentSize = await blobClient.GetBlobsSize("student");
-                //dynamic spaceinfo = new ExpandoObject();
-                //spaceinfo.doc = docSize;
-                //spaceinfo.video = videoSize;
-                //spaceinfo.image = imageSize;
-                //spaceinfo.res = resSize;
-                //spaceinfo.video = voteSize;
-                //spaceinfo.audio = audioSize;
-                //spaceinfo.vote = voteSize;
-                //spaceinfo.survey = surveySize;
-                //spaceinfo.item = itemSize;
-                //spaceinfo.paper = paperSize;
-                //spaceinfo.syllabus = syllabusSize;
-                //spaceinfo.avatar = avatarSize;
-                //spaceinfo.record = recordSize;
-                //spaceinfo.other = otherSize;
-                //spaceinfo.student = studentSize;
-                //spaceinfo.teacher = teacherSize;
-                //SchoolProductSumData spaceDum = serviceSum.Where(svsum => svsum.prodCode.Equals("IPALJ6NY")).FirstOrDefault(); //取得目前學校空間可用數
-                //spaceinfo.avaliable = (spaceDum != null) ? Convert.ToInt64(spaceDum.avaliable) * 1073741824 : 0; //G換算成bytes
-                //spaceinfo.startDate = 0;
-                //spaceinfo.endDate = 0;
+
+                #region 產品購買履歷廢除部分
                 ////(服務)取得各產品購買履歷
-                await foreach (var itemsv in clientContainer.GetItemQueryStreamIterator(queryText: $"SELECT * FROM c WHERE c.dataType = 'service'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Product-{school_code}") }))
+                //await foreach (var itemsv in clientContainer.GetItemQueryStreamIterator(queryText: $"SELECT * FROM c WHERE c.dataType = 'service'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Product-{school_code}") }))
+                //{
+                //    using var json = await JsonDocument.ParseAsync(itemsv.ContentStream);
+                //    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                //    {
+                //        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
+                //        {
+                //            SchoolProductService serviceProductRow = obj.ToObject<SchoolProductService>();
+                //            serviceProduct.Add(serviceProductRow);
+                //        }
+                //    }
+                //}
+                ////(服務)產品購買履歷整形
+                //IEnumerable<SchoolProductService> serviceProductOrder = serviceProduct.OrderBy(sp => sp.startDate);
+                //foreach (SchoolProductService serviceProductRow in serviceProduct)
+                //{
+                //    //取得此產品現在可用數
+                //    SchoolProductSumDataService serviceSumNow = serviceSum.Where(ss => ss.prodCode.Equals(serviceProductRow.prodCode)).FirstOrDefault();
+                //    int serviceAvaliableNow = (serviceSumNow != null) ? serviceSumNow.avaliable : 0;
+                //    long serviceAvaliableStartDate = (serviceSumNow != null) ? serviceSumNow.startDate : 0;
+                //    long serviceAvaliableEndDate = (serviceSumNow != null) ? serviceSumNow.endDate : 0;
+                //    //取得此產品購買履歷
+                //    SchoolProductOrder serviceOrderNow = serviceOrder.Where(so => so.prodCode == serviceProductRow.prodCode).FirstOrDefault();
+                //    if (serviceOrderNow == null) //無此產品項
+                //    {
+                //        SchoolProductOrder serviceOrderRow = new SchoolProductOrder();
+                //        serviceOrderRow.prodCode = serviceProductRow.prodCode;
+                //        serviceOrderRow.order = new List<SchoolProductOrderList>();
+                //        SchoolProductOrderList serviceOrderRowOrderList = new SchoolProductOrderList();
+                //        serviceOrderRowOrderList.id = serviceProductRow.id;
+                //        serviceOrderRowOrderList.orderDate = serviceProductRow.orderDate;
+                //        serviceOrderRowOrderList.startDate = serviceProductRow.startDate;
+                //        serviceOrderRowOrderList.endDate = serviceProductRow.endDate;
+                //        serviceOrderRowOrderList.number = serviceProductRow.number;
+                //        serviceOrderRowOrderList.unit = serviceProductRow.unit;
+                //        serviceOrderRow.order.Add(serviceOrderRowOrderList);
+                //        serviceOrderRow.avaliable = serviceAvaliableNow;
+                //        serviceOrderRow.avaliableStartDate = serviceAvaliableStartDate;
+                //        serviceOrderRow.avaliableEndDate = serviceAvaliableEndDate;
+                //        serviceOrder.Add(serviceOrderRow);
+                //    }
+                //    else //有此產品項 => 看是否有此購買紀錄
+                //    {
+                //        //記入可用起始終止日
+                //        serviceOrderNow.avaliableStartDate = serviceAvaliableStartDate;
+                //        serviceOrderNow.avaliableEndDate = serviceAvaliableEndDate;
+                //        //記入購買紀錄
+                //        SchoolProductOrderList SchoolProductOrderListNow = serviceOrderNow.order.Where(Sol => Sol.id.Equals(serviceProductRow.id)).FirstOrDefault();
+                //        if (SchoolProductOrderListNow == null) //無此購買紀錄
+                //        {
+                //            SchoolProductOrderList serviceOrderRowOrderList = new SchoolProductOrderList();
+                //            serviceOrderRowOrderList.id = serviceProductRow.id;
+                //            serviceOrderRowOrderList.orderDate = serviceProductRow.orderDate;
+                //            serviceOrderRowOrderList.startDate = serviceProductRow.startDate;
+                //            serviceOrderRowOrderList.endDate = serviceProductRow.endDate;
+                //            serviceOrderRowOrderList.number = serviceProductRow.number;
+                //            serviceOrderRowOrderList.unit = serviceProductRow.unit;
+                //            serviceOrderNow.order.Add(serviceOrderRowOrderList);
+                //        }
+                //    }
+                //}
+                #endregion
+
+                //硬體
+                await foreach (var itemhd in clientContainer.GetItemQueryStreamIterator(queryText: $"SELECT * FROM c WHERE c.dataType = 'hard'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Product-{school_code}") }))
                 {
-                    using var json = await JsonDocument.ParseAsync(itemsv.ContentStream);
+                    using var json = await JsonDocument.ParseAsync(itemhd.ContentStream);
                     if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
                     {
                         foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
                         {
-                            SchoolProductService serviceProductRow = obj.ToObject<SchoolProductService>();
-                            serviceProduct.Add(serviceProductRow);
-                            //學校空間特別處理:取得起始結束時間
-                            if (serviceProductRow.code.Equals("IPALJ6NY"))
-                            {
-                                if (serviceProductRow.startDate < UTCNow && UTCNow < serviceProductRow.endDate)
-                                {
-                                    spaceinfo["startDate"] = serviceProductRow.startDate;
-                                    spaceinfo["endDate"] = serviceProductRow.endDate;
-                                    // spaceinfo.startDate = serviceProductRow.startDate;
-                                    //spaceinfo.endDate = serviceProductRow.endDate;
-                                }
-                            }
+                            hard.Add(obj.ToObject<SchoolProductHard>());
                         }
                     }
                 }
-                ////(服務)產品購買履歷整形
-                IEnumerable<SchoolProductService> serviceProductOrder = serviceProduct.OrderBy(sp => sp.startDate);
-                foreach (SchoolProductService serviceProductRow in serviceProduct)
+
+                //空間計算
+                ////取得教師分配空間
+                long teach = 0;
+                var querysp = $"SELECT SUM(c.size) as size FROM c";
+                await foreach (var item in clientContainer.GetItemQueryStreamIterator(queryText: querysp, requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Teacher-{school_code}") }))
                 {
-                    //取得此產品現在可用數
-                    SchoolProductSumDataService serviceSumNow = serviceSum.Where(ss => ss.prodCode.Equals(serviceProductRow.prodCode)).FirstOrDefault();
-                    int serviceAvaliableNow = (serviceSumNow != null) ? serviceSumNow.avaliable : 0;
-                    long serviceAvaliableStartDate = (serviceSumNow != null) ? serviceSumNow.startDate : 0;
-                    long serviceAvaliableEndDate = (serviceSumNow != null) ? serviceSumNow.endDate : 0;
-                    //取得此產品購買履歷
-                    SchoolProductOrder serviceOrderNow = serviceOrder.Where(so => so.prodCode == serviceProductRow.prodCode).FirstOrDefault();
-                    if (serviceOrderNow == null) //無此產品項
+                    var jsonts = await JsonDocument.ParseAsync(item.ContentStream);
+                    foreach (var obj in jsonts.RootElement.GetProperty("Documents").EnumerateArray())
                     {
-                        SchoolProductOrder serviceOrderRow = new SchoolProductOrder();
-                        serviceOrderRow.prodCode = serviceProductRow.prodCode;
-                        serviceOrderRow.order = new List<SchoolProductOrderList>();
-                        SchoolProductOrderList serviceOrderRowOrderList = new SchoolProductOrderList();
-                        serviceOrderRowOrderList.id = serviceProductRow.id;
-                        serviceOrderRowOrderList.orderDate = serviceProductRow.orderDate;
-                        serviceOrderRowOrderList.startDate = serviceProductRow.startDate;
-                        serviceOrderRowOrderList.endDate = serviceProductRow.endDate;
-                        serviceOrderRowOrderList.number = serviceProductRow.number;
-                        serviceOrderRowOrderList.unit = serviceProductRow.unit;
-                        serviceOrderRow.order.Add(serviceOrderRowOrderList);
-                        serviceOrderRow.avaliable = serviceAvaliableNow;
-                        serviceOrderRow.avaliableStartDate = serviceAvaliableStartDate;
-                        serviceOrderRow.avaliableEndDate = serviceAvaliableEndDate;
-                        serviceOrder.Add(serviceOrderRow);
+                        teach = obj.GetProperty("size").GetInt64() * 1073741824; //G換算
                     }
-                    else //有此產品項 => 看是否有此購買紀錄
+                }
+                ////學校已使用空間
+                long blobsize = 0;
+                RedisValue value = default;
+                value = _azureRedis.GetRedisClient(8).HashGet($"Blob:Record", $"{school_code}");
+                if (value != default && !value.IsNullOrEmpty)
+                {
+                    JsonElement record = value.ToString().ToObject<JsonElement>();
+                    if (record.TryGetInt64(out blobsize))
                     {
-                        //記入可用起始終止日
-                        serviceOrderNow.avaliableStartDate = serviceAvaliableStartDate;
-                        serviceOrderNow.avaliableEndDate = serviceAvaliableEndDate;
-                        //記入購買紀錄
-                        SchoolProductOrderList SchoolProductOrderListNow = serviceOrderNow.order.Where(Sol => Sol.id.Equals(serviceProductRow.id)).FirstOrDefault();
-                        if (SchoolProductOrderListNow == null) //無此購買紀錄
-                        {
-                            SchoolProductOrderList serviceOrderRowOrderList = new SchoolProductOrderList();
-                            serviceOrderRowOrderList.id = serviceProductRow.id;
-                            serviceOrderRowOrderList.orderDate = serviceProductRow.orderDate;
-                            serviceOrderRowOrderList.startDate = serviceProductRow.startDate;
-                            serviceOrderRowOrderList.endDate = serviceProductRow.endDate;
-                            serviceOrderRowOrderList.number = serviceProductRow.number;
-                            serviceOrderRowOrderList.unit = serviceProductRow.unit;
-                            serviceOrderNow.order.Add(serviceOrderRowOrderList);
-                        }
                     }
                 }
-                //硬體
-                await foreach (var itemhd in clientContainer.GetItemQueryStreamIterator(queryText: $"SELECT * FROM c WHERE c.dataType = 'hard'", requestOptions: new QueryRequestOptions() { PartitionKey = new PartitionKey($"Product-{school_code}") }))
+                ////各項空間數值取得
+                Dictionary<string, double> catalog = new Dictionary<string, double>();
+                SortedSetEntry[] Scores = _azureRedis.GetRedisClient(8).SortedSetRangeByScoreWithScores($"Blob:Catalog:{school_code}");
+                if (Scores != null)
                 {
-                    using var json = await JsonDocument.ParseAsync(itemhd.ContentStream);
-                    if (json.RootElement.TryGetProperty("_count", out JsonElement count) && count.GetUInt16() > 0)
+                    foreach (var score in Scores)
                     {
-                        foreach (var obj in json.RootElement.GetProperty("Documents").EnumerateArray())
-                        {
-                            hard.Add(obj.ToObject<SchoolProductHard>());
-                        }
+                        double val = score.Score;
+                        string key = score.Element.ToString();
+                        catalog.Add(key, val);
                     }
                 }
+                dynamic space = new ExpandoObject();
+                space.size = blobsize;
+                space.teach = teach;
+                space.catalog = catalog;
 
-                return Ok(new { serial = serialResult, service = serviceOrder, hard, spaceinfo });
+                //購買紀錄 ※DB資料未生成,先訂class 後補上
+                List<SchoolOrder> order = new List<SchoolOrder>();
+
+                return Ok(new { serial = serialResult, service = serviceOrder, hard, space, order });
             }
             catch (Exception ex)
             {
@@ -747,16 +723,15 @@ namespace TEAMModelOS.Controllers
         [ProducesDefaultResponseType]
         [HttpPost("unbind-serial")]
         [Authorize(Roles = "IES")]
+        [AuthToken(Roles = "admin,teacher")]
         public async Task<IActionResult> UnbindSerial(JsonElement request)
         {
             try
             {
                 //輸入參數
-                if (!request.TryGetProperty("id_token", out JsonElement id_token)) return BadRequest();
-                var jwt = new JwtSecurityToken(id_token.GetString());
-                var id = jwt.Payload.Sub;
-                jwt.Payload.TryGetValue("name", out object name);
                 if (!request.TryGetProperty("serial", out JsonElement serialJson)) return BadRequest();
+                var (id, name, _, _) = HttpContext.GetAuthTokenInfo(); //取得IDToken資訊
+
                 request.TryGetProperty("uuid", out JsonElement uuidJson);
                 request.TryGetProperty("uuid2", out JsonElement uuid2Json);
                 string serial = serialJson.ToString();