Browse Source

解决冲突

hbchen 1 year ago
parent
commit
aaede10b16

+ 1 - 0
package.json

@@ -28,6 +28,7 @@
     "crypto-js": "^3.1.9-1",
     "dependencies": "^0.0.1",
     "dll": "^0.2.0",
+    "drag-tree-table": "^2.2.0",
     "element-resize-detector": "^1.2.2",
     "element-ui": "2.13.0",
     "font-awesome": "^4.7.0",

+ 5 - 1
src/api/api.js

@@ -73,6 +73,9 @@ import {reportVarietyENInterence} from './modules/reportVariety'
 //商家管理
 import {businessCustomInterence} from './modules/businessCustom'
 
+//帮助中心
+import {assistanceDocInterence} from './modules/assistanceDoc'
+
 export {
   dataBaseInterface,
   mychartInterface,
@@ -110,7 +113,8 @@ export {
   cloudDiskInterface,
   businessTripInterence,
   reportVarietyENInterence,
-  businessCustomInterence
+  businessCustomInterence,
+  assistanceDocInterence
 };
 
 //老接口 研报 ppt等

+ 105 - 0
src/api/modules/assistanceDoc.js

@@ -0,0 +1,105 @@
+/**
+ * 帮助中心api
+ */
+import http from "@/api/http.js"
+
+export const assistanceDocInterence = {
+    /**
+     * 获取文章列表
+     * @param Keyword String 文章标题
+     * @param PageSize number 每页数据条数
+     * @param CurrentIndex number 当前页面
+     * @param ClassifyId number 分类id
+     * @returns 
+     */
+    getAssistanceDocList:(params)=>{
+      return http.get('/help_doc/list',params)
+    },
+    /**
+     * 新增文章
+     * @param ClassifyId number 分类Id
+     * @param Title string 题目
+     * @param Author string 作者
+     * @param Status number 1
+     * @param Content string 正文
+     * @param AnchorData array 锚点数组
+     * @param AnchorData[0].AnchorId string 锚点Id
+     * @param AnchorData[0].Anchor string 锚点名称
+     * @param AnchorData[0].Child array 子锚点数组
+     */
+    addAssistanceDoc:(params)=>{
+      return http.post('/help_doc/add',params)
+    },
+    /**
+     * 文章详情
+     * @param DocId string 文章Id
+     */
+    getAssistanceDoc:(params)=>{
+      return http.get('/help_doc/detail',params)
+    },
+    /**
+     * 文章发布/取消发布
+     * @param DocId number 文章Id
+     * @param Status number 状态
+     */
+    assistanceDocPublish:(params)=>{
+      return http.post('/help_doc/publish',params)
+    },
+    /**
+     * 文章发布/取消发布
+     * @param DocId number 文章Id
+     */
+    assistanceDocDelete:(params)=>{
+      return http.post('/help_doc/delete',params)
+    },
+    /**
+     * 获取分类列表
+     * @param Keyword String分类名称
+     * @returns 
+     */
+    getAssistanceClassifyList:(params)=>{
+      return http.get('/help_doc/classify/list',params)
+    },
+    /**
+     * 新增分类
+     * @param ParentId number 父节点Id
+     * @param HelpDocClassifyName string 添加的目录名称
+     */
+    addAssistanceClassify:(params)=>{
+      return http.post('/help_doc/classify/add',params)
+    },
+    /**
+     * 编辑分类
+     * @param HelpDocClassifyId number 节点Id
+     * @param ParentId number 父节点Id
+     * @param HelpDocClassifyName string 添加的目录名称
+     */
+    editAssistanceClassify:(params)=>{
+      return http.post('/help_doc/classify/edit',params)
+    },
+    /**
+     * 修改分类可见权限
+     * @param HelpDocClassifyId number 文章Id
+     * @param VisibleBusinessIds number 商家Id 多选 ,拼接
+     */
+    editAssistanceClassifyVisible:(params)=>{
+      return http.post('help_doc/classify/visible/edit',params)
+    },
+    /**
+     * 删除分类
+     * @param ClassifyId number 节点Id
+     */
+    deleteAssistanceClassify:(params)=>{
+      return http.get('/help_doc/classify/delete',params)
+    },
+    /**
+     * 移动分类
+     * @param ClassifyId number 节点Id
+     * @param ParentClassifyId number 父节点Id
+     * @param PrevClassifyId number 上一个节点Id 没有为0
+     * @param NextClassifyId number 下一个节点Id 没有为0
+     */
+    moveAssistanceClassify:(params)=>{
+      return http.post('/help_doc/classify/move',params)
+    },
+}

+ 2 - 0
src/main.js

@@ -35,6 +35,8 @@ require('froala-editor/css/froala_style.min.css');
 // Import Froala Editor css files.
 import 'froala-editor/css/froala_editor.pkgd.min.css';
 import 'froala-editor/css/plugins/quick_insert.css';
+// froala-editor 预览时的样式,如需使用在展示富文本的节点上加上 .fr-view 的类
+import 'froala-editor/css/froala_style.min.css'
 
 // Import and use Vue Froala lib.
 import VueFroala from 'vue-froala-wysiwyg';

+ 61 - 5
src/routes/modules/operateRoutes.js

@@ -8,8 +8,8 @@ export default [
 		name: '运营管理',
 		hidden: false,
 		icon_path: require('@/assets/img/home/custom_ico.png'),
-        children:[
-            {
+		children:[
+			{
 				path:'daynews',
 				component:()=> import('@/views/report_manage/dayilyNews.vue'),
 				name:'每日资讯',
@@ -49,7 +49,7 @@ export default [
 				name: '留言管理员',
 				hidden: false,
 			},
-            {
+			{
 				path:"voiceManage",
 				component: () => import('@/views/system_manage/voiceManage.vue'),
 				name: '语音播报管理',
@@ -61,6 +61,62 @@ export default [
 				name: '更新日志配置',
 				hidden: false,
 			},
-        ]
-    }
+			{
+				path:"assistanceCenter",
+				component: () => import('@/views/system_manage/assistance_center/assistanceCenter.vue'),
+				name: '帮助中心配置',
+				hidden: false,
+			},
+			{
+				path:"assistanceDocDetail",
+				component: () => import('@/views/system_manage/assistance_center/assistanceDocDetail.vue'),
+				name: '查看文章',
+				hidden: true,
+				meta: {
+					pathFrom: 'assistanceCenter',
+					pathName: '帮助中心配置'
+				}
+			},
+			{
+				path:"assistanceDocAdd",
+				component: () => import('@/views/system_manage/assistance_center/assistanceDocAdd.vue'),
+				name: '添加文章',
+				hidden: true,
+				meta: {
+					pathFrom: 'assistanceCenter',
+					pathName: '帮助中心配置'
+				}
+			},
+			{
+				path:"assistanceDocEdit",
+				component: () => import('@/views/system_manage/assistance_center/assistanceDocAdd.vue'),
+				name: '编辑文章',
+				hidden: true,
+				meta: {
+					pathFrom: 'assistanceCenter',
+					pathName: '帮助中心配置'
+				}
+			},
+			{
+				path:"assistanceDocEdit",
+				component: () => import('@/views/system_manage/assistance_center/assistanceDocAdd.vue'),
+				name: '编辑文章',
+				hidden: true,
+				meta: {
+					pathFrom: 'assistanceCenter',
+					pathName: '帮助中心配置'
+				}
+			},
+			{
+				path:"docClassifyManage",
+				component: () => import('@/views/system_manage/assistance_center/docClassifyManage.vue'),
+				name: '分类管理',
+				hidden: true,
+				meta: {
+					pathFrom: 'assistanceCenter',
+					pathName: '帮助中心配置'
+				}
+			},
+		]
+	}
 ]

+ 1 - 1
src/styles/index.scss

@@ -28,4 +28,4 @@ $color_green:#67C23A;
   border-radius: 5px;
   color: #3994fb;
   background-color: #dcecfc;
-}
+}

+ 209 - 0
src/views/system_manage/assistance_center/assistanceCenter.vue

@@ -0,0 +1,209 @@
+<template>
+  <div class="assistance-center-container">
+    <div class="assistance-center-top-zone">
+      <div class="assistance-center-top-operation">
+        <el-button type="primary" @click="addDocument">添加文章</el-button>
+        <el-button type="primary" @click="classifyManage" style="margin-left: 20px;">分类管理</el-button>
+      </div>
+      <div class="assistance-center-top-search">
+        <el-cascader
+          :options="classifyList"
+          collapse-tags
+          clearable
+          :props="{
+            multiple:true,
+            value:'ClassifyId',
+            label:'ClassifyName',
+            children:'Children',
+            emitPath:false
+          }"
+          placeholder="所属分类"
+          @change="handlSearchClassify"
+        />
+        <el-input placeholder="文章标题" v-model="queryParams.KeyWord" clearable @input="getDocumentList"
+        style="width:500px;margin-left: 20px;">
+				  <i slot="prefix" class="el-input__icon el-icon-search"></i>
+			  </el-input>
+      </div>
+    </div>
+    <el-table ref="documentTable" :data="documentList" border class="document-table">
+      <el-table-column prop="Title" label="文章标题" align="center">
+        <template slot-scope="scope">
+          <span @click="goDetail(scope.row)" class="document-title">{{scope.row.Title}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="ClassifyName" label="所属分类" align="center">
+        <template slot-scope="scope"> <span>{{scope.row.ClassifyName}}</span> </template>
+      </el-table-column>
+      <el-table-column prop="Author" label="文章作者" align="center">
+        <template slot-scope="scope"> <span>{{scope.row.Author}}</span> </template>
+      </el-table-column>
+      <el-table-column prop="Status" label="发布状态" align="center">
+        <template slot-scope="scope"> 
+          <span :style="{color:scope.row.Status==2?'#4FB112':'#F56C6C'}">{{scope.row.Status==2?"已发布":"未发布"}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="CreateTime" label="创建时间" align="center">
+        <template slot-scope="scope"> <span>{{scope.row.CreateTime}}</span> </template>
+      </el-table-column>
+      <el-table-column prop="ModifyTime" label="更新时间" align="center">
+        <template slot-scope="scope"> <span>{{scope.row.ModifyTime}}</span> </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" min-width="110" v-if="Role!='admin'">
+        <template slot-scope="scope">
+          <div style="color:#4099ef;">
+            <span style="margin-right:10px;cursor: pointer;" @click="publish(scope.row)" v-if="scope.row.Status==2">取消发布</span>
+            <template v-if="scope.row.Status==1">
+              <span style="margin-right:10px;cursor: pointer;" @click="editDocument(scope.row)">编辑</span>
+              <span style="margin-right:10px;cursor: pointer;" @click="publish(scope.row)">发布</span>
+            </template>
+            <span style="color: #F56C6C;cursor: pointer;" @click="deleteDocument(scope.row)">删除</span>
+          </div>
+        </template>
+      </el-table-column>
+      <div slot="empty" style="lineHeight:44px;margin:60px 0;color:#999;">
+        <img src="~@/assets/img/cus_m/nodata.png" style="display:block;width:160px;height:128px;margin: auto;">
+        <span>暂无数据</span>
+      </div>
+    </el-table>
+    <!-- 页数选择器 -->
+    <m-page :page_no="queryParams.CurrentIndex" :pageSize="queryParams.PageSize"
+    :total="total" style="position: absolute;right: 40px;bottom: 40px;" @handleCurrentChange="pageChange"
+    />
+  </div>
+</template>
+
+<script>
+import mPage from '@/components/mPage.vue';
+import { assistanceDocInterence } from '../../../api/modules/assistanceDoc';
+
+  export default {
+    name:"assistanceCenter",
+    components:{mPage},
+    data() {
+      return {
+        classifyList:[],
+        documentList:[],
+        ClassifyIdList:[],
+        queryParams:{
+          CurrentIndex:1,
+          PageSize:10,
+          ClassifyIds:"",
+          KeyWord:""
+        },
+        total:100
+      }
+    },
+    created(){
+      this.getClassifyList()
+      this.getDocumentList()
+    },
+    methods: {
+      getClassifyList(){
+        assistanceDocInterence.getAssistanceClassifyList().then(res=>{
+          if(res.Ret == 200){
+            this.classifyList = res.Data?res.Data.AllNodes||[]:[]
+          }
+        })
+      },
+      getDocumentList(){
+        assistanceDocInterence.getAssistanceDocList(this.queryParams).then(res=>{
+          if(res.Ret == 200){
+            this.documentList=res.Data.List || []
+            this.total = res.Data.Paging.Totals || 0
+          }
+        })
+      },
+      handlSearchClassify(value){
+        // console.log(value);
+        this.queryParams.ClassifyIds = value.join(',')
+        this.getDocumentList()
+      },
+      pageChange(page_no){
+        this.queryParams.CurrentIndex=page_no
+        this.getDocumentList()
+      },
+      goDetail(item){
+        this.$router.push({path:"/assistanceDocDetail",query:{DocId:item.Id}})
+      },
+      //发布/取消发布
+      publish(item){
+        let text = item.Status==2?'取消发布':'发布'
+
+        this.$confirm(`是否确认${text}?`,"提示",
+        {
+          type:"warning",
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+        }).then(res=>{
+          assistanceDocInterence.assistanceDocPublish({
+            DocId:item.Id,
+            Status:3-item.Status
+          }).then(res=>{
+            if(res.Ret == 200){
+              this.$message.success(text+"成功")
+              this.getDocumentList()
+            }
+          })
+        }).catch(() => {});
+      },
+      addDocument(){
+        this.$router.push("/assistanceDocAdd")
+      },
+      editDocument(item){
+        this.$router.push({path:"/assistanceDocEdit",query:{DocId:item.Id}})
+      },
+      //删除文章
+      deleteDocument(item){
+        this.$confirm('删除后不可恢复,是否确认删除?',"提示",
+        {
+          type:"warning",
+          confirmButtonText: "确定",
+          cancelButtonText: "取消",
+        }).then(res=>{
+          assistanceDocInterence.assistanceDocDelete({DocId:item.Id}).then(res=>{
+            if(res.Ret == 200){
+              this.$message.success("删除成功")
+              this.getDocumentList()
+            }
+          })
+        }).catch(() => {});
+      },
+      classifyManage(){
+        this.$router.push("/docClassifyManage")
+      }
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+.assistance-center-container{
+  background-color: white;
+  min-height: calc(100vh - 110px);
+  padding: 30px 30px 80px;
+  box-sizing: border-box;
+  border: solid 1px #ECECEC;
+  .assistance-center-top-zone{
+    display: flex;
+    align-items: flex-start;
+    justify-content: space-between;
+    flex-wrap: wrap;
+    margin-bottom: 20px;
+    .assistance-center-top-operation{
+      display: flex;
+      align-items: center;
+      justify-content: flex-start;
+      margin: 0 30px 8px 0;
+    }
+    .assistance-center-top-search{
+      margin-bottom: 8px;
+    }
+  }
+  .document-table{
+    .document-title{
+      color:#409EFF;
+      cursor:pointer;
+    }
+  }
+}
+</style>

+ 369 - 0
src/views/system_manage/assistance_center/assistanceDocAdd.vue

@@ -0,0 +1,369 @@
+<template>
+  <div class="assistance-edit-container">
+    <div class="edit-container-rich-text">
+      <froala
+        id="froala-editor"
+        ref="froalaEditor"
+        :tag="'textarea'"
+        :config="froalaConfig"
+        v-model="addDocForm.Content"
+      ></froala>
+    </div>
+    <div class="edit-container-document-options">
+      <div class="document-options-button-box">
+        <el-button type="primary" class="document-options-button" @click="previewDocument" v-loading="isSubmiting">预览</el-button>
+        <el-button type="primary" class="document-options-button" @click="saveDocument('保存')" v-loading="isSubmiting">保存</el-button>
+        <el-button type="primary" class="document-options-button" @click="saveDocument('发布')" v-loading="isSubmiting">发布</el-button>
+      </div>
+      <div class="document-options-form">
+        <el-form :model="addDocForm" ref="addDocForm" :rules="addDocRules">
+          <el-form-item label="文章标题" prop="Title">
+            <el-input v-model="addDocForm.Title" placeholder="请输入文章标题"></el-input>
+          </el-form-item>
+          <el-form-item label="所属分类" prop="ClassifyId">
+            <el-cascader style="width: 100%;"
+              v-model="addDocForm.ClassifyId" :options="classifyList"
+              :props="{value:'ClassifyId',label:'ClassifyName',children:'Children',emitPath:false,disabled:'Disabled'}" placeholder="所属分类"/>
+          </el-form-item>
+          <el-form-item label="文章作者" prop="Author">
+            <el-input v-model="addDocForm.Author" placeholder="请输入文章作者"></el-input>
+          </el-form-item>
+          <el-form-item label="相关推荐">
+            <div v-for="(item,index) in addDocForm.RecommendData" :key="index" class="form-item-recommendedLink">
+              <el-input v-model="item.Name" placeholder="请输入链接名称" style="width: 190px;"></el-input>
+              <div class="recommendedLink-line"></div>
+              <el-input v-model="item.Url" placeholder="请输入链接" style="width: 190px;"></el-input>
+            </div>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import {assistanceDocInterence} from "@/api/api.js"
+import {createBottomHref} from "./utils/common"
+  export default {
+    name:"assistanceDocAdd",
+    data() {
+      const that = this;
+      return {
+        editor: null,
+        froalaConfig: {
+          toolbarButtons: [
+            "insertImage",
+            "insertVideo",
+            "embedly",
+            "insertFile",
+            "textColor",
+            "bold",
+            "italic",
+            "underline",
+            "strikeThrough",
+            "subscript",
+            "superscript",
+            "fontFamily",
+            "fontSize",
+            "color",
+            "inlineClass",
+            "inlineStyle",
+            "paragraphStyle",
+            "lineHeight",
+            "paragraphFormat",
+            "align",
+            "formatOL",
+            "formatUL",
+            "outdent",
+            "indent",
+            "quote",
+            "insertTable",
+            "emoticons",
+            "fontAwesome",
+            "specialCharacters",
+            "insertHR",
+            "selectAll",
+            "clearFormatting",
+            "html",
+            "undo",
+            "redo"
+          ],
+          height:"calc(100vh - 230px)",
+          fontSize: ["12", "14", "16", "18", "20", "24", "28", "32", "36", "40"],
+          fontSizeDefaultSelection: "16",
+          theme: "dark", //主题
+          placeholderText: "请输入内容",
+          language: "zh_cn", //国际化
+          imageUploadURL: process.env.API_ROOT + "/report/uploadImg", //上传url
+          videoUploadURL: process.env.API_ROOT + "/report/uploadImg", //上传url
+          fileUploadURL: process.env.API_ROOT + "/report/uploadImg", //上传url 更多上传介绍 请访问https://www.froala.com/wysiwyg-editor/docs/options
+          imageEditButtons:['imageAlign', 'imageCaption', 'imageRemove',  '-', 'imageDisplay',  'imageSize'],
+          quickInsertButtons: ["image","video","hr"], //快速插入项
+          toolbarVisibleWithoutSelection: false, //是否开启 不选中模式
+          // disableRightClick:true,//是否屏蔽右击
+          toolbarSticky: false, //操作栏是否自动吸顶
+          // zIndex:99999,
+          saveInterval: 0,
+          /* 				saveParam: 'content',
+            saveURL: process.env.API_ROOT+'/report/saveReportContent',
+            saveMethod: 'POST',
+            saveParams: {}, */
+          events: {
+            //this.editor 定义在vue data 中
+            initialized: function () {
+              that.editor = this;
+            },
+            keyup: function (e, editor) {
+              //添加事件,在每次按键按下时,都记录一下最后停留位置
+              that.$nextTick(function () {
+                that.lastEditRange = getSelection().getRangeAt(0);
+              });
+            },
+            click: function (e, editor) {
+              //添加事件,在每次鼠标点击时,都记录一下最后停留位置
+              that.$nextTick(function () {
+                that.lastEditRange = getSelection().getRangeAt(0);
+              });
+            },
+          },
+        },
+        classifyList:[],
+        addDocForm:{
+          Title:"",
+          ClassifyId:"",
+          Author:"",
+          Status:1,
+          Content:'',
+          AnchorData:[],
+          RecommendData:[{Name:"",Url:""},{Name:"",Url:""}],
+        },
+        addDocRules:{
+          Title:{required:true,message:'文章标题不能为空',trigger:'blur'},
+          ClassifyId:{required:true,message:'文章所属分类不能为空',trigger:'change'},
+          Author:{required:true,message:'文章作者不能为空',trigger:'blur'}
+        },
+        anchorData:[],
+        isSubmiting:false,
+      }
+    },
+    created() {
+      this.getClassifyData()
+      if(this.$route.query.DocId){
+        assistanceDocInterence.getAssistanceDoc({DocId:this.$route.query.DocId}).then(res=>{
+          if(res.Ret == 200){
+            this.addDocForm={
+              Id:res.Data.Id,
+              Title:res.Data.Title,
+              ClassifyId:res.Data.ClassifyId,
+              Author:res.Data.Author,
+              Status:res.Data.Status,
+              Content:res.Data.Content,
+              RecommendData:res.Data.Recommend || [{Name:"",Url:""},{Name:"",Url:""}]
+            }
+            
+          }
+        })
+      }      
+    },
+    mounted(){
+      this.addDocForm.Content=""
+    },
+    methods: {
+      getClassifyData(){
+        assistanceDocInterence.getAssistanceClassifyList().then(res=>{
+          if(res.Ret == 200){
+            this.classifyList = res.Data?res.Data.AllNodes||[]:[]
+          }
+        })
+      },
+      // 生成锚点
+      generateAnchor(){
+        this.anchorData=[]
+        // 搜索富文本中的h1和h2标签 当做一级和二级的锚点
+        this.searchTitleTag(0,1)
+        // console.log(this.addDocForm.Content,this.anchorData);
+      },
+      // 搜索标题标签h1,h2
+      searchTitleTag(searchPosition,firstLevel){
+        let frontH1Posiiton,nextH1Posiiton,H2Posiiton=0
+        let frontH1RightPosiiton,H2RightPosiiton=0
+        let backH1Posiiton,backH2Posiiton=0
+        // 本次搜索第一个h1的位置
+        frontH1Posiiton = this.addDocForm.Content.indexOf('<h1',searchPosition)
+        // 右闭合标签
+        frontH1RightPosiiton = this.addDocForm.Content.indexOf('>',frontH1Posiiton)
+
+        if(frontH1Posiiton == -1) return 
+
+        let anchorText=`id="doc_anchor_${firstLevel}"`
+        // console.log(frontH1Posiiton,firstLevel,'firstLevel');
+        this.addDocForm.Content = this.addDocForm.Content.substring(0, frontH1Posiiton+3) 
+                                  +" "+anchorText + this.addDocForm.Content.substring(frontH1RightPosiiton);
+        // 再次获取右闭合标签
+        frontH1RightPosiiton = this.addDocForm.Content.indexOf('>',frontH1Posiiton)
+        // 对应的</h1>的位置 原本用的</h1>,后来发现> 和 </h1>之间会掺其他标签
+        backH1Posiiton = this.addDocForm.Content.indexOf('<',frontH1RightPosiiton)
+        // 获取标题
+        let AnchorTitle = this.addDocForm.Content.substring(frontH1RightPosiiton+1,backH1Posiiton)
+
+        this.anchorData.push({
+          AnchorId:`${firstLevel}`,
+          Anchor:`doc_anchor_${firstLevel}`,
+          AnchorName:AnchorTitle,
+          Child:[]})
+        // 本次搜索下一个h1的位置
+        nextH1Posiiton = this.addDocForm.Content.indexOf('<h1',backH1Posiiton)==-1?
+                          this.addDocForm.Content.length:this.addDocForm.Content.indexOf('<h1',backH1Posiiton)
+        // 从第一个h1的位置开始查找h2标签
+        H2Posiiton = this.addDocForm.Content.indexOf('<h2',backH1Posiiton)
+
+        let secondLevel=1
+        while (!(H2Posiiton==-1 || H2Posiiton>nextH1Posiiton)) {
+          // 右闭合标签
+          H2RightPosiiton = this.addDocForm.Content.indexOf('>',H2Posiiton)
+
+          // 找到了,并且位置小于下一个h1的位置 
+          let anchorTextH2=`id="doc_anchor_${firstLevel}_${secondLevel}"`
+          // console.log(H2Posiiton,secondLevel,'secondLevel');
+          this.addDocForm.Content = this.addDocForm.Content.substring(0, H2Posiiton+3) 
+                                    +" "+anchorTextH2 + this.addDocForm.Content.substring(H2RightPosiiton);
+          // 再次获取右闭合标签
+          H2RightPosiiton = this.addDocForm.Content.indexOf('>',H2Posiiton)
+          // 对应的</h2>的位置  原本用的</h2>,后来发现> 和 </h2>之间会掺其他标签
+          backH2Posiiton = this.addDocForm.Content.indexOf('<',H2RightPosiiton)
+          // 获取标题
+          let AnchorTitleLevelTwo = this.addDocForm.Content.substring(H2RightPosiiton+1,backH2Posiiton)
+          this.anchorData[firstLevel-1].Child.push(
+            {AnchorId:`${firstLevel}_${secondLevel}`,
+            Anchor:`doc_anchor_${firstLevel}_${secondLevel}`,
+            AnchorName:AnchorTitleLevelTwo,
+            Child:[]
+          })
+          // nextH1Posiiton 和 secondLevel 随之增加
+          // nextH1Posiiton +=anchorTextH2.length+1
+          // 更新nextH1Posiiton位置
+          nextH1Posiiton = this.addDocForm.Content.indexOf('<h1',backH1Posiiton)==-1?
+                          this.addDocForm.Content.length:this.addDocForm.Content.indexOf('<h1',backH1Posiiton)
+          secondLevel++
+          H2Posiiton = this.addDocForm.Content.indexOf('<h2',backH2Posiiton)
+        }
+        // 结束一轮 <h1></h1>标签的寻找
+        if(this.addDocForm.Content.indexOf('<h1',backH1Posiiton+4)!=-1){
+          // 如果有下一个h1的标签,说明寻找还没结束,继续寻找
+          firstLevel++
+          this.searchTitleTag(nextH1Posiiton,firstLevel)
+        }
+      },
+      previewDocument(){
+        // this.addDocForm.Content=`<p>范德萨发的刚发的</p><p>刚发的g梵蒂冈</p><p>割发代首刚发的</p><hr><h1>1. 个刚发的施工方</h1><p>刚发的刚发的g规范的施工方都是割发代首规范</p><h2>1.1. 规范的三个富士达割发代首</h2><p>个梵蒂冈是梵蒂冈讽德诵功范德萨割发代首个割发代首</p><p>刚分手的割发代首割发代首高富帅d</p><p>刚分手的刚分手的</p><p>割发代首刚分手的</p><p>刚分手的公司发的</p><p>刚发的事故发生的</p><p><br></p><p>割发代首刚分手的刚分手的</p><h2>1.2. 噶规范十多个范德萨刚发的施工方多少公分</h2><p>个讽德诵功范德萨</p><p>割发代首割发代首刚发的s规范的三个</p><h1>2.讽德诵功是反的</h1><p>割发代首割发代首个人的施工方都是</p><p>范德萨个人东方闪电方式</p><p>割发代首割发代首</p><h2>2.1.个梵蒂冈</h2><p>讽德诵功范德萨规范的三个范德萨讽德诵功放大s</p><h2>2.2.刚发的广泛地个</h2><p>刚分手的割发代首</p><p>割发代首割发代首割发代首</p><p><br></p><p>范德萨割发代首</p><h2>2.3.辅导费是的</h2><p>范甘迪个放大割发代首个</p><p>刚发的刚发的</p><h1>3. 个梵蒂冈放大</h1>`
+        if(this.isSubmiting) return 
+        if(!this.addDocForm.Content){
+          this.$message.error("文章内容不能为空")
+          return
+        }
+        let bottomLink = createBottomHref(this.addDocForm.RecommendData)
+        
+        sessionStorage.setItem("documentDoc",this.addDocForm.Content+bottomLink)
+        let { href } = this.$router.resolve({ path: "/assistanceDocDetail" });
+        window.open(href, "_blank");
+      },
+      saveDocument(type){
+        if(this.isSubmiting) return 
+        this.$refs.addDocForm.validate(valid=>{
+          if(valid){
+            if(!this.addDocForm.Content){
+              this.$message.error("文章内容不能为空")
+              return
+            }
+            // console.log(this.addDocForm);
+            this.isSubmiting=true
+            if(type=="发布") this.addDocForm.Status=2
+
+            this.generateAnchor()
+            this.addDocForm.AnchorData = this.anchorData
+            //保存
+            assistanceDocInterence.addAssistanceDoc(this.addDocForm).then(res=>{
+              if(res.Ret == 200){
+                this.$message({
+                  type:'success',
+                  message:'操作成功',
+                  duration:2000
+                })
+                setTimeout(()=>{
+                  this.$router.back()
+                  this.isSubmiting=false
+                },2000)
+              }
+            }).catch(()=>{
+              this.isSubmiting=false
+            })
+          }
+        })
+      }
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+  .assistance-edit-container{
+    display: flex;
+    justify-content: flex-start;
+    .edit-container-rich-text{
+      flex-grow: 1;
+      min-height: calc(100vh - 110px);
+      background-color: white;
+      border:solid 1px #ECECEC;
+      box-sizing: border-box;
+    }
+    .edit-container-document-options{
+      background-color: white;
+      margin-left: 20px;
+      min-height: calc(100vh - 110px);
+      border:solid 1px #ECECEC;
+      box-sizing: border-box;
+      width: 440px;
+      min-width: 440px;
+      .document-options-button-box{
+        width: 100%;
+        height: 80px;
+        box-sizing: border-box;
+        padding: 20px;
+        box-shadow: 0px 5px 10px #ECECEC;
+        border-bottom: solid 1px #ECECEC;
+        .document-options-button{
+          height: 40px;
+          width: 120px;
+        }
+      }
+      .document-options-form{
+        padding: 30px 20px;
+        .form-item-recommendedLink{
+          display: flex;
+          align-items: center;
+          justify-content: flex-start;
+          width: 100%;
+          margin-bottom: 20px;
+          &:last-child{
+            margin-bottom: 0;
+          }
+          .recommendedLink-line{
+            flex: 1;
+            height: 1px;
+            background-color:#DCDFE6 ;
+          }
+        }
+      }
+    }
+  }
+</style>
+<style lang="scss">
+.assistance-edit-container{
+  .fr-toolbar,.fr-box.fr-basic .fr-wrapper{
+    border: none;
+  }
+}
+.fr-popup.fr-active{
+  z-index: 100000!important;
+  opacity: 1!important;
+}
+</style>

+ 45 - 0
src/views/system_manage/assistance_center/assistanceDocDetail.vue

@@ -0,0 +1,45 @@
+<template>
+  <div class="assistance-detail-container">
+    <div class="assistance-detail-box fr-view" v-html="content"></div>
+  </div>
+</template>
+
+<script>
+import {assistanceDocInterence} from '@/api/api.js'
+import {createBottomHref} from './utils/common'
+  export default {
+    name:"assistanceDocDetail",
+    data() {
+      return {
+        content:''
+      }
+    },
+    created(){
+      if(this.$route.query.DocId){
+        assistanceDocInterence.getAssistanceDoc({DocId:this.$route.query.DocId}).then(res=>{
+          if(res.Ret == 200){
+            this.content = res.Data.Content + createBottomHref(res.Data.Recommend || [{Name:"",Url:""},{Name:"",Url:""}])
+          }
+        })
+      }else{
+        this.content = sessionStorage.getItem("documentDoc") || ''
+      }
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+.assistance-detail-container{
+  background-color: white;
+  min-height: calc(100vh - 110px);
+  // height: calc(100vh - 110px);
+  padding: 20px;
+  box-sizing: border-box;
+  border: solid 1px #ECECEC;
+  // .assistance-detail-box{
+  //   border: solid 1px #333333;
+  //   height: 100%;
+  //   width: 100%;
+  // }
+}
+</style>

+ 472 - 0
src/views/system_manage/assistance_center/docClassifyManage.vue

@@ -0,0 +1,472 @@
+<!-- 
+    表格树形数据拖拽 本来使用el-table和sortablejs 但是奇怪的判断导致前端无法做跨级拖拽的限制。
+  得由后端来限制,固使用drag-tree-table 但是这个插件构造比较简单,不是用table标签实现的
+  如果产品要实现el-table上面的功能,需要自定义,有更好的方法,还请通知一声。
+ -->
+<template>
+  <div class="doc-classifyMana-container">
+    <div class="doc-classifyMana-top-zone">
+      <el-button type="primary" @click="addClassify">添加分类</el-button>
+      <el-input placeholder="分类名称" v-model="queryParams.KeyWord" @input="getclassifyData" clearable 
+      style="width:500px;margin-left: 20px;">
+        <i slot="prefix" class="el-input__icon el-icon-search"></i>
+      </el-input>
+    </div>
+    <!-- <el-table style="border:1px solid #eaeaea;" ref="classifyTableRef"
+    :data="classifyList" :row-class-name="tableRowClassName" row-key="id" :tree-props="{children:'child'}">
+      <el-table-column prop="text" label="一级分类">
+        <template slot-scope="scope">
+          <span>{{scope.row.level==1?scope.row.text:''}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="text" label="二级分类">
+        <template slot-scope="scope">
+          <span>{{scope.row.level==2?scope.row.text:''}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column prop="text" label="三级分类">
+        <template slot-scope="scope">
+          <span>{{scope.row.level==3?scope.row.text:''}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center">
+        <template slot-scope="scope">
+          <div class="table-button">
+            <span @click="configItem(scope.row)">权限配置</span>
+            <span @click="edititem(scope.row)">编辑</span>
+            <span @click="checkdeleteitem(scope.row)" style="margin-right: 0;color: #F56C6C;">删除</span>
+          </div>
+            </template>
+      </el-table-column>
+    </el-table> -->
+    <dragTreeTable ref="dragTreeTableRef" :beforeDragOver="beforeDrag"
+    :data="treeData" :onDrag="onTreeDataChange"
+    hightRowChange resize border >
+    <!-- onlySameLevelCanDrag -->
+    </dragTreeTable>
+    <!-- 添加分类弹窗 -->
+    <el-dialog :title="dialogTitle" :visible.sync="showAddClassifyDia" width="625px"
+    append-to-body :close-on-click-modal="false" @close="resetForm">
+      <div style="display: flex;flex-direction: column; align-items: center;margin-bottom: 35px;">
+        <el-form :model="classifyForm" ref="classifyFormRef" label-width="80px">
+          <el-form-item label="上级目录" prop="ParentId">
+            <el-cascader v-model="classifyForm.ParentId" :options="noLevelThreeList" @change="selectParentId"
+              placeholder="请选择上级目录(不选默认添加的是一级分类)" ref="parentIdCascaderRef"
+              :props="{ value:'ClassifyId',label:'ClassifyName',children:'Children',checkStrictly:true,emitPath:false,disabled:'Disabled'}" 
+              class="lastCatalogCascader" :disabled="this.dialogTitle.indexOf('编辑分类')!=-1" />
+          </el-form-item>
+          <el-form-item label="分类名称" prop="HelpDocClassifyName" :rules="{required:true,message:'分类名称不能为空',trigger:'blur'}">
+            <el-input v-model="classifyForm.HelpDocClassifyName" placeholder="请输入分类名称" style="width: 337px;"
+             maxlength="10"></el-input>
+          </el-form-item>
+        </el-form>
+        <div style="margin-top: 40px;">
+          <el-button type="primary" style="width:120px;margin-right:10px" @click="classifySave" size="medium">保存</el-button>
+          <el-button  style="width:120px;" @click="showAddClassifyDia=false" size="medium">取消</el-button>
+        </div>
+      </div>
+    </el-dialog>
+    <!-- 设置权限弹窗 -->
+    <el-dialog :title="dialogTitle" :visible.sync="showPermissionDia" width="625px"
+    append-to-body :close-on-click-modal="false" @close="resetPermissonForm">
+      <div style="display: flex;flex-direction: column; align-items: center;margin-bottom: 35px;">
+        <el-form :model="permissionForm" ref="permissionFormRef" label-width="80px">
+          <el-form-item label="可见权限" prop="merchantIds">
+            <el-select v-model="permissionForm.merchantIds" placeholder="请选择商家" 
+            multiple style="width: 337px;" collapse-tags clearable filterable >
+              <el-option :label="item.BusinessName" :value="item.EtaBusinessId" 
+              v-for="item in merchantList" :key="item.merchantId"></el-option>
+            </el-select>
+          </el-form-item>
+        </el-form>
+        <div style="margin-top: 40px;">
+          <el-button type="primary" style="width:120px;margin-right:10px" @click="configSave" size="medium">保存</el-button>
+          <el-button  style="width:120px;" @click="showPermissionDia=false" size="medium">取消</el-button>
+        </div>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+// import Sortable from "sortablejs";
+import {assistanceDocInterence,businessCustomInterence} from "@/api/api.js"
+import dragTreeTable from "drag-tree-table";
+  export default {
+    name:"docClassifyManage",
+    components:{dragTreeTable},
+    data() {
+      // 表格头设置
+      this.tableHeadList=[
+        {
+          type:"selection",
+          title: '一级分类',
+          field: 'ClassifyName',
+          flex:1,
+          align: 'center',
+          formatter: (item) => {    
+            return item.Level==1?item.ClassifyName:""
+          }
+        },
+        {
+          title: '二级分类',
+          field: 'ClassifyName',
+          // width: 200,
+          flex:1,
+          align: 'center',
+          formatter: (item) => {
+            return item.Level==2?item.ClassifyName:""
+          }
+        },
+        {
+          title: '三级分类',
+          field: 'ClassifyName',
+          // width: 200,
+          flex:1,
+          align: 'center',
+          formatter: (item) => {
+            return item.Level==3?item.ClassifyName:""
+          }
+        },
+        {
+          type: 'action',
+          title: '操作',
+          width: 260,
+          // flex:1,
+          align: 'center',
+          actions:[
+            {
+              text: '权限配置',
+              onclick: (item) => {
+                // item是当前行的数据
+                this.configClassify(item)
+              },
+              formatter: (item) => {
+                return '<span class="table-button">权限配置</span>'
+              }
+            },
+            {
+              text: '编辑',
+              onclick: (item) => {
+                this.editClassify(item)
+              },
+              formatter: (item) => {
+                return '<span class="table-button">编辑</span>'
+              }
+            },
+            {
+              text: '删除',
+              onclick: (item) => {
+                this.deleteClassify(item)
+              },
+              formatter: (item) => {
+                return '<span class="table-button" style="margin-right: 0;color: #F56C6C;">删除</span>'
+              }
+            }
+          ]
+        }
+      ]
+      // 自定义字段替换
+      this.custom_field={
+        id: 'ClassifyId',
+        order: 'Sort',
+        lists: 'Children',
+        parent_id: 'ParentId'
+      }
+
+      return {
+        queryParams:{
+          KeyWord:''
+        },
+        treeData:{
+          columns:this.tableHeadList,
+          lists:[],
+          custom_field:this.custom_field
+        },
+        // 没有三级分类的分类数组,用于添加
+        noLevelThreeList:[],
+        // // 扁平化之后的数据
+        // classifyListFlat:[],
+        dialogTitle:"",
+        showAddClassifyDia:false,
+        classifyForm:{
+          ParentId:0,
+          HelpDocClassifyName:'',
+          Level:0,
+        },
+        merchantList:[],
+        showPermissionDia:false,
+        permissionForm:{
+          HelpDocClassifyId:0,
+          merchantIds:[]
+        },
+      }
+    },
+    created(){
+      this.getmerchantList()
+      this.getclassifyData()
+    },
+    mounted(){
+      this.$nextTick(()=>{
+        // this.tableDropSet()
+      })
+    },
+    methods: {
+      getmerchantList(){
+        businessCustomInterence.getBusinessList({PageSize:9999999,CurrentIndex:1}).then(res=>{
+          if(res.Ret == 200){
+            this.merchantList = res.Data.List||[]
+          }
+        })
+      },
+      getclassifyData(){
+        assistanceDocInterence.getAssistanceClassifyList(this.queryParams).then(res=>{
+          if(res.Ret == 200){
+            this.treeData.lists = res.Data?res.Data.AllNodes||[]:[]
+            this.noLevelThreeList = res.Data?res.Data.TwoLevelNodes||[]:[]
+            this.treeData.lists.map(list=> {
+              // 一级展开
+              list.open=true
+            })
+            // console.log(this.treeData.lists);
+          }
+        })
+      },
+      // tableRowClassName({row,rowIndex}) {
+      //   if( row.child && row.child.length>0 ){
+      //     return 'has-child-row';
+      //   }else{
+      //     return '';
+      //   }
+      // },
+      beforeDrag(dragItem,effectItem,type){
+        if(type=='center'){
+          // 放里面
+          if((dragItem.Level-1)!=effectItem.Level) return false
+        }else{
+          //不放里面
+          if(dragItem.Level!=effectItem.Level) return false
+        }
+        // return false
+      },
+      onTreeDataChange(list,dragItem){
+        // console.log(list,dragItem,'arguments');
+        // list - 拖拽后的数据 dragItem-拖拽的项
+        let ClassifyId,PrevClassifyId,NextClassifyId,ParentClassifyId=0
+        // 在拖拽后的数据中找到拖拽项对应的位置
+        const findDraggedItem=(list)=>{
+          let itemIndex = list.findIndex(it => it.ClassifyId == dragItem.ClassifyId)
+          if(itemIndex!=-1){
+            if(itemIndex==0){
+              PrevClassifyId=0
+            }else{
+              PrevClassifyId = list[itemIndex-1].ClassifyId
+            }
+            if(itemIndex==(list.length-1)){
+              NextClassifyId=0
+            }else{
+              NextClassifyId = list[itemIndex+1].ClassifyId
+            }
+            ClassifyId = dragItem.ClassifyId
+            ParentClassifyId = dragItem.ParentId
+            console.log({
+              ClassifyId,ParentClassifyId,PrevClassifyId,NextClassifyId
+            });
+            assistanceDocInterence.moveAssistanceClassify({
+              ClassifyId,ParentClassifyId,PrevClassifyId,NextClassifyId
+            }).then(res=>{
+              if(res.Ret == 200){
+                this.$message.success("移动分类成功")
+                this.getclassifyData()
+              }
+            })
+          }else{
+            list.map(li => {
+              li.Children && li.Children.length>0 && findDraggedItem(li.Children)
+            })
+          }
+        }
+        findDraggedItem(list)
+      },
+      // tableDropSet(){
+      //   const tbody = this.$refs.classifyTableRef.$el.querySelector(
+      //     ".el-table__body-wrapper > table > tbody"
+      //   );
+      //   const _this = this;
+      //   Sortable.create(tbody, {
+      //     animation: 150, 
+      //     onStart(evt){
+      //       if(_this.classifyListFlat && _this.classifyListFlat.length>0){
+      //         return 
+      //       }else{
+      //         _this.flatClassifyList(_this.classifyList,0)
+      //       }
+      //       console.log(_this.classifyListFlat);
+      //     },
+      //     onEnd({ newIndex, oldIndex }) {
+      //       console.log({ newIndex, oldIndex });
+      //       if(newIndex == oldIndex) return 
+      //       const oldRow = _this.classifyListFlat[oldIndex]
+      //       const newRow = _this.classifyListFlat[newIndex]
+      //       console.log(oldRow,newRow);
+      //       _this.$message.success("拖拽成功")
+      //       _this.getclassifyData()
+      //     },
+      //     onMove({ dragged, related }){
+      //       console.log(dragged.rowIndex, related.rowIndex);
+      //       const oldRow = _this.classifyListFlat[dragged.rowIndex]
+      //       const newRow = _this.classifyListFlat[related.rowIndex]
+      //       console.log(oldRow.level,newRow.level);
+      //       if (oldRow.level !== newRow.level) {
+      //         return false // 不允许不同级的拖动
+      //       }
+      //     }
+      //   });
+      // },
+      // flatClassifyList(list,parentId){
+      //   for (let i = 0; i < list.length; i++) {
+      //     const element = list[i];
+      //     const lastElementId = i==0?0:list[i-1].id
+      //     const nextElementId = i==(list.length-1)?0:list[i+1].id
+      //     this.classifyListFlat.push({id:element.id,lastElementId,nextElementId,parentId,level:element.level})
+      //     if(element.child && element.child.length>0){
+      //       this.flatClassifyList(element.child,element.id)
+      //     }
+      //   }
+      // },
+      // 添加分类
+      addClassify(){
+        this.dialogTitle="添加分类"
+        this.showAddClassifyDia=true
+      },
+      // 编辑分类
+      editClassify(item){
+        this.classifyForm={
+          ParentId:item.ParentId,
+          HelpDocClassifyId:item.ClassifyId,
+          HelpDocClassifyName:item.ClassifyName
+        }
+        this.dialogTitle="编辑分类"
+        this.showAddClassifyDia=true
+      },
+      selectParentId(value){
+        this.classifyForm.Level = this.$refs.parentIdCascaderRef.getCheckedNodes()[0].data.Level
+      },
+      deleteClassify(item){
+        this.$confirm('是否确认删除?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning',
+        }).then(() => {
+          assistanceDocInterence.deleteAssistanceClassify({ClassifyId:item.ClassifyId}).then(res=>{
+            if(res.Ret == 200){
+              this.$message.success("删除分类成功")
+              this.getclassifyData()
+            }
+          })
+        }).catch(()=>{})
+      },
+      // 保存
+      classifySave(){
+        this.$refs.classifyFormRef.validate(valid=>{
+          if(valid){
+            console.log(this.classifyForm);
+            if(this.classifyForm.HelpDocClassifyId){
+              //编辑
+              assistanceDocInterence.editAssistanceClassify(this.classifyForm).then(res=>{
+                if(res.Ret == 200){
+                  this.$message.success(this.dialogTitle+"成功")
+                  this.showAddClassifyDia=false
+                  this.resetForm()
+                  this.getclassifyData()
+                }
+              })
+            }else{
+              //新增
+              assistanceDocInterence.addAssistanceClassify({...this.classifyForm}).then(res=>{
+                if(res.Ret == 200){
+                  this.$message.success(this.dialogTitle+"成功")
+                  this.showAddClassifyDia=false
+                  this.resetForm()
+                  this.getclassifyData()
+                }
+              })
+            }
+          }
+        })
+      },
+      resetForm(){
+        this.classifyForm={
+          ParentId:0,
+          HelpDocClassifyName:'',
+          Level:0
+        }
+        this.$refs.classifyFormRef.clearValidate()
+      },
+      //权限配置
+      configClassify(row){
+        this.permissionForm={
+          HelpDocClassifyId:row.ClassifyId,
+          merchantIds:row.VisibleBusinessIds?row.VisibleBusinessIds.split(',').map(element => {
+            return parseInt(element)
+          }):[]
+        }
+        // console.log(this.permissionForm.merchantIds);
+        this.dialogTitle="设置权限"
+        this.showPermissionDia=true
+      },
+      resetPermissonForm(){
+        this.permissionForm={
+          HelpDocClassifyId:0,
+          merchantIds:[]
+        }
+        this.$refs.permissionFormRef.clearValidate()
+      },
+      configSave(){
+        assistanceDocInterence.editAssistanceClassifyVisible({
+          HelpDocClassifyId:this.permissionForm.HelpDocClassifyId,
+          VisibleBusinessIds:this.permissionForm.merchantIds.join(',')
+        }).then(res=>{
+          if(res.Ret == 200){
+            this.$message.success("设置成功")
+            this.showPermissionDia=false
+            this.resetPermissonForm()
+            this.getclassifyData()
+          }
+        })
+      }
+    },
+  }
+</script>
+
+<style lang="scss" scoped>
+.doc-classifyMana-container{
+  background-color: white;
+  min-height: calc(100vh - 110px);
+  padding: 30px;
+  box-sizing: border-box;
+  border: solid 1px #ECECEC;
+  .doc-classifyMana-top-zone{
+    display: flex;
+    align-items: flex-start;
+    justify-content: space-between;
+    margin-bottom: 20px;
+  }
+}
+</style>
+<style lang="scss">
+.lastCatalogCascader{
+  width: 337px;
+  .el-input{
+    width: 337px;
+  }
+}
+.has-child-row {
+    background-color: #f2f6fa!important;
+}
+.table-button{
+    color:#4099ef; 
+    cursor: pointer;
+    margin-right: 10px;
+  }
+</style>

+ 10 - 0
src/views/system_manage/assistance_center/utils/common.js

@@ -0,0 +1,10 @@
+// 生成底部的两个链接
+export function createBottomHref(RecommendData){
+  let hrefStringBuiler='<ul style="margin-top:40px">'
+  RecommendData.map(item =>{
+    if(item.Name){
+      hrefStringBuiler+=`<li><a href="${item.Url}" target="_blank" style="text-decoration: underline;">${item.Name}</a></li>`
+    }
+  })
+  return hrefStringBuiler+"</ul>"
+}