Prechádzať zdrojové kódy

Merge branch 'develop3.0' of http://106.12.23.251:10080/TEAMMODEL/TEAMModelOS into develop3.0

李思淳 5 rokov pred
rodič
commit
d8ec5f2afd
20 zmenil súbory, kde vykonal 1415 pridanie a 599 odobranie
  1. 2 0
      TEAMModelOS.Service/Models/PowerPoint/Item.cs
  2. 1 0
      TEAMModelOS.Service/Models/PowerPoint/Shape.cs
  3. 234 37
      TEAMModelOS.Service/Services/PowerPoint/Implement/ShapeGenerator.cs
  4. 303 302
      TEAMModelOS.Service/Services/PowerPoint/Implement/ShapeSvg.cs
  5. 2 3
      TEAMModelOS/ClientApp/src/common/EmptyData.vue
  6. 3 3
      TEAMModelOS/ClientApp/src/components/syllabus/DragTree.vue
  7. 2 13
      TEAMModelOS/ClientApp/src/router/routes.js
  8. 1 1
      TEAMModelOS/ClientApp/src/view/knowledge-point/index/Index.less
  9. 7 8
      TEAMModelOS/ClientApp/src/view/knowledge-point/index/index.vue
  10. 8 3
      TEAMModelOS/ClientApp/src/view/knowledge-point/index/operation/addBlock.vue
  11. 0 2
      TEAMModelOS/ClientApp/src/view/knowledge-point/index/operation/addPoint.vue
  12. 9 2
      TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/Index.less
  13. 60 15
      TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/index.vue
  14. 171 0
      TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/AddEditors.vue
  15. 151 0
      TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/BaseKnowledge.less
  16. 88 148
      TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/BaseKnowledge.vue
  17. 166 13
      TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/BaseResource.less
  18. 195 42
      TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/BaseResource.vue
  19. 9 5
      TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/addVolume.vue
  20. 3 2
      TEAMModelOS/Startup.cs

+ 2 - 0
TEAMModelOS.Service/Models/PowerPoint/Item.cs

@@ -6,10 +6,12 @@ namespace HiTeachCC.Model.PowerPoint
 {
     public abstract class Item
     {
+        // Sp  CxnSp Media Group
         public string Type { get; set; }
         public Position Position { get; set; }
         public string Xml { get; set; }
         public int Index { get; set; }
+        public Svg Svg { get; set; }
         //public Picture Picture { get; set; }
         //public Shape Shape { get; set; }
         //public Math Math { get; set; }

+ 1 - 0
TEAMModelOS.Service/Models/PowerPoint/Shape.cs

@@ -27,6 +27,7 @@ namespace HiTeachCC.Model.PowerPoint
         public List<SvgShape> SvgShape { get; set; }
         public string Defs { get; set; }
         public string Transform { get; set; }
+        public string SvgData { get; set; }
        
     }
 

+ 234 - 37
TEAMModelOS.Service/Services/PowerPoint/Implement/ShapeGenerator.cs

@@ -12,6 +12,7 @@ using System.Xml.Linq;
 using TEAMModelOS.SDK.Context.Constant;
 using TEAMModelOS.SDK.Context.Constant.Common;
 using TEAMModelOS.SDK.Context.Exception;
+using TEAMModelOS.SDK.Helper.Common.CollectionHelper;
 using TEAMModelOS.SDK.Helper.Security.ShaHash;
 using TEAMModelOS.SDK.Module.AzureBlob.Container;
 using TEAMModelOS.SDK.Module.AzureBlob.Interfaces;
@@ -26,7 +27,7 @@ namespace HiTeachCC.Service.PowerPoint.Implement
     public class ShapeGenerator : IShapeGenerator
     {
 
-      
+
         private string fileShaCode { get; set; }
         private bool isDone = false;
         private List<object> MsgQueue = new List<object>();
@@ -280,9 +281,10 @@ namespace HiTeachCC.Service.PowerPoint.Implement
             {
                 var nodes = spTreeNode.ChildNodes;
                 int order = 1;
+                List<Item> items = new List<Item>();
                 foreach (XmlNode node in nodes)
                 {
-                    result += await ProcessNodesInSlide(node.Name, node, order, warpObj);
+                    await ProcessNodesInSlide(items, node.Name, node, order, warpObj);
                     order += 1;
                 }
             }
@@ -290,41 +292,39 @@ namespace HiTeachCC.Service.PowerPoint.Implement
             return result;
         }
 
-        public async Task<string> ProcessNodesInSlide(string nodeKey, XmlNode node, int order, WarpObj warpObj)
+        public async Task ProcessNodesInSlide(List<Item> items, string nodeKey, XmlNode node, int order, WarpObj warpObj)
         {
-            string result = "";
+            //  string result = "";
 
             switch (nodeKey)
             {
                 case "p:sp":    // Shape, Text
-                    result = await ProcessSpNode(node, order, warpObj);
+                    await ProcessSpNode(node, order, warpObj);
                     break;
                 case "p:cxnSp":    // Shape, Text (with connection)
-                    result = await ProcessCxnSpNode(node, order, warpObj);
+                    await ProcessCxnSpNode(node, order, warpObj);
                     break;
                 case "p:pic":    // Picture
-                    await ProcessPicNode(node, order, warpObj);
+                    items.Add(await ProcessPicNode(node, order, warpObj));
                     break;
                 case "p:graphicFrame":    // Chart, Diagram, Table
-                    result = ProcessGraphicFrameNode(node, order, warpObj);
+                    ProcessGraphicFrameNode(items, node, order, warpObj);
                     break;
                 case "p:grpSp":
-                    await ProcessGroupSpNode(node, order, warpObj);
+                    await ProcessGroupSpNode(items, node, order, warpObj);
                     break;
                 case "mc:AlternateContent": //Equations and formulas as Image  处理公式 方程等
                     var mcFallbackNode = node.GetTextByPath("mc:Fallback/p:sp");
-                    result = await ProcessSpNode(mcFallbackNode, order, warpObj);
+                    await ProcessSpNode(mcFallbackNode, order, warpObj);
                     break;
                 default:
                     break;
             }
-            return result;
         }
 
-        public async Task<string> ProcessGroupSpNode(XmlNode node, int order, WarpObj warpObj)
+        public async Task ProcessGroupSpNode(List<Item> items, XmlNode node, int order, WarpObj warpObj)
         {
             var factor = 1.00 * px96 / px914400;
-
             var xfrmNode = node.GetTextByPath("p:grpSpPr/a:xfrm");
             var x = int.Parse(xfrmNode.GetTextByPath("a:off/@x").Value) * factor;
             var y = int.Parse(xfrmNode.GetTextByPath("a:off/@y").Value) * factor;
@@ -334,22 +334,29 @@ namespace HiTeachCC.Service.PowerPoint.Implement
             var cy = int.Parse(xfrmNode.GetTextByPath("a:ext/@cy").Value) * factor;
             var chcx = int.Parse(xfrmNode.GetTextByPath("a:chExt/@cx").Value) * factor;
             var chcy = int.Parse(xfrmNode.GetTextByPath("a:chExt/@cy").Value) * factor;
-            string result = "<div class='block group' style='z-index: " + order + "; top: " + (y - chy) + "px; left: " + (x - chx) + "px; width: " + (cx - chcx) + "px; height: " + (cy - chcy) + "px;'>";
-
+            var rotate = ShapeHelper.AngleToDegrees(xfrmNode.GetTextByPath("@rot"));
+            string result = "<div class='block group' style='z-index: " + order + "; top: " + (y - chy) + "px; left: " + (x - chx) + "px;" +
+                " width: " + (cx - chcx) + "px; height: " + (cy - chcy) + "px;'>";
+            Group group = new Group();
+            group.Position = new Position { X = x - chx, Y = y - chy, Cx = cx - chcx, Cy = cy - chcy, Rot = rotate };
+            group.Type = "Group";
+            group.Index = order++;
             // Procsee all child nodes
             var nodes = node.ChildNodes;
+            List<Item> gpIterm = new List<Item>();
             foreach (XmlNode nd in nodes)
             {
-                result += await ProcessNodesInSlide(nd.Name, nd, order, warpObj);
+                await ProcessNodesInSlide(gpIterm, nd.Name, nd, order, warpObj);
                 order += 1;
             }
-
+            group.Shapes = gpIterm;
+            items.Add(group);
             result += "</div>";
 
-            return result;
+            //return result;
         }
 
-        public string ProcessGraphicFrameNode(XmlNode node, int order, WarpObj warpObj)
+        public string ProcessGraphicFrameNode(List<Item> items, XmlNode node, int order, WarpObj warpObj)
         {
             var result = "";
             var graphicTypeUri = node.GetTextByPath("a:graphic/a:graphicData/uri");
@@ -370,8 +377,6 @@ namespace HiTeachCC.Service.PowerPoint.Implement
                         break;
                 }
             }
-
-
             return result;
         }
 
@@ -393,10 +398,9 @@ namespace HiTeachCC.Service.PowerPoint.Implement
 
         public async Task<string> ProcessCxnSpNode(XmlNode node, int order, WarpObj warpObj)
         {
-
             var id = node.GetTextByPath("p:nvCxnSpPr/p:cNvPr/@id");
             var name = node.GetTextByPath("p:nvCxnSpPr/p:cNvPr/@name");
-            return await GenShape(node, null, null, id, name, null, null, order, warpObj);
+            return await GenShape("CxnSp", node, null, null, id, name, null, null, order, warpObj);
         }
 
         public async Task<string> ProcessSpNode(XmlNode node, int order, WarpObj warpObj)
@@ -437,12 +441,11 @@ namespace HiTeachCC.Service.PowerPoint.Implement
                     // type = getTextByPathList(slideMasterSpNode, ["p:nvSpPr", "p:nvPr", "p:ph", "attrs", "type"]);
                 }
             }
-            string s = await GenShape(node, slideLayoutSpNode, slideMasterSpNode, id, name, idx, type, order, warpObj);
-
+            string s = await GenShape("Sp", node, slideLayoutSpNode, slideMasterSpNode, id, name, idx, type, order, warpObj);
             return "";
         }
 
-        public async Task<string> GenShape(XmlNode node, XmlNode slideLayoutSpNode, XmlNode slideMasterSpNode, XmlNode id, XmlNode name, XmlNode idx, XmlNode type, int order, WarpObj warpObj)
+        public async Task<string> GenShape(string ShapeType, XmlNode node, XmlNode slideLayoutSpNode, XmlNode slideMasterSpNode, XmlNode id, XmlNode name, XmlNode idx, XmlNode type, int order, WarpObj warpObj)
         {
             var xfrmList = "p:spPr/a:xfrm";
             var slideXfrmNode = node.GetTextByPath(xfrmList);
@@ -503,8 +506,9 @@ namespace HiTeachCC.Service.PowerPoint.Implement
             var shapeBorder = ShapeHelper.GetBorder(node, true, "shape", slideLayoutClrOvride, warpObj.slideMasterContent, warpObj.themeContent);
             var headEndNodeAttrs = node.GetTextByPath("p:spPr/a:ln/a:headEnd");
             var tailEndNodeAttrs = node.GetTextByPath("p:spPr/a:ln/a:tailEnd");
-            StringBuilder svgPath = new StringBuilder("<svg class='drawing' _id='" + order + id + "' _idx='" + order + idx + "' _type='" + order + type + "' _name='" + order + name+ "'");
-            svgPath.Append(" style='top:"+position.Y+"px;left:"+position.X+ "px;width:"+position.Cx+ "px;height"+position.Cy+"px;'");
+            Svg shapeSvg = new Svg { Id = order + "", Width = position.Cx + "", Height = position.Cy + "", Top = position.X + "", Left = position.Y + "", Transform = "rotate(" + position.Rot + "deg)" };
+            StringBuilder svgPath = new StringBuilder("<svg class='drawing' _id='" + order + id + "' _idx='" + order + idx + "' _type='" + order + type + "' _name='" + order + name + "'");
+            svgPath.Append(" style='top:" + position.Y + "px;left:" + position.X + "px;width:" + position.Cx + "px;height" + position.Cy + "px;'");
             if (shapeType != null || custShapType != null)
             {
 
@@ -517,8 +521,8 @@ namespace HiTeachCC.Service.PowerPoint.Implement
                 //            "'>";
                 //result += "<defs>";
                 // Fill Color
-               
-              
+
+
                 var clrFillType = ShapeHelper.GetFillType(node.GetTextByPath("p:spPr"));
                 /////////////////////////////////////////                    
                 if (clrFillType == "GRADIENT_FILL")
@@ -528,6 +532,7 @@ namespace HiTeachCC.Service.PowerPoint.Implement
                     var angl = Fill.Rot;
 
                     var svgGrdnt = ShapeHelper.GetSvgGradient(position.Cx, position.Cy, angl, color_arry, order, slideLayoutClrOvride, warpObj.themeContent);
+                    shapeSvg.Defs = svgGrdnt;
                     //fill="url(#linGrd)"
                     Fill.SvgText = svgGrdnt;
                     result += svgGrdnt;
@@ -536,6 +541,7 @@ namespace HiTeachCC.Service.PowerPoint.Implement
                 {
                     imgFillFlg = true;
                     var svgBgImg = ShapeHelper.GetSvgImagePattern(Fill.Image, order);
+                    shapeSvg.Defs = svgBgImg;
                     //fill="url(#imgPtrn)"
                     //console.log(svgBgImg)
                     Fill.SvgText = svgBgImg;
@@ -546,6 +552,7 @@ namespace HiTeachCC.Service.PowerPoint.Implement
                     if (clrFillType != null && clrFillType != "SOLID_FILL" && clrFillType != "PATTERN_FILL")
                     {
                         Fill.HtmlText = "none";
+                        Fill.Color = "none";
                     }
                     if (shapeType != null)
                     {
@@ -556,13 +563,14 @@ namespace HiTeachCC.Service.PowerPoint.Implement
                             shapeType.Value == "leftBrace" ||
                             shapeType.Value == "rightBrace" ||
                             shapeType.Value == "rightBracket")
-                            { //Temp. solution  - TODO
-                                Fill.HtmlText = "none";
-                            }
+                        { //Temp. solution  - TODO
+                            Fill.HtmlText = "none";
+                            Fill.Color = "none";
+                        }
                     }
 
                 }
-              
+
                 // type: none, triangle, stealth, diamond, oval, arrow
 
                 if ((headEndNodeAttrs != null && (headEndNodeAttrs.GetTextByPath("@type").Value == "triangle" || (headEndNodeAttrs.GetTextByPath("@type").Value == "arrow")) ||
@@ -575,12 +583,201 @@ namespace HiTeachCC.Service.PowerPoint.Implement
                 result += "</defs>";
             }
 
-            if (shapeType != null && custShapType == null) {
-                result+= ShapeSvg.GenShapeSvg(node, order, shapeType, isFlipV, position, grndFillFlg, imgFillFlg, Fill, shapeBorder, headEndNodeAttrs, tailEndNodeAttrs);
+            if (shapeType != null && custShapType == null)
+            {
+                Svg svg = ShapeSvg.GenShapeSvg(node, order, shapeType, isFlipV, position, grndFillFlg, imgFillFlg, Fill, shapeBorder, headEndNodeAttrs, tailEndNodeAttrs);
+                shapeSvg.SvgShape = svg.SvgShape;
+                shapeSvg.SvgData = svg.SvgData;
+                if (ShapeType.Equals("Sp"))
+                {
+                    Shape  shape=  new Shape { Border = shapeBorder, Fill = Fill, Svg = shapeSvg, Type = "Sp", Position = position, Index = order, ShapeType = shapeType.Value };
+                    
+                    var txbody = node.GetTextByPath("p:txBody");
+                    if (txbody != null) {
+                        List<Paragraph> paragraphs= GenTextBody(txbody, node, slideLayoutSpNode, slideMasterSpNode, type, warpObj);
+                    }
+                   
+                }
+                else if (ShapeType.Equals("CxnSp"))
+                {
+                    new Connector { Border = shapeBorder, Svg = shapeSvg, Type = "CxnSp", Position = position, Index = order, CxnType = shapeType.Value };
+                }
+
+            }
+            else {
+
             }
+            
             return result;
         }
 
+        private List<Paragraph> GenTextBody(XmlNode textBodyNode, XmlNode node, XmlNode slideLayoutSpNode, XmlNode slideMasterSpNode, XmlNode type, WarpObj warpObj)
+        {
+            var slideMasterTextStyles = warpObj.slideMasterTextStyles;
+            string vert = GetVerticalAlign(node, slideLayoutSpNode, slideMasterSpNode);
+            var ps= textBodyNode.GetTextByPathList("a:p");
+            if (ps != null) {
+                foreach (XmlNode pNode in ps) {
+                    var rNode = pNode.GetTextByPathList("a:r");
+                    GetHorizontalAlign(pNode, slideLayoutSpNode, slideMasterSpNode, type, slideMasterTextStyles);
+                   BuChar buChar=  GenBuChar(pNode, node, slideLayoutSpNode, slideMasterSpNode, type, warpObj);
+                }
+            }
+            return null;
+        }
+
+        private BuChar GenBuChar(XmlNode node, XmlNode spNode, XmlNode slideLayoutSpNode, XmlNode slideMasterSpNode, XmlNode type, WarpObj warpObj)
+        {
+            var sldMstrTxtStyles = warpObj.slideMasterTextStyles;
+            var slideMasterContent = warpObj.slideMasterContent;
+            var themeContent = warpObj.themeContent;
+            var rNodes=  node.GetTextByPathList("a:r");
+            XmlNode rNode = null;
+            if (rNodes != null) {
+                rNode = rNodes[0];
+            }
+            XmlNode dfltBultColor, dfltBultSize, bultColor, bultSize;
+            if (rNode !=  null)
+            {
+                dfltBultColor = GetFontColorPr(rNode, spNode, type, sldMstrTxtStyles, slideMasterContent , themeContent);
+            }
+                throw new NotImplementedException();
+        }
+
+        private XmlNode GetFontColorPr(XmlNode node, XmlNode spNode, XmlNode type, XmlNode sldMstrTxtStyles , XmlNode slideMasterContent ,XmlNode themeContent)
+        {
+            var rPrNode = node.GetTextByPath("a:rPr");
+            string filTyp,  textBordr;
+            string color = null;
+            if (rPrNode != null) {
+                filTyp = ShapeHelper.GetFillType(rPrNode);
+                if (filTyp == "SOLID_FILL")
+                {
+                    var solidFillNode = node.GetTextByPath( "a:rPr/a:solidFill");
+                    string  colorstr = ShapeHelper.GetSolidFill(solidFillNode , slideLayoutClrOvride, slideMasterContent , themeContent);
+                    color =  PowerPointHelper.ColorToning(solidFillNode.OuterXml, colorstr);
+                     
+                }
+                else if (filTyp == "PATTERN_FILL")
+                {
+                    var pattFill = node.GetTextByPath("a:rPr/a:pattFill");
+                    Fill colorFill = ShapeHelper. GetPatternFill(pattFill ,slideLayoutClrOvride,slideMasterContent,themeContent);
+
+                    if (colorFill != null && colorFill.gradColor.IsNotEmpty())
+                    {
+                        color = colorFill.gradColor[0];
+                    }
+                    else {
+                        color = "000000";
+                    }
+                }
+                else
+                {
+                    var sPstyle = spNode.GetTextByPath("p:style/a:fontRef");
+                    if (sPstyle !=null)
+                    {
+                        string colorstr   = ShapeHelper.GetSolidFill(sPstyle,slideLayoutClrOvride,slideMasterContent,themeContent);
+                        color = PowerPointHelper.ColorToning(sPstyle.OuterXml, colorstr);
+                    }
+                }
+            }
+            if (color == null) {
+                color = "000000";
+            }
+            var txtBrdrNode = node.GetTextByPath("a:rPr/a:ln");
+            if (txtBrdrNode != null) {
+                var txBrd = ShapeHelper.GetBorder(node,true,"text",slideLayoutClrOvride,slideMasterContent,themeContent);
+            }
+            throw new NotImplementedException();
+        }
+
+        public string GetVerticalAlign(XmlNode node, XmlNode slideLayoutSpNode, XmlNode slideMasterSpNode ) {
+            XmlDocument doc = new XmlDocument();
+            doc.LoadXml(node.OuterXml);
+            XmlNode anchor = doc.GetTextByPath("//p:txBody/a:bodyPr/@anchor");
+            if (anchor == null)
+            {
+                if (slideLayoutSpNode != null)
+                {
+                    doc.LoadXml(slideLayoutSpNode.OuterXml);
+                    anchor = doc.GetTextByPath("//p:txBody/a:bodyPr/@anchor");
+                }
+                if (anchor == null && slideMasterSpNode != null)
+                {
+                    doc.LoadXml(slideMasterSpNode.OuterXml);
+                    anchor = doc.GetTextByPath("//p:txBody/a:bodyPr/@anchor");
+                }
+            }
+            if (anchor != null)
+            {
+                return anchor.Value.Equals("ctr") ? "v-mid" : anchor.Value.Equals("b") ? "v-down" : "v-up";
+            }
+            else
+            {
+                return "v-up";
+            }
+        }
+        public string GetHorizontalAlign(XmlNode node, XmlNode slideLayoutSpNode, XmlNode slideMasterSpNode,
+            XmlNode typeNode, XmlNode slideMasterTextStyles)
+        {
+            XmlDocument doc = new XmlDocument();
+            doc.LoadXml(node.OuterXml);
+            XmlNode algn = doc.GetTextByPath("//a:pPr/@algn");
+            if (algn == null)
+            {
+                if (slideLayoutSpNode != null)
+                {
+                    doc.LoadXml(slideLayoutSpNode.OuterXml);
+                    algn = doc.GetTextByPath("//p:txBody/a:p/a:pPr/@algn");
+                }
+
+                if (algn == null && slideMasterSpNode != null)
+                {
+                    doc.LoadXml(slideMasterSpNode.OuterXml);
+                    algn = doc.GetTextByPath("//p:txBody/a:p/a:pPr/@algn");
+                }
+                if (algn == null && typeNode != null)
+                {
+                    switch (typeNode.Value)
+                    {
+                        case "title":
+                        case "subTitle":
+                        case "ctrTitle":
+                            //doc.LoadXml(slideMasterStyle.TypeTable.OuterXml);
+                            doc.LoadXml(slideMasterTextStyles.OuterXml);
+                            algn = doc.GetTextByPath("//p:titleStyle/a:lvl1pPr/@algn");
+                            break;
+                        case "body":
+                            doc.LoadXml(slideMasterTextStyles.OuterXml);
+                            algn = doc.GetTextByPath("//p:bodyStyle/a:lvl1pPr/@algn");
+                            break;
+                        default:
+                            //  doc.LoadXml(slideMasterStyle.TypeTable.OuterXml);
+                            doc.LoadXml(slideMasterTextStyles.OuterXml);
+                            algn = doc.GetTextByPath("//p:otherStyle/a:lvl1pPr/@algn");
+                            break;
+                    }
+                }
+            }
+            if (algn == null)
+            {
+                if (typeNode == null)
+                {
+                    return "h-left";
+                }
+                if (typeNode.Value.Equals("title") || typeNode.Value.Equals("subTitle") || typeNode.Value.Equals("ctrTitle"))
+                {
+                    return "h-mid";
+                }
+                else if (typeNode.Value == "sldNum")
+                {
+                    return "h-right";
+                }
+                else if (typeNode.Value.Equals("body")) { return "h-left"; }
+            }
+            return algn.Value.Equals("ctr") ? "h-mid" : algn.Value.Equals("r") ? "h-right" : "h-left";
+        }
+
         /// <summary>
         /// 幻灯片 背景色填充
         /// </summary>
@@ -1034,7 +1231,7 @@ namespace HiTeachCC.Service.PowerPoint.Implement
         {
             var xfrmList = "p:spPr/a:xfrm";
             var xfrmNode = node.GetTextByPath(xfrmList);
-            Media media = new Media() { Type = "Pic" };
+            Media media = new Media() { Type = "Media" };
             var id = node.GetTextByPath("p:nvPicPr/p:cNvPr/@id");
             XmlNode slideLayoutSpNode = ShapeHelper.GetNodesTable(id, null, null, warpObj, "Layout");
             XmlNode slideMasterSpNode = ShapeHelper.GetNodesTable(id, null, null, warpObj, "Master");

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 303 - 302
TEAMModelOS.Service/Services/PowerPoint/Implement/ShapeSvg.cs


+ 2 - 3
TEAMModelOS/ClientApp/src/common/EmptyData.vue

@@ -1,14 +1,14 @@
 <template>
     <div class="empty-container" :style="{'margin-top':top+'px'}">
         <img src="@/assets/icon/no_data.png" width="100" />
-        <span>暂无数据</span>
+        <span :style="{'margin-top':textTop+'px'}">暂无数据</span>
     </div>
 </template>
 
 <script>
     export default {
         name: 'emptyData',
-        props: ['top'],
+        props: ['top','textTop'],
         data() {
             return {
             }
@@ -32,7 +32,6 @@
     }
 
         .empty-container span {
-            margin-top: 20px;
             font-size: 18px;
             font-weight: bold;
             color: #848484;

+ 3 - 3
TEAMModelOS/ClientApp/src/components/syllabus/DragTree.vue

@@ -34,7 +34,7 @@
 
         <!-- 关联内容弹窗 -->
         <Modal v-model="isRelatedContent" width="880" footer-hide class="tree-modal related-modal">
-            <div class="modal-header" slot="header">内容关联</div>
+            <div class="modal-header" slot="header">内容关联 ( 当前节点:{{ currentEditData ? currentEditData.title : '' }} )</div>
             <Tabs>
                 <TabPane label="资源文件" icon="md-folder">
                     <BaseResource :volume="volume" :currentNode="currentEditData"></BaseResource>
@@ -242,11 +242,11 @@
 
             .syllabus-tree-main .el-tree-node__content:hover {
                 height: 50px;
-                background: #464646;
+                background: #313131;
             }
 
         .syllabus-tree-main .el-tree-node:focus > .el-tree-node__content {
-            background: #464646;
+            background: #313131;
         }
 
         .syllabus-tree-main .el-tree__empty-block {

+ 2 - 13
TEAMModelOS/ClientApp/src/router/routes.js

@@ -122,17 +122,6 @@ export const routes = [
         component: resolve => require(['@/view/student-account/Index.vue'], resolve)
     },
 
-    // 课纲管理
-    //{
-    //    path: '/syllabus',
-    //    component: resolve => require(['@/view/syllabus/index/index.vue'], resolve)
-    //},
-
-    // 新课纲管理
-    //{
-    //    path: '/newSyllabus',
-    //    component: resolve => require(['@/view/syllabus/newSyllabus/index.vue'], resolve)
-    //},
 
     // 整合功能
     {
@@ -224,7 +213,7 @@ export const routes = [
             {
                 path: 'syllabus',
                 name: 'syllabus',
-                component: resolve => require(['@/view/syllabus/newSyllabus/index.vue'], resolve)
+                component: resolve => require(['@/view/syllabus/newSyllabus/Index.vue'], resolve)
             },
             {
                 path: 'teachcontent',
@@ -234,7 +223,7 @@ export const routes = [
             {
                 path: 'knowledge',
                 name: 'knowledge',
-                component: resolve => require(['@/view/knowledge-point/index/index.vue'], resolve)
+                component: resolve => require(['@/view/knowledge-point/index/Index.vue'], resolve)
             }
         ]
     }

+ 1 - 1
TEAMModelOS/ClientApp/src/view/knowledge-point/index/Index.less

@@ -115,7 +115,7 @@
 
             .vl {
                 .gl-item {
-                    padding: 30px 15px
+                    padding: 20px 15px
                 }
 
                 .gl-item-name {

+ 7 - 8
TEAMModelOS/ClientApp/src/view/knowledge-point/index/index.vue

@@ -48,8 +48,7 @@
                         <div :class='["gl-item","animated","slideInUp",index == activeSubjectIndex ? "item-active":""]'
                              v-for="(item,index) in subjectList"
                              :key="index"
-                             @click="hasModify ? handleConfirmSave({index},'2') : handleSubjectTap(index)"
-                             :style="{ animationDelay: ((index+1)*0.05) + 's'}">
+                             @click="hasModify ? handleConfirmSave({index},'2') : handleSubjectTap(index)">
                             <p class="gl-item-name">{{item.subjectName}}</p>
                             <p class="gl-item-info"><span></span>知识块数:{{index}}</p>
                         </div>
@@ -94,8 +93,7 @@
                             <div :class='["gl-item","animated","slideInUp",index == activeBlockIndex ? "item-active":""]'
                                  v-for="(item,index) in blockList"
                                  :key="index"
-                                 @click="handleBlockTap(index,item)"
-                                 :style="{ animationDelay: ((index+1)*0.05) + 's'}">
+                                 @click="handleBlockTap(index,item)">
                                 <p class="gl-item-name" :title="item.name">{{item.name}}</p>
                                 <p class="gl-item-info"><span></span>知识点数:{{item.points ? item.points.length : 0}}</p>
                                 <span class="btn-edit" title="编辑" @click.stop="onEditBlock(item)"><Icon type="md-create" size="20" color="#d2d2d2" /></span>
@@ -144,7 +142,7 @@
                                     <span class="btn-delete" title="删除" @click.stop="onDeletePoint(item)"><Icon type="md-trash" size="20" color="#d2d2d2" /></span>
                                 </span>
                             </div>
-                            <Page :total="pointList.length || 0"
+                            <Page :total="originPointList.length || 0"
                                   show-elevator
                                   show-sizer
                                   show-total
@@ -192,8 +190,8 @@
     import Tree from '@/components/syllabus/DragTree'
     import EmptyBox from '@/common/EmptyData'
     import Loading from '@/common/Loading'
-    import AddBlock from './operation/addBlock'
-    import AddPoint from './operation/addPoint'
+    import AddBlock from './operation/AddBlock'
+    import AddPoint from './operation/AddPoint'
 
     export default {
         data() {
@@ -373,6 +371,7 @@
                 this.currentBlock = item
                 this.isLoadPoints = true
                 setTimeout(function () {
+                    that.originPointList = item ? item.points : []
                     that.pointList = item ? item.points.slice(0, this.pageSize) : []
                     that.pageSizeChange(20)
                     that.isLoadPoints = false
@@ -497,7 +496,7 @@
                 this.isAddPoint = true // 打开新增窗口
                 this.isEditPoint = true //设置成编辑状态
                 this.editPointIndex = index
-                this.currentPoint = this.tabIndex === 0 ? null : data
+                this.currentPoint =  data
             },
 
             //搜索知识块输入框onchange事件

+ 8 - 3
TEAMModelOS/ClientApp/src/view/knowledge-point/index/operation/addBlock.vue

@@ -11,7 +11,7 @@
                 <Input v-model="formTop.name" placeholder="请输入知识块名称,必填项"></Input>
             </FormItem>
             <FormItem>
-                <Button @click="handleSubmit">确认</Button>
+                <Button @click="handleSubmit" :loading="isLoading">确认</Button>
             </FormItem>
         </Form>
     </div>
@@ -26,6 +26,7 @@
                 originDatas: {},
                 currentPeriod: {},
                 editItem: null,
+                isLoading:false,
                 uuid:"",
                 formTop: {
                     subject: '',
@@ -46,6 +47,7 @@
                 if (!newName) {
                     this.$Message.warning("知识块名称不能为空!")
                 } else {
+                    this.isLoading = true
                     this.uuid = Math.uuid()
                     let params = {
                         type: 0,
@@ -62,6 +64,7 @@
                     }
                     if (this.editItem) {
                         params.knowledgeId = this.editItem.knowledgeId
+                        params.points = this.editItem.points
                         params.id = this.editItem.id
                     }
                     this.$api.knowledge.SaveOrUpdateSchoolBlock([params]).then(res => {
@@ -70,10 +73,12 @@
                         } else {
                             this.$Message.warning("添加册别失败,错误代码:" + res.error.code + ",错误信息:" + res.error.message)
                         }
-                        this.closeModal();
-                        this.editItem = null;
+                        this.closeModal()
+                        this.editItem = null
+                        this.isLoading = false
                     }).catch(err => {
                         this.$Message.warning("添加册别失败")
+                        this.isLoading = false
                     })
                 }
             },

+ 0 - 2
TEAMModelOS/ClientApp/src/view/knowledge-point/index/operation/addPoint.vue

@@ -135,8 +135,6 @@
             addType: {
                 handler(newValue, oldValue) {
                     if (newValue) {
-                        console.log("!!!!!!!!!!")
-                        console.log(newValue)
                         this.addPointType = newValue
                     }
 

+ 9 - 2
TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/Index.less

@@ -121,7 +121,7 @@
                 }
 
                 .gl-item:hover {
-                    .btn-delete, .btn-edit {
+                    .btn-delete, .btn-edit, .btn-users {
                         display: unset;
                     }
                 }
@@ -133,12 +133,19 @@
                     display: none;
                 }
 
-                .btn-edit {
+                .btn-users {
                     position: absolute;
                     right: 60px;
                     top: 44px;
                     display: none;
                 }
+
+                .btn-edit {
+                    position: absolute;
+                    right: 90px;
+                    top: 44px;
+                    display: none;
+                }
             }
         }
 

+ 60 - 15
TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/index.vue

@@ -29,7 +29,7 @@
                             <Icon type="md-bookmark" color="#fff" size="20" />
                             <span style="margin-left:5px">学科</span>
                         </span>
-                        <Icon type="ios-search" color="#fff" size="18" style="cursor:pointer" @click="isSearchSubject = true" />
+                        <Icon type="ios-search" color="#fff" size="18" style="cursor:pointer" @click="isSearchSubject = true" v-show="subjectList.length" />
                     </div>
                     <div class="ns-header-search" v-else>
                         <Input icon="ios-close"
@@ -37,8 +37,7 @@
                                placeholder="搜索学科..."
                                autofocus
                                style="width: 100%"
-                               @on-click="isSearchSubject = false"
-                               @on-blur="isSearchSubject = false"
+                               @on-click="onSearchSubjectClose"
                                @on-change="onSearchSubjectChange"
                                @on-enter="onSearchSubjectChange" />
                     </div>
@@ -50,7 +49,7 @@
                              :key="index"
                              @click="hasModify ? handleConfirmSave({index},'2') : handleSubjectTap(index)">
                             <p class="gl-item-name">{{item.subjectName}}</p>
-                            <p class="gl-item-info"><span></span>册别数:{{index}}</p>
+                            <p class="gl-item-info"><span></span>册别数:{{ 0 }}</p>
                         </div>
                     </div>
                 </vuescroll>
@@ -67,7 +66,7 @@
                         </span>
                         <div>
                             <Icon type="md-add" color="#fff" size="18" style="cursor:pointer;margin-right:10px" @click="onAddVolume" />
-                            <Poptip title="筛选册别" placement="bottom-end" @on-popper-show="onPopperShow">
+                            <Poptip title="筛选册别" placement="bottom-end" @on-popper-show="onPopperShow" v-show="volumeList.length">
                                 <Icon type="ios-funnel" color="#fff" size="18" style="cursor:pointer;margin-right:10px" />
                                 <div class="funnel-box" slot="content">
                                     <p>年级</p>
@@ -80,7 +79,7 @@
                                     </Select>
                                 </div>
                             </Poptip>
-                            <Icon type="ios-search" color="#fff" size="18" style="cursor:pointer" @click="isSearchVolume = true" />
+                            <Icon type="ios-search" color="#fff" size="18" style="cursor:pointer" @click="isSearchVolume = true" v-show="volumeList.length" />
                         </div>
                     </div>
                     <div class="ns-header-search" v-else>
@@ -90,8 +89,7 @@
                                placeholder="搜索册别..."
                                autofocus
                                style="width: 100%"
-                               @on-click="isSearchVolume = false"
-                               @on-blur="isSearchVolume = false"
+                               @on-click="onSearchVolumeClose"
                                @on-change="onSearchVolumeChange"
                                @on-enter="onSearchVolumeChange" />
                     </div>
@@ -111,6 +109,7 @@
                                 <p class="gl-item-info">{{item.gradeName}}<span></span>{{item.semesterName}}</p>
                                 <p class="gl-item-info">共编使用者:{{item.editors ? item.editors.length : '0'}}</p>
                                 <span class="btn-edit" title="编辑" @click.stop="onEditVolume(item)"><Icon type="md-create" size="20" color="#d2d2d2" /></span>
+                                <span class="btn-users" title="共编使用者管理" @click.stop="onEditEditors(item)"><Icon type="md-people" size="22" color="#d2d2d2" /></span>
                                 <span class="btn-delete" title="删除" @click.stop="onDeleteVolume(item)"><Icon type="md-trash" size="22" color="#d2d2d2" /></span>
                             </div>
                         </div>
@@ -154,6 +153,20 @@
             </div>
         </Modal>
 
+        <!-- 共编使用者弹窗 -->
+        <Modal v-model="isEditEditors" width="560" footer-hide class="add-volume-modal">
+            <div class="modal-header" slot="header">共编使用者管理</div>
+            <div class="modal-content">
+                <AddEditors :originData="originSchoolData"
+                            :periodIndex="currentPeriodIndex"
+                            :subjectIndex="currentSubjectIndex"
+                            :addType="addType"
+                            :editVolume="editVolume"
+                            @addFinish="onFinishAddVolume">
+                </AddEditors>
+            </div>
+        </Modal>
+
     </div>
 </template>
 
@@ -161,15 +174,16 @@
     import Tree from '@/components/syllabus/DragTree'
     import EmptyBox from '@/common/EmptyData'
     import Loading from '@/common/Loading'
-    import AddVolume from './operation/addVolume'
+    import AddVolume from './operation/AddVolume'
+    import AddEditors from './operation/AddEditors'
     export default {
         data() {
             return {
-                schoolInfo: {
+                schoolInfo: { //学校基本信息
                     schoolCode: "HBCN",
                     areaCode: "86"
                 },
-                currentParams: {
+                currentParams: { //默认API传递参数
                     schoolCode: "",
                     periodCode: "",
                     subjectCode: "",
@@ -207,11 +221,12 @@
                 searchSubject: '',
                 editVolume: null,
                 hasModify: false,
-                preSelectVal:null
+                preSelectVal: null,
+                isEditEditors:false
             }
         },
         components: {
-            Tree, AddVolume, EmptyBox, Loading
+            Tree, AddVolume, EmptyBox, Loading, AddEditors
         },
         created() {
             this.initSchoolData()
@@ -246,6 +261,7 @@
                         this.volumeList = list
                         this.originVolumeList = list
                         this.handleVolumeTap(0, list.length > 0 ? list[0] : null)
+                        this.searchVolume = ""
                         setTimeout(function () {
                             that.isLoadVolumes = false
                         }, 400)
@@ -281,7 +297,7 @@
                     this.currentParams.TEAMModelId = 'habook#0001'
                 }
                 this.addType = index === 0 ? 'school' : 'private'
-                this.onPeriodChange(0)
+                this.onPeriodChange(this.currentPeriodIndex)
             },
 
             //学段切换处理
@@ -299,6 +315,7 @@
                     this.gradeList = this.periodList[index].grades //切换学段后更新 年级 列表
                     this.semesterList = this.periodList[index].semesters //切换学段后更新 学期 列表
                     this.handleSubjectTap(0)
+                    this.searchSubject = ""
                     setTimeout(function () {
                         that.isLoadSubject = false
                     }, 400)
@@ -377,6 +394,12 @@
                 this.editVolume = null
             },
 
+            // 管理共编使用者
+            onEditEditors(item) {
+                this.isEditEditors = true
+
+            },
+
             //筛选年级事件
             onFilterGrade(val) {
                 if (val === 'all' && this.filterSemester === 'all') {
@@ -411,12 +434,34 @@
             //搜索册别输入框onchange事件
             onSearchVolumeChange() {
                 this.volumeList = this.originVolumeList.filter(item => item.volumeName.indexOf(this.searchVolume) > -1);
+                if (this.volumeList.length) this.handleVolumeTap(0,this.volumeList[0]) // 获取筛选后的第一个册别课纲数据
+            },
+
+            // 清空科目搜索框
+            onSearchSubjectClose() {
+                this.searchSubject = ""
+                this.isSearchSubject = false
+                this.subjectList = this.originSubjectList
+                this.handleSubjectTap(0)
+            },
+
+            // 清空册别搜索框
+            onSearchVolumeClose() {
+                this.searchVolume = ""
+                this.isSearchVolume = false
+                this.volumeList = this.originVolumeList
+                this.handleVolumeTap(0,this.volumeList[0])
             },
 
             //搜索学科输入框onchange事件
             onSearchSubjectChange() {
                 this.subjectList = this.originSubjectList.filter(item => item.subjectName.indexOf(this.searchSubject) > -1);
-                this.handleSubjectTap(0)
+                if (this.subjectList.length) {
+                    this.handleSubjectTap(0)
+                } else {
+                    this.volumeList = []
+                    this.treeData = []
+                } 
             },
 
             //显示后添加全部选项

+ 171 - 0
TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/AddEditors.vue

@@ -0,0 +1,171 @@
+
+<template>
+    <div class="form-container">
+        
+    </div>
+</template>
+
+<script>
+    export default {
+        props: ['originData', 'periodIndex','subjectIndex','editVolume','addType'],
+        data() {
+            return {
+                originDatas: {},
+                currentPeriod: {},
+                editItem: {},
+                addVolumeType: 'school',
+                isLoading:false,
+                formTop: {
+                    subject: '',
+                    grade: '',
+                    semester: '',
+                    volume: ''
+                }
+            }
+        },
+
+        created() {
+
+        },
+        methods: {
+            // 提交添加
+            handleSubmit() {
+                this.isLoading = true
+                let params = {
+                    type: this.addVolumeType === 'school' ? 0 : 1,
+                    schoolCode: this.originDatas.schoolCode,
+                    periodCode: this.currentPeriod.periodCode,
+                    subjectCode: this.formTop.subject,
+                    gradeCode: this.formTop.grade,
+                    semesterCode: this.formTop.semester,
+                    volumeName: this.getNewVolumeName(),
+                    status: 1
+                }
+                if (this.editItem) {
+                    params.id = this.editItem.id
+                    params.volumeCode = this.editItem.volumeCode
+                }
+                if (this.addVolumeType === 'private') {
+                    params.TEAMModelId = 'habook#0001'
+                }
+                this.$api.syllabus.SaveOrUpdateVolume(params).then(res => {
+                    if (!res.error && res.result.data) {
+                        this.$emit('addFinish',res.result.data.id)
+                    } else {
+                        this.$Message.warning("操作失败,错误代码:" + res.error.code + ",错误信息:"  + res.error.message)
+                    }
+                    this.isLoading = false
+                    this.closeModal();
+                    this.editItem = {};
+                }).catch(err => {
+                    this.$Message.warning("操作失败")
+                    this.isLoading = false
+                })
+            },
+
+            // 获取新册别名称
+            getNewVolumeName() {
+                if (this.formTop.volume) {
+                    return this.formTop.volume
+                } else {
+                    let subject = this.currentPeriod.subjects[this.subjectIndex].subjectName
+                    let grade = this.currentPeriod.grades.filter(item => item.gradeCode === this.formTop.grade)[0].gradeName
+                    let semester = this.currentPeriod.semesters.filter(item => item.semesterCode === this.formTop.semester)[0].semesterName
+                    return subject + grade + semester
+                }
+            },
+
+            //添加完成 关闭窗口
+            closeModal() {
+                this.$emit('addFinish', false)
+                this.formTop.volume = ''
+            }
+        },
+        mounted() {
+        },
+        watch: {
+            addType: {
+                handler(newValue, oldValue) {
+                    if (newValue) {
+                        this.addVolumeType = newValue
+                    }
+                },
+            },
+            originData: {
+                handler(newValue, oldValue) {
+                    this.originDatas = newValue
+                },
+            },
+            periodIndex: {
+                handler(newValue, oldValue) {
+                    this.currentPeriod = this.originDatas.period[newValue]
+                    this.formTop.subject = this.currentPeriod.subjects[0].subjectCode
+                    this.formTop.grade = this.currentPeriod.grades[0].gradeCode
+                    this.formTop.semester = this.currentPeriod.semesters[0].semesterCode
+                    this.formTop.volume = ""
+                },
+            },
+            subjectIndex: {
+                handler(newValue, oldValue) {
+                    this.formTop.subject = this.currentPeriod.subjects[newValue].subjectCode
+                },
+            },
+            editVolume: {
+                handler(newValue, oldValue) {
+                    if (newValue) {  // 有编辑册别传过来则为编辑状态
+                        this.editItem = newValue
+                        this.formTop.subject = newValue.subjectCode
+                        this.formTop.grade = newValue.gradeCode
+                        this.formTop.semester = newValue.semesterCode
+                        this.formTop.volume = newValue.volumeName
+                    } else { //否则为新增状态
+                        this.formTop.subject = this.currentPeriod.subjects[0].subjectCode
+                        this.formTop.grade = this.currentPeriod.grades[0].gradeCode
+                        this.formTop.semester = this.currentPeriod.semesters[0].semesterCode
+                        this.formTop.volume = ""
+                        this.editItem = newValue
+                    }
+                    
+                },
+            }
+        },
+
+    }
+</script>
+
+<style>
+    .form-container .ivu-form .ivu-form-item-label {
+        color: #fff;
+        margin:10px 0;
+        font-size:16px;
+    }
+
+    .form-container .ivu-input {
+        background: #575757;
+        border-color: transparent;
+        height: 35px;
+        color:#fff;
+    }
+    .form-container .ivu-input::-webkit-input-placeholder {
+        color:#808080;
+    }
+
+    .form-container .ivu-select-single .ivu-select-selection {
+        background: #575757;
+        color: #fbfbfb;
+        border-color: transparent;
+        height: 35px;
+    }
+
+    .form-container .ivu-select-single .ivu-select-arrow {
+        color: #fbfbfb;
+    }
+
+    .form-container .ivu-btn {
+        width: 100%;
+        height: 40px;
+        background: rgb(11, 151, 117);
+        border: none;
+        color:#fff;
+    }
+</style>

+ 151 - 0
TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/BaseKnowledge.less

@@ -0,0 +1,151 @@
+.knowledge-container {
+    width: 100%;
+    height: 100%;
+    background: #464646;
+    border-radius: 4px;
+    overflow: hidden;
+
+
+    .select-wrap {
+        width: 100%;
+        height: 60%;
+
+        .ns-header-search {
+            width: 400px;
+            margin-right: 15px;
+        }
+
+        .wrap-title {
+            display: flex;
+            justify-content: space-between;
+
+            .ivu-icon {
+                margin-right: 15px;
+                font-size: 22px;
+            }
+        }
+    }
+
+    .select-content {
+        display: flex;
+        height: 320px;
+        border-top: 1px solid #565656;
+        border-bottom: 1px solid #565656;
+    }
+
+    .show-wrap {
+        width: 100%;
+        height: auto;
+
+        .checked-point-item {
+            padding: 5px 20px;
+            color: #fff;
+            background: #6d6d6d;
+            margin: 10px;
+            border-radius: 50px;
+            display: inline-block;
+            cursor: pointer;
+        }
+    }
+
+    .point-box {
+        padding: 30px 10px;
+        border-top: 1px solid #565656;
+        color: #fff;
+        display: flex;
+        flex-wrap: wrap;
+
+
+        .checked-point-item {
+            padding: 5px 20px;
+            color: #fff;
+            background: #6d6d6d;
+            margin: 10px;
+            border-radius: 50px;
+            display: inline-block;
+            cursor: pointer;
+        }
+    }
+
+
+    .wrap-title {
+        position: relative;
+        font-size: 16px;
+        font-weight: bold;
+        color: #fff;
+        width: 100%;
+        height: 50px;
+        line-height: 50px;
+        padding-left: 20px;
+        background: #525252;
+        display: flex;
+        justify-content: space-between;
+
+        .wrap-btns {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+        }
+
+        .ivu-btn {
+            height: 30px;
+            margin-right: 15px;
+            background: #0f9272;
+            color: #fff;
+            border: none;
+        }
+    }
+
+
+    .knowledge-left {
+        width: 18%;
+        border-right: 1px solid #565656;
+
+        .knowledge-left-item {
+            width: 100%;
+            height: 20%;
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            color: #fff;
+            font-size: 14px;
+            font-weight: bold;
+            border-bottom: 1px solid #565656;
+            cursor: pointer;
+        }
+
+        .item-active {
+            background: #0f9272;
+        }
+    }
+
+
+    .knowledge-right {
+        width: 82%;
+        height: 100%;
+        padding: 0 0 0 20px;
+        overflow: hidden;
+
+        .knowledge-box {
+            padding: 10px;
+            color: #fff;
+            display: flex;
+            flex-wrap: wrap;
+
+            .knowledge-item {
+                margin: 10px;
+                width: 190px;
+                height: 120px;
+                overflow: hidden;
+                display: flex;
+                flex-direction: column;
+                justify-content: center;
+                align-items: center;
+                background: #545454;
+                box-shadow: 11px 11px 5px #383838;
+                border-radius: 3px;
+                cursor: pointer;
+            }
+        }
+    }
+}

+ 88 - 148
TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/BaseKnowledge.vue

@@ -1,9 +1,13 @@
-
+<style lang="less" scoped>
+    @import './BaseKnowledge.less';
+</style>
 <template>
     <div class="knowledge-container">
         <vuescroll>
             <div class="select-wrap">
-                <p class="wrap-title">选择知识点</p>
+                <p class="wrap-title">
+                    <span>选择知识点</span>
+                </p>
                 <div class="select-content">
                     <div class="knowledge-left">
                         <div :class='["knowledge-left-item",activeIndex === 0 ? "item-active" : ""]' @click="onChangeOrigin(0)">校本知识块</div>
@@ -18,8 +22,9 @@
                                      node-key="id"
                                      ref="elTree"
                                      show-checkbox
+                                     check-on-click-node
                                      default-expand-all
-                                     @check-change="handleCheckChange">
+                                     @check="handleCheckChange">
                                 <span class="custom-tree-node" slot-scope="{ node, data }">
                                     <span>{{data.name}}</span>
                                 </span>
@@ -30,14 +35,20 @@
             </div>
             <div class="show-wrap">
                 <div class="wrap-title">
-                    已选知识点
-                    <Button @click="onSaveNode" v-show="hasModify" :loading="isLoading">存储变更</Button>
+                    <span>已选知识点<span v-if="currentNodeInfo">  ( {{ checkedPoints.length }} )</span></span>
+                    <div class="wrap-btns">
+                        <Button @click="onClearChecked" v-show="checkedPoints.length">清空</Button>
+                        <Button @click="onSaveNode" v-show="hasModify" :loading="isLoading">存储变更</Button>
+                    </div>
                 </div>
                 <div v-if="checkedPoints.length === 0">
                     <EmptyBox :top="10"></EmptyBox>
                 </div>
                 <div class="point-box" v-else>
-                    <span class="checked-point-item" v-for="(item,index) in checkedPoints" :key="index">{{item.name}}</span>
+                    <span class="checked-point-item" v-for="(item,index) in checkedPoints" :key="index">
+                        <span>{{item.name}}</span>
+                        <Icon type="ios-close" size="20" style="vertical-align:bottom;margin-left:5px" @click="onSplicePoint(item)"/>
+                    </span>
                 </div>
             </div>
         </vuescroll>
@@ -54,17 +65,17 @@
             return {
                 currentVolume: null,
                 currentNodeInfo: null,
-                currentParams:null,
+                currentParams: null,
                 activeIndex: 0,
                 checkedPoints: [],
-                originPoints:[],
+                originPoints: [],
                 treeData: [],
                 defaultProps: {
                     children: 'points',
                     label: 'name'
                 },
                 hasModify: false,
-                isLoading:false
+                isLoading: false
 
             }
         },
@@ -77,8 +88,6 @@
                 schoolCode: this.currentVolume.schoolCode,
                 period: this.currentVolume.periodCode
             }
-            console.log(this.currentParams.subjectCode)
-            console.log(this.currentParams.subjectCode)
             this.getSchoolBlocks()
         },
         methods: {
@@ -95,6 +104,10 @@
                     default:
                         break
                 }
+
+                // 切换数据源时 检测当前已选项 是否要设置选中状态
+                this.$refs.elTree.setCheckedKeys(this.checkedPoints.map(item => item.id),true)
+
             },
 
             //获取校本知识块
@@ -102,6 +115,7 @@
                 this.$api.knowledge.GetSchoolBlocks({ PointParams: this.currentParams }).then(res => {
                     if (!res.error && res.result.data) {
                         let list = res.result.data
+                        list.forEach(item => { item.disabled = true }) //知识块 层级 不能被关联
                         this.treeData = list
                     } else {
                         this.$Message.warning("获取数据失败")
@@ -122,11 +136,19 @@
             },
 
             // 节点复选框被点击时事件
-            handleCheckChange() {
-                this.checkedPoints = this.$refs.elTree.getCheckedNodes(true)
+            handleCheckChange(data) {
+
+                const isExistIndex = this.checkedPoints.map(item => item.id).indexOf(data.id)
+                if (isExistIndex > -1) {
+                    this.checkedPoints.splice(isExistIndex, 1)
+                } else {
+                    this.checkedPoints.push(data)
+                }
                 this.hasModify = !(this.isEqual(this.checkedPoints, this.originPoints))
+
             },
 
+            /** 保存知识点关联 */
             onSaveNode() {
                 this.isLoading = true
                 this.currentNodeInfo.knowledges = this.checkedPoints.map(item => item.id)
@@ -138,7 +160,21 @@
                         this.$Message.warning("获取数据失败")
                     }
                 })
-                
+            },
+
+            /**
+             * 删除已选项
+             * @param item 已选项数据
+             */
+            onSplicePoint(item) {
+                this.checkedPoints.splice(this.checkedPoints.indexOf(item), 1)
+                this.onChangeOrigin(this.activeIndex)
+            },
+
+            /** 清空已选项 */
+            onClearChecked() {
+                this.checkedPoints = []
+                this.onChangeOrigin(this.activeIndex)
             },
 
             // 判断两个数组是否相等
@@ -152,7 +188,7 @@
                 let params = {
                     collectionName: 'SchoolPoint',
                     queryDict: {
-                        id:arr
+                        id: arr
                     }
                 }
                 this.$api.syllabus.FindCollection(params).then(res => {
@@ -182,17 +218,18 @@
                     }
                     this.getSchoolBlocks()
                 },
-                deep:true
+                deep: true
             },
             // 监听册别数据变化
             currentNode: {
                 handler: function (n, o) {
                     this.currentNodeInfo = n
+                    this.checkedPoints = []
                     this.onChangeOrigin(0)
-                    this.getPointObject(n.knowledges) // 用ID换知识点对象数据
+                    //this.getPointObject(n.knowledges) // 用ID换知识点对象数据
                     this.hasModify = false
                 },
-                deep:true
+                deep: true
             },
 
         },
@@ -200,160 +237,63 @@
     }
 </script>
 
-<style scoped>
-    .knowledge-container {
-        width: 100%;
-        height: 100%;
-        background: #464646;
-        border-radius:4px;
-        overflow:hidden;
-    }
-
-        .knowledge-container .select-wrap {
-            width:100%;
-            height:60%;
-        }
-
-        .knowledge-container .select-content {
-            display:flex;
-            height:320px;
-            border-top:1px solid #565656;
-            border-bottom:1px solid #565656;
-        }
-
-        .knowledge-container .show-wrap{
-            width:100%;
-            height:auto;
-        }
-
-        .knowledge-container .point-box {
-            padding:30px 10px;
-            height:300px;
-            border-top:1px solid #565656;
-            border-bottom:1px solid #565656;
-
-
-        }
-            .knowledge-container .show-wrap .checked-point-item {
-                padding:5px 20px;
-                color:#fff;
-                background:#6d6d6d;
-                margin:10px;
-                border-radius:50px;
-                display:inline-block;
-                cursor:pointer;
-            }
-
-        .knowledge-container .wrap-title {
-            position:relative;
-            font-size:16px;
-            font-weight:bold;
-            color:#fff;
-            width:100%;
-            height:50px;
-            line-height:50px;
-            padding-left:20px;
-            background:#525252;
-        }
-
-            .knowledge-container .wrap-title .ivu-btn {
-                position:absolute;
-                right:20px;
-                top:10px;
-                width:100px;
-                height:30px;
-                background:#0f9272;
-                color:#fff;
-                border:none;
-             }
-
-    .knowledge-left {
-        width: 18%;
-        border-right: 1px solid #565656;
+<style>
+    .knowledge-container .__view {
+        min-height: unset !important;
     }
 
-        .knowledge-left .knowledge-left-item {
-            width: 100%;
-            height: 25%;
-            display:flex;
-            justify-content:center;
-            align-items:center;
-            color: #fff;
-            font-size: 14px;
-            font-weight: bold;
-            border-bottom: 1px solid #565656;
-            cursor: pointer;
-        }
-
-        .knowledge-left .item-active {
-            background:#0f9272;
-        }
-
-    .knowledge-right {
-        width:82%;
-        height:100%;
-        padding:0 10px 0 20px;
-        overflow:hidden;
+    .knowledge-container .__bar-is-vertical {
+        background: transparent !important;
     }
 
-
-
-    .knowledge-container /deep/ .__view {
-        min-height:unset !important;
-    }
-    
-    .knowledge-container /deep/ .__bar-is-vertical {
-        background:transparent !important;
+    .knowledge-container .knowledge-right .__bar-is-vertical {
+        background: #777676 !important;
     }
 
 
-    .knowledge-container /deep/ .ivu-checkbox-checked .ivu-checkbox-inner,
-    .knowledge-container /deep/ .ivu-checkbox-indeterminate .ivu-checkbox-inner {
+    .knowledge-container .ivu-checkbox-checked .ivu-checkbox-inner,
+    .knowledge-container .ivu-checkbox-indeterminate .ivu-checkbox-inner {
         border-color: #0f9272;
         background: #0f9272;
     }
 
-    .knowledge-container /deep/ .ivu-tree-title-selected,
-    .knowledge-container /deep/ .ivu-tree-title-selected:hover,
-    .knowledge-container /deep/ .ivu-tree-title:hover {
-        background:transparent;
+    .knowledge-container .ivu-tree-title-selected,
+    .knowledge-container .ivu-tree-title-selected:hover,
+    .knowledge-container .ivu-tree-title:hover {
+        background: transparent;
     }
 
     .knowledge-container .el-tree {
-            background: transparent;
-            color: #fff;
-            padding-top: 10px;
-            padding-bottom: 100px;
-        }
-
-        .knowledge-container .el-tree-node__content {
-            height: 50px;
-        }
+        background: transparent;
+        color: #fff;
+        padding-top: 10px;
+        padding-bottom: 100px;
+    }
 
-            .knowledge-container .el-tree-node__content:hover {
-                height: 50px;
-                background: #464646;
-            }
+    .knowledge-container .el-tree-node__content {
+        height: 40px;
+    }
 
-        .knowledge-container .el-tree-node:focus > .el-tree-node__content {
+        .knowledge-container .el-tree-node__content:hover {
+            height: 40px;
             background: #464646;
         }
 
-        .knowledge-container .el-tree__empty-block {
-            display: none;
-        }
+    .knowledge-container .el-tree-node:focus > .el-tree-node__content {
+        background: #464646;
+    }
 
-    .knowledge-container /deep/ .el-tree-node__content {
-        height:36px;
+    .knowledge-container .el-tree__empty-block {
+        display: none;
     }
 
-    .knowledge-container /deep/ .el-tree-node__content:hover,
-    .knowledge-container /deep/ .el-tree-node:focus>.el-tree-node__content{
-        background:#565656;
+    .knowledge-container .el-tree-node__content:hover,
+    .knowledge-container .el-tree-node:focus > .el-tree-node__content {
+        background: #565656;
     }
 
-    .knowledge-container /deep/ .el-checkbox__input.is-checked .el-checkbox__inner,
-    .knowledge-container /deep/ .el-checkbox__input.is-indeterminate .el-checkbox__inner {
+    .knowledge-container .el-checkbox__input.is-checked .el-checkbox__inner,
+    .knowledge-container .el-checkbox__input.is-indeterminate .el-checkbox__inner {
         border-color: #0f9272;
         background: #0f9272;
     }

+ 166 - 13
TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/BaseResource.less

@@ -9,6 +9,21 @@
     .select-wrap {
         width: 100%;
         height: 60%;
+
+        .ns-header-search {
+            width: 400px;
+            margin-right: 15px;
+        }
+
+        .wrap-title {
+            display: flex;
+            justify-content: space-between;
+
+            .ivu-icon {
+                margin-right: 15px;
+                font-size: 22px;
+            }
+        }
     }
 
     .select-content {
@@ -34,10 +49,69 @@
     }
 
     .point-box {
-        padding: 30px 10px;
-        height: 300px;
+        padding: 30px 10px 80px 10px;
         border-top: 1px solid #565656;
         border-bottom: 1px solid #565656;
+        color: #fff;
+        display: flex;
+        flex-wrap: wrap;
+        min-height: 300px;
+
+        .resource-item {
+            margin: 10px;
+            width: 180px;
+            height: 120px;
+            overflow: hidden;
+            display: flex;
+            flex-direction: column;
+            justify-content: center;
+            align-items: center;
+            background: #545454;
+            box-shadow: 11px 11px 5px #383838;
+            border-radius: 3px;
+            cursor: pointer;
+
+
+
+            .resource-item-img {
+                margin: 0 30px;
+                position: relative;
+
+                .icon-close {
+                    position: absolute;
+                    right: -50px;
+                    top: -10px;
+                    font-size: 20px;
+                    color: #a7a7a7;
+                }
+            }
+
+            &-name {
+                width: 80%;
+
+                .file-name {
+                    display: inline-block;
+                    width: 150px;
+                    margin-top: 5px;
+                    text-align: center;
+                    overflow: hidden;
+                    text-overflow: ellipsis;
+                    white-space: nowrap;
+                }
+            }
+
+            .file-info {
+
+                p {
+                    white-space: normal;
+                    word-break: break-all;
+                    color: #6d6d6d;
+
+                    span {
+                    }
+                }
+            }
+        }
     }
 
 
@@ -51,13 +125,18 @@
         line-height: 50px;
         padding-left: 20px;
         background: #525252;
+        display: flex;
+        justify-content: space-between;
+
+        .wrap-btns {
+            display: flex;
+            justify-content: center;
+            align-items: center;
+        }
 
         .ivu-btn {
-            position: absolute;
-            right: 20px;
-            top: 10px;
-            width: 100px;
             height: 30px;
+            margin-right: 15px;
             background: #0f9272;
             color: #fff;
             border: none;
@@ -91,7 +170,7 @@
     .resource-right {
         width: 82%;
         height: 100%;
-        padding: 0 10px 0 20px;
+        padding: 0 0 0 20px;
         overflow: hidden;
 
         .resource-box {
@@ -103,27 +182,101 @@
             .resource-item {
                 margin: 10px;
                 width: 190px;
-                height: 100px;
+                height: 120px;
                 overflow: hidden;
                 display: flex;
                 flex-direction: column;
                 justify-content: center;
                 align-items: center;
-                border: 1px solid #fff;
-                cursor:pointer;
+                background: #545454;
+                box-shadow: 11px 11px 5px #383838;
+                border-radius: 3px;
+                cursor: pointer;
 
                 &-name {
-                    width:80%;
+                    width: 80%;
+
+                    .file-name {
+                        display: inline-block;
+                        width: 150px;
+                        margin-top: 5px;
+                        text-align: center;
+                        overflow: hidden;
+                        text-overflow: ellipsis;
+                        white-space: nowrap;
+                    }
+                }
+
+                .file-info {
 
                     p {
+                        white-space: normal;
+                        word-break: break-all;
+                        color: #6d6d6d;
+
+                        span {
+                        }
+                    }
+                }
+            }
+        }
+
+        .resource-box-list {
+            padding: 10px;
+            color: #fff;
+            display: flex;
+            flex-direction: column;
+            flex-wrap: wrap;
+
+            .resource-item-list {
+                margin: 10px;
+                width: 95%;
+                height: 80px;
+                overflow: hidden;
+                display: flex;
+                flex-direction: row;
+                align-items: center;
+                background: #545454;
+                box-shadow: 11px 11px 5px #383838;
+                border-radius: 3px;
+                cursor: pointer;
+
+                .resource-item-img {
+                    margin: 0 30px;
+                    position: relative;
+
+                    .icon-close {
+                        position: absolute;
+                        right: 0;
+                        top: 0;
+                    }
+                }
+
+                &-name {
+                    width: 80%;
+
+                    .file-name {
                         display: inline-block;
-                        width: 100%;
-                        text-align:center;
+                        width: 150px;
+                        margin-top: 5px;
+                        text-align: center;
                         overflow: hidden;
                         text-overflow: ellipsis;
                         white-space: nowrap;
                     }
                 }
+
+                .file-info {
+
+                    p {
+                        white-space: normal;
+                        word-break: break-all;
+                        color: #6d6d6d;
+
+                        span {
+                        }
+                    }
+                }
             }
         }
     }

+ 195 - 42
TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/BaseResource.vue

@@ -6,46 +6,102 @@
     <div class="resource-container">
         <vuescroll>
             <div class="select-wrap">
-                <p class="wrap-title">选择资源文件</p>
+                <div class="wrap-title">
+                    <span>选择资源文件<span v-if="currentNodeInfo">  ( {{ resourceList.length }} )</span></span>
+                    <div>
+                        <div class="select-wrap-header" v-if="!isSearchFile">
+                            <Icon type="ios-menu" title="切换显示样式" style="cursor:pointer" v-show="isShowBlocks" @click="onChangeShowType('1')" />
+                            <Icon type="ios-keypad" title="切换显示样式" style="cursor:pointer" v-show="!isShowBlocks" @click="onChangeShowType('0')" />
+                            <Icon type="ios-search" title="搜索" style="cursor:pointer" @click="isSearchFile = true" />
+                        </div>
+                        <div class="ns-header-search" v-else>
+                            <!-- 搜索册别部分 -->
+                            <Input icon="ios-close"
+                                   v-model="searchFile"
+                                   placeholder="搜索册别..."
+                                   autofocus
+                                   style="width: 100%"
+                                   @on-click="isSearchFile = false"
+                                   @on-blur="isSearchFile = false"
+                                   @on-change="onSearchFileChange"
+                                   @on-enter="onSearchFileChange" />
+                        </div>
+                    </div>
+                </div>
                 <div class="select-content">
                     <div class="resource-left">
                         <div :class='["resource-left-item",activeIndex === 0 ? "item-active" : ""]' @click="onChangeOrigin(0)">全部</div>
                         <div :class='["resource-left-item",activeIndex === 1 ? "item-active" : ""]' @click="onChangeOrigin(1)">图片</div>
                         <div :class='["resource-left-item",activeIndex === 2 ? "item-active" : ""]' @click="onChangeOrigin(2)">视频</div>
                         <div :class='["resource-left-item",activeIndex === 3 ? "item-active" : ""]' @click="onChangeOrigin(3)">文档</div>
-                        <div :class='["resource-left-item",activeIndex === 3 ? "item-active" : ""]' @click="onChangeOrigin(3)">其他</div>
+                        <div :class='["resource-left-item",activeIndex === 4 ? "item-active" : ""]' @click="onChangeOrigin(4)">其他</div>
                     </div>
                     <div class="resource-right">
                         <vuescroll>
-                           <div class="resource-box">
-                               <div class="resource-item"  v-for="(item,index) in resourceList" :key="index">
-                                   <div class="resource-item-img">
-                                       <img v-if="item.extension === 'ppt'" src="@/assets/icon/ppt50.png" width="40" />
-                                       <img v-else-if="item.extension === 'doc'" src="@/assets/icon/word50.png" width="40" />
-                                       <img v-else-if="item.extension === 'xlsx'" src="@/assets/icon/xls50.png" width="40" />
-                                       <img v-else-if="item.type === 'picture'" src="@/assets/icon/icon_img.png" width="40" />
-                                       <img v-else-if="item.type === 'video4'" src="@/assets/icon/icon_video.png" width="40" />
-                                       <img v-else src="@/assets/icon/prelearn50.png" width="40" />
-                                   </div>
-                                   <div class="resource-item-name">
-                                       <p>{{ item.fileName }}</p>
-                                   </div>
-                               </div>
-                           </div>
+                            <div :class="isShowBlocks ? 'resource-box':'resource-box-list'">
+                                <div :class="isShowBlocks ? 'resource-item' : 'resource-item-list'"
+                                     v-for="(item,index) in resourceList" :key="index"
+                                     @click="onFileSelect(item)"
+                                     :style="{backgroundColor:checkedList.indexOf(item) > -1 ? '#0f9272' : '#545454'}">
+                                    <div class="resource-item-img">
+                                        <img v-if="item.extension === 'ppt'||item.extension === 'pptx'" src="@/assets/icon/ppt50.png" width="40" />
+                                        <img v-else-if="item.extension === 'doc'||item.extension === 'docx'" src="@/assets/icon/word50.png" width="40" />
+                                        <img v-else-if="item.extension === 'xls'||item.extension === 'xlsx'" src="@/assets/icon/xls50.png" width="40" />
+                                        <img v-else-if="item.type === 'picture'" src="@/assets/icon/icon_img.png" width="40" />
+                                        <img v-else-if="item.type === 'video'" src="@/assets/icon/icon_video.png" width="40" />
+                                        <img v-else-if="item.extension === 'rar'" src="@/assets/icon/zip50.png" width="40" />
+                                        <img v-else src="@/assets/icon/prelearn50.png" width="40" />
+                                    </div>
+                                    <div class="resource-item-name">
+                                        <Tooltip>
+                                            <p class="file-name">{{ item.fileName }}</p>
+                                            <div slot="content" class="file-info">
+                                                <p><span>文件名:</span>{{item.fileName}}</p>
+                                                <p><span>大小:</span>{{item.size/1204 > 1024 ? (item.size/1204/1204).toFixed(1) + 'M': (item.size/1204).toFixed(1) + 'KB'}}</p>
+                                                <p><span>上传时间:</span>{{new Date(item.createTime/10000).toLocaleString()}}</p>
+                                            </div>
+                                        </Tooltip>
+                                    </div>
+                                </div>
+                            </div>
                         </vuescroll>
                     </div>
                 </div>
             </div>
             <div class="show-wrap">
                 <div class="wrap-title">
-                    已选资源
-                    <Button @click="onSaveNode" v-show="hasModify" :loading="isLoading">存储变更</Button>
+                    <span>已选资源<span v-if="currentNodeInfo">  ( {{ checkedList.length }} )</span></span>
+                    <div class="wrap-btns">
+                        <Button @click="onClearChecked" v-show="checkedList.length">清空</Button>
+                        <Button @click="onSaveResources" v-show="hasModify" :loading="isLoading">存储变更</Button>
+                    </div>
                 </div>
-                <div v-if="resourceList.length === 0">
+                <div v-if="checkedList.length === 0">
                     <EmptyBox :top="10"></EmptyBox>
                 </div>
                 <div class="point-box" v-else>
-                    <span class="checked-point-item" v-for="(item,index) in resourceList" :key="index">{{item.fileName}}</span>
+                    <div class="resource-item" v-for="(item,index) in checkedList" :key="index">
+                        <div class="resource-item-img">
+                            <img v-if="item.extension === 'ppt'||item.extension === 'pptx'" src="@/assets/icon/ppt50.png" width="40" />
+                            <img v-else-if="item.extension === 'doc'||item.extension === 'docx'" src="@/assets/icon/word50.png" width="40" />
+                            <img v-else-if="item.extension === 'xls'||item.extension === 'xlsx'" src="@/assets/icon/xls50.png" width="40" />
+                            <img v-else-if="item.type === 'picture'" src="@/assets/icon/icon_img.png" width="40" />
+                            <img v-else-if="item.type === 'video'" src="@/assets/icon/icon_video.png" width="40" />
+                            <img v-else-if="item.extension === 'rar'" src="@/assets/icon/zip50.png" width="40" />
+                            <img v-else src="@/assets/icon/prelearn50.png" width="40" />
+                            <Icon type="md-close" class="icon-close" @click="onSpliceFile(file)"/>
+                        </div>
+                        <div class="resource-item-name">
+                            <Tooltip>
+                                <p class="file-name">{{ item.fileName }}</p>
+                                <div slot="content" class="file-info">
+                                    <p><span>文件名:</span>{{item.fileName}}</p>
+                                    <p><span>大小:</span>{{item.size/1204 > 1024 ? (item.size/1204/1204).toFixed(1) + 'M': (item.size/1204).toFixed(1) + 'KB'}}</p>
+                                    <p><span>上传时间:</span>{{new Date(item.createTime/10000).toLocaleString()}}</p>
+                                </div>
+                            </Tooltip>
+                        </div>
+                    </div>
                 </div>
             </div>
         </vuescroll>
@@ -65,14 +121,20 @@
                 currentParams: null,
                 activeIndex: 0,
                 resourceList: [],
-                originList:[],
+                searchList: [],
+                originList: [],
                 treeData: [],
+                checkedList: [],
+                originResourcesList: [],
                 defaultProps: {
                     children: 'points',
                     label: 'name'
                 },
                 hasModify: false,
-                isLoading: false
+                isLoading: false,
+                searchFile: "",
+                isSearchFile: false,
+                isShowBlocks: false
 
             }
         },
@@ -89,24 +151,37 @@
             this.getResourceData('private')
         },
         methods: {
-            //切换知识点数据来源
+
+            /** 切换知识点数据来源 */
             onChangeOrigin(index) {
                 this.activeIndex = index;
                 switch (index) {
                     case 0:
-                        this.getSchoolBlocks()
+                        this.resourceList = this.originList
                         break
                     case 1:
-                        this.getSchoolPoints()
+                        this.resourceList = this.originList.filter(item => item.type === 'picture')
+                        break
+                    case 2:
+                        this.resourceList = this.originList.filter(item => item.type === 'video')
+                        break
+                    case 3:
+                        this.resourceList = this.originList.filter(item => item.type === 'document')
+                        break
+                    case 4:
+                        this.resourceList = this.originList.filter(item => item.type === 'other')
                         break
                     default:
                         break
                 }
+
+                this.searchList = this.resourceList
             },
 
+            /** 根据类型获取资源数据 */
             getResourceData(type) {
                 let params = {
-                    range : type
+                    range: type
                 }
                 this.$api.teachContent.findResourceByDict(params).then(res => {
                     if (!res.error && res.result.data) {
@@ -116,32 +191,76 @@
                         this.$Message.warning("获取数据失败")
                     }
                 })
+            },
 
 
+            /** 改变显示视图 */
+            onChangeShowType(type) {
+                this.isShowBlocks = type === '0'
             },
 
 
-            onSaveNode() {
+            /**
+             * 文件点击事件
+             * @param item 文件数据
+             */
+            onFileSelect(item) {
+                const isExistIndex = this.checkedList.indexOf(item)
+                if (isExistIndex > -1) {
+                    this.checkedList.splice(isExistIndex, 1)
+                } else {
+                    this.checkedList.push(item)
+                }
+                this.hasModify = !(this.isEqual(this.checkedList, this.originResourcesList))
+            },
+
+            /** 清空已选项 */
+            onClearChecked() {
+                this.checkedList = []
+            },
+
+            /**
+             * 移除已选项
+             * @param file
+             */
+            onSpliceFile(file) {
+                this.checkedList.splice(this.checkedList.indexOf(file), 1)
+            },
+
+            /** 搜索资源文件事件 */
+            onSearchFileChange() {
+                this.resourceList = this.searchList.filter(item => item.fileName.indexOf(this.searchFile) > -1);
+            },
+
+            /** 保存关联资源文件 */
+            onSaveResources() {
                 this.isLoading = true
-                this.currentNodeInfo.resources = this.checkedPoints.map(item => item.id)
-                this.$api.syllabus.SaveOrUpdateAsNodes([this.currentNodeInfo]).then(res => {
-                    if (!res.error && res.result.data) {
-                        this.$emit("addPointsFinish", res.result.data)
-                        this.isLoading = false
-                    } else {
-                        this.$Message.warning("获取数据失败")
-                    }
-                })
+                this.currentNodeInfo.resources = this.checkedList.map(item => item.id)
+                //this.$api.syllabus.SaveOrUpdateAsNodes([this.currentNodeInfo]).then(res => {
+                //    if (!res.error && res.result.data) {
+                //        this.$emit("addPointsFinish", res.result.data)
+                //        this.isLoading = false
+                //    } else {
+                //        this.$Message.warning("获取数据失败")
+                //    }
+                //})
 
             },
 
-            // 判断两个数组是否相等
+            /**
+             * 判断两个数组是否相等
+             * @param arr1
+             * @param arr2
+             */
             isEqual(arr1, arr2) {
                 return (JSON.stringify(arr1) === JSON.stringify(arr2))
             },
 
 
-            // 获取知识点完整对象数据 ID换对象
+            /**
+             * 获取知识点完整对象数据 ID换对象
+             * @param arr 原始ID数组
+             */
             getPointObject(arr) {
                 let params = {
                     collectionName: 'SchoolPoint',
@@ -181,8 +300,10 @@
             currentNode: {
                 handler: function (n, o) {
                     this.currentNodeInfo = n
+                    this.checkedList = []
                     this.onChangeOrigin(0)
-                    this.getPointObject(n.resources) // 用ID换知识点对象数据
+                    this.originResourcesList = n.resources
+                    //this.getPointObject(n.resources) // 用ID换知识点对象数据
                     this.hasModify = false
                 },
                 deep: true
@@ -194,7 +315,7 @@
 </script>
 
 <style>
- 
+
     .resource-container .__view {
         min-height: unset !important;
     }
@@ -203,5 +324,37 @@
         background: transparent !important;
     }
 
- 
+
+    .resource-container .resource-right .__bar-is-vertical {
+        background: #777676 !important;
+    }
+
+    .resource-container .ivu-tooltip-inner {
+        background: #fff;
+        padding: 15px;
+        color: #808080;
+    }
+
+    .resource-container .ivu-tooltip-popper[x-placement^=bottom] .ivu-tooltip-arrow {
+        border-bottom-color: #fff;
+    }
+
+    .resource-container .ivu-input {
+        background: #656565;
+        color: #fff;
+        border: none;
+        height: 34px;
+    }
+
+        .resource-container .ivu-input:focus {
+            border: none;
+            box-shadow: none;
+        }
+
+    .resource-container .ivu-input-icon {
+        font-size: 24px;
+        color: #cfc7c7;
+        line-height: 36px;
+        cursor: pointer;
+    }
 </style>

+ 9 - 5
TEAMModelOS/ClientApp/src/view/syllabus/newSyllabus/operation/addVolume.vue

@@ -21,7 +21,7 @@
                 <Input v-model="formTop.volume" placeholder="非必填,默认由年级+科目+学期组成..."></Input>
             </FormItem>
             <FormItem>
-                <Button @click="handleSubmit">确认</Button>
+                <Button @click="handleSubmit" :loading="isLoading">确认</Button>
             </FormItem>
         </Form>
     </div>
@@ -35,7 +35,8 @@
                 originDatas: {},
                 currentPeriod: {},
                 editItem: {},
-                addVolumeType:'school',
+                addVolumeType: 'school',
+                isLoading:false,
                 formTop: {
                     subject: '',
                     grade: '',
@@ -51,11 +52,12 @@
         methods: {
             // 提交添加
             handleSubmit() {
+                this.isLoading = true
                 let params = {
                     type: this.addVolumeType === 'school' ? 0 : 1,
                     schoolCode: this.originDatas.schoolCode,
                     periodCode: this.currentPeriod.periodCode,
-                    subjectCode: this.currentPeriod.subjects[this.subjectIndex].subjectCode,
+                    subjectCode: this.formTop.subject,
                     gradeCode: this.formTop.grade,
                     semesterCode: this.formTop.semester,
                     volumeName: this.getNewVolumeName(),
@@ -72,12 +74,14 @@
                     if (!res.error && res.result.data) {
                         this.$emit('addFinish',res.result.data.id)
                     } else {
-                        this.$Message.warning("添加册别失败,错误代码:" + res.error.code + ",错误信息:"  + res.error.message)
+                        this.$Message.warning("操作失败,错误代码:" + res.error.code + ",错误信息:"  + res.error.message)
                     }
+                    this.isLoading = false
                     this.closeModal();
                     this.editItem = {};
                 }).catch(err => {
-                     this.$Message.warning("添加册别失败")
+                    this.$Message.warning("操作失败")
+                    this.isLoading = false
                 })
             },
 

+ 3 - 2
TEAMModelOS/Startup.cs

@@ -11,11 +11,13 @@ using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Http.Features;
+using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.SpaServices;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
 using Microsoft.IdentityModel.Tokens;
+using Newtonsoft.Json;
 using TEAMModelOS.SDK.Context.Attributes.Azure;
 using TEAMModelOS.SDK.Context.Configuration;
 using TEAMModelOS.SDK.Context.Filter;
@@ -96,7 +98,7 @@ namespace TEAMModelOS
             //    });
             //});
             services.AddMemoryCache();
-            services.AddControllers().AddNewtonsoftJson();
+            services.AddControllers().AddNewtonsoftJson().AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = true; });
             //上传文件最大处理
             services.Configure<FormOptions>(x =>
             {   x.BufferBodyLengthLimit= long.MaxValue;
@@ -105,7 +107,6 @@ namespace TEAMModelOS
                 x.MultipartHeadersLengthLimit = int.MaxValue;
             });
 
-
             // Table配置
             services.AddScoped<IAzureTableDBRepository, AzureTableDBRepository>();
             //使用Blob配置