瀏覽代碼

修改目录,预览,公式等bug 并打包

yangg 10 月之前
父節點
當前提交
9d9360701c
共有 33 個文件被更改,包括 1132 次插入448 次删除
  1. 0 0
      dist/index.html
  2. 0 0
      dist/static/css/app.cb67a4d3.css
  3. 0 0
      dist/static/css/chunk-07c440fa.19263c89.css
  4. 0 0
      dist/static/css/chunk-0882ce66.16e21a5e.css
  5. 0 0
      dist/static/css/chunk-413eea75.a12d40e0.css
  6. 1 1
      dist/static/css/chunk-a676d172.2799ca54.css
  7. 0 0
      dist/static/js/app.b3227866.js
  8. 0 0
      dist/static/js/app.e134e78c.js
  9. 0 0
      dist/static/js/chunk-07c440fa.34fa1b89.js
  10. 0 0
      dist/static/js/chunk-0882ce66.7ad717eb.js
  11. 0 0
      dist/static/js/chunk-24067204.ba850856.js
  12. 0 0
      dist/static/js/chunk-413eea75.1a7fe2df.js
  13. 0 0
      dist/static/js/chunk-52f685c2.55ebb9a3.js
  14. 0 0
      dist/static/js/chunk-5ea048a8.1356e809.js
  15. 0 0
      dist/static/js/chunk-6887eea4.0e5b85f2.js
  16. 0 0
      dist/static/js/chunk-81c5f682.7e988cc6.js
  17. 10 0
      src/api/api.js
  18. 1 1
      src/api/formula.js
  19. 1 1
      src/styles/index.scss
  20. 17 4
      src/views/dashboard/admin/components/PanelGroup.vue
  21. 4 3
      src/views/document/com/components/Attribute/Directory/index.scss
  22. 3 2
      src/views/document/com/components/Attribute/Directory/index.vue
  23. 224 286
      src/views/document/com/components/Attribute/attributeVar/index.vue
  24. 76 11
      src/views/document/com/components/Formula/dataInfo.vue
  25. 10 2
      src/views/document/com/components/Formula/index.vue
  26. 105 24
      src/views/document/com/components/TextArea/index.vue
  27. 47 7
      src/views/document/com/components/Variable/index.vue
  28. 7 7
      src/views/document/com/menus.vue
  29. 189 1
      src/views/document/com/view.vue
  30. 1 1
      src/views/document/create.scss
  31. 262 35
      src/views/document/create.vue
  32. 155 62
      src/views/login/index.vue
  33. 19 0
      src/views/product/components/dataList.scss

File diff suppressed because it is too large
+ 0 - 0
dist/index.html


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/app.cb67a4d3.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-07c440fa.19263c89.css


File diff suppressed because it is too large
+ 0 - 0
dist/static/css/chunk-0882ce66.16e21a5e.css


+ 0 - 0
dist/static/css/chunk-81c5f682.a12d40e0.css → dist/static/css/chunk-413eea75.a12d40e0.css


+ 1 - 1
dist/static/css/chunk-a676d172.6044f932.css → dist/static/css/chunk-a676d172.2799ca54.css

@@ -1 +1 @@
-.sub-imgs{padding:0;margin:0}.sub-imgs li{float:left;margin-right:10px;width:100px;height:100px;list-style:none}.data-search{padding:20px 10px 0 10px}.data-list .btns,.data-list .page-info{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.data-list .page-info{margin-top:10px}.data-list .page-info .opt{width:50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.data-list .page-info .opt .pick{width:100px}.data-list .page-info .opt .section{margin-left:10px}.data-list .page-info .page-data{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%}.data-list .page-info .page-data .page-item{width:100%}.data-list .page-info .page-data .page-opt{width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.project-search{padding:30px;font-size:12px}
+.sub-imgs{padding:0;margin:0}.sub-imgs li{float:left;margin-right:10px;width:100px;height:100px;list-style:none}.data-search{padding:20px 10px 0 10px}.data-list .btns,.data-list .page-info{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.data-list .page-info{margin-top:10px}.data-list .page-info .opt{width:50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.data-list .page-info .opt .pick{width:100px}.data-list .page-info .opt .section{margin-left:10px}.data-list .page-info .page-data{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%}.data-list .page-info .page-data .page-item{width:100%}.data-list .page-info .page-data .page-opt{width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-table{scrollbar-color:#efefef #fff;scrollbar-width:thin}.el-table::-webkit-scrollbar{height:8px}.el-table::-webkit-scrollbar-thumb{background-color:#efefef;border-radius:4px}.el-table::-webkit-scrollbar-track{background-color:#fff}.project-search{padding:30px;font-size:12px}

File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.b3227866.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/app.e134e78c.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-07c440fa.34fa1b89.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-0882ce66.7ad717eb.js


+ 0 - 0
dist/static/js/chunk-24067204.e996c129.js → dist/static/js/chunk-24067204.ba850856.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-413eea75.1a7fe2df.js


+ 0 - 0
dist/static/js/chunk-52f685c2.df6710a5.js → dist/static/js/chunk-52f685c2.55ebb9a3.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-5ea048a8.1356e809.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-6887eea4.0e5b85f2.js


File diff suppressed because it is too large
+ 0 - 0
dist/static/js/chunk-81c5f682.7e988cc6.js


+ 10 - 0
src/api/api.js

@@ -28,3 +28,13 @@ export function userLogout(data) {
     data
   })
 }
+
+/* 统计 */
+export function statistics(data) {
+  return request({
+    url: 'index/statistics',
+    method: 'post',
+    data
+  })
+}
+

+ 1 - 1
src/api/formula.js

@@ -41,7 +41,7 @@ export function getFormulaInfo(data) {
 
  export function deleteFormula(data) {
    return request({
-     url: '/formula/info',
+     url: '/formula/delete',
      method: 'post',
      data
    })

+ 1 - 1
src/styles/index.scss

@@ -211,7 +211,7 @@ aside {
 .text-input-box{
   border:none;
   border-bottom:1px solid #CCC;
-  width:100px;
+  min-width:100px;
   text-align:center;
 }
 h1{

+ 17 - 4
src/views/dashboard/admin/components/PanelGroup.vue

@@ -9,7 +9,7 @@
           <div class="card-panel-text">
             用户数
           </div>
-          <count-to :start-val="0" :end-val="1" :duration="2600" class="card-panel-num" />
+          <count-to :start-val="0" :end-val="statisticsForm.admin_count" :duration="2600" class="card-panel-num" />
         </div>
       </div>
     </el-col>
@@ -22,7 +22,7 @@
           <div class="card-panel-text">
             文档数量
           </div>
-          <count-to :start-val="0" :end-val="2" :duration="3000" class="card-panel-num" />
+          <count-to :start-val="0" :end-val="statisticsForm.document_coutn" :duration="3000" class="card-panel-num" />
         </div>
       </div>
     </el-col>
@@ -35,7 +35,7 @@
           <div class="card-panel-text">
             模块数量
           </div>
-          <count-to :start-val="0" :end-val="2" :duration="3200" class="card-panel-num" />
+          <count-to :start-val="0" :end-val="statisticsForm.template_count" :duration="3200" class="card-panel-num" />
         </div>
       </div>
     </el-col>
@@ -48,7 +48,7 @@
           <div class="card-panel-text">
             产品数量
           </div>
-          <count-to :start-val="0" :end-val="3" :duration="3600" class="card-panel-num" />
+          <count-to :start-val="0" :end-val="statisticsForm.product_count" :duration="3600" class="card-panel-num" />
         </div>
       </div>
     </el-col>
@@ -57,12 +57,25 @@
 
 <script>
 import CountTo from 'vue-count-to'
+import {statistics} from '@/api/api.js'
 
 export default {
   components: {
     CountTo
   },
+  data(){
+    return{
+      statisticsForm:{}
+    }
+  },
+  mounted() {
+    this.init()
+  },
   methods: {
+   async init(){
+      let res=await statistics()
+      this.statisticsForm=res.data
+    },
     handleSetLineChartData(type) {
       this.$emit('handleSetLineChartData', type)
     }

+ 4 - 3
src/views/document/com/components/Attribute/Directory/index.scss

@@ -6,7 +6,7 @@
   overflow: auto;
   justify-content: flex-start;
   align-items: flex-start;
-  margin-top:50px;
+  margin-top:10px;
   overflow: hidden;
   .com-title{
     padding-left:10px;
@@ -18,8 +18,7 @@
   .com-items{
 
     width:100%;
-    height:100%;
-
+    max-height:50%;
     overflow: hidden;
     overflow-y:auto;
 
@@ -77,4 +76,6 @@
 .dirceForm{
   width: 100%;
   margin: 0 10px 0;
+  max-height: 50%;
+  overflow: auto;
 }

+ 3 - 2
src/views/document/com/components/Attribute/Directory/index.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="com-directory" v-if="coms != null && coms.length > 0 && size > 0">
     <el-form class="dirceForm">
-      <template v-for="(sub) in coms" >
+      <template v-for="(sub) in coms">
         <template v-for="(item,index) in sub.attrs">
-          <el-form-item :key="index" v-if="item.type=='Directory'" :label="item.name + ' (引用名:[' + sub.id + '])'">
+          <el-form-item :key="index" v-if="item.type=='Directory'" :label="item.name + ' (引用名:[' + item.id + '])'">
             <el-input type="textarea" v-model="item.content"></el-input>
           </el-form-item>
         </template>
@@ -40,6 +40,7 @@ export default {
   watch: {
     coms: {
       handler(val) {
+        console.log(val);
         if (val == null) return;
         this.size = 0;
         for (var i = 0; i < val.length; i++) {

+ 224 - 286
src/views/document/com/components/Attribute/attributeVar/index.vue

@@ -1,301 +1,239 @@
 <template>
-    <div class="editor-attribute" v-if="com != null">
-             <!-- <el-cascader
-                v-model="com.category_id"
-                :options="categoryList"
-                :props="props"
-                @change="onChangeCategory"
-                placeholder="请选择模块分类"
-              /> --><!-- @change="onChangeCategory" -->
-      <el-form>
-        <!-- <el-form-item label="模块分类:">
-          <el-select
-            v-model="com.category_id"
-            placeholder="请选择模块分类"
-            size="large"
-            style="width: 100%"
-            >
-            <el-option
-              v-for="item in categoryList"
-              :key="item.id"
-              :label="item.name"
-              :value="item.id"
-            />
-          </el-select>
-     
-        </el-form-item>
-        <el-form-item label="模块引用名:">
-          <el-input
-            v-model="com.code"
-            class="input-item"
-            placeholder="请填写模块引用名"
-          />
-        </el-form-item>
-        <el-form-item label="模块名称:">
-          <el-input
-            v-model="com.name"
-            class="input-item"
-            placeholder="请填写模块名称"
-          />
-        </el-form-item>
-        <el-form-item label="模块描述:">
-          <el-input
-            type="textarea"
-            class="input-item"
-            v-model="com.intro"
-            placeholder="请填写模块介绍"
-          />
-        </el-form-item>
-        <el-form-item>
-          <div class="btn-save">
-            <el-button type="primary" size="mini" @click="onSaveTemplate(com)"
-              >保存模块</el-button
-            >
-            <el-button
-              type="primary"
-              size="mini"
-              @click="onSaveAs(com)"
-              v-if="com.id > 0"
-              >另存为</el-button
-            >
-          </div>
-        </el-form-item> -->
-        <template v-for="(sub, subIndex) in com.attrs">
-          <!-- 文本开始-->
-          <template v-if="com.type == 'TextArea'">
-            <template
-              v-if="
-                sub.type != 'pager' &&
-                sub.type != 'constant' &&
-                sub.type != 'attr' &&
-                sub.type != 'formual' &&
-                sub.type != 'sourceData'&&
-                sub.type !='Directory'
-              "
-            >
-              <el-form-item :label="sub.name + ' (引用名:[' + sub.id + '])'">
-                <el-input type="textarea" v-model="sub.content"></el-input>
-              </el-form-item>
-            </template>
-  
-            <template v-if="sub.type == 'formual'">
-              <el-form-item :label="sub.name + ' (引用名:[' + sub.id + '])'">
-                <el-input type="textarea" v-model="sub.formula"></el-input>
-              </el-form-item>
-            </template>
-  
-            <template v-if="sub.type == 'sourceData'">
-              <el-form-item :label="sub.name + ' (引用名:[' + sub.id + '])'">
-                {{ formatSourceData(sub.id, sub.formula) }}
-              </el-form-item>
-            </template>
+  <div class="editor-attribute" v-if="com != null">
+    <el-form>
+      <template v-for="(sub, subIndex) in filteredAttrs">
+        <template v-if="com.type == 'TextArea'">
+          <template v-if="isTextAreaType(sub.type)">
+            <el-form-item :label="sub.name + ' (引用名:[' + sub.id + '])'">
+              <el-input type="textarea" v-model="sub.content"></el-input>
+            </el-form-item>
+          </template>
+          <template v-if="sub.type == 'formual'">
+            <el-form-item :label="sub.name + ' (引用名:[' + sub.id + '])'">
+              <el-input type="textarea" v-model="sub.formula"></el-input>
+            </el-form-item>
+          </template>
+          <template v-if="sub.type == 'sourceData'">
+            <el-form-item :label="sub.name + ' (引用名:[' + sub.id + '])'">
+              {{ formatSourceData(sub.id, sub.formula) }}
+            </el-form-item>
           </template>
         </template>
-      </el-form>
-  
-      <el-dialog
-        :visible.sync="dialogVisible"
-        append-to-body
-        v-el-drag-dialog
-        width="300"
-        custom-class="prod-verify"
-        title="编辑表头"
-      >
-        <headerSetting
-          :headerItemName="headerItemName"
-          @onSetHeader="onSetHeader"
-        ></headerSetting>
-      </el-dialog>
-    </div>
-  </template>
-  
-  <script>
-  import headerSetting from "../headerSetting";
-  import elDragDialog from "@/directive/el-drag-dialog";
-  
-  import { getAllCategory, createTemplate, updateTemplate } from "@/api/template";
-  import { searchSourceDataCategory } from "@/api/sourceData";
-  import { searchDocumentCategory } from "@/api/document";
-  import { searchTemplateCategory, searchTemplate } from "@/api/template";
-  export default {
-    name: "attributes",
-    components: {
-      headerSetting,
+      </template>
+    </el-form>
+
+    <el-dialog
+      :visible.sync="dialogVisible"
+      append-to-body
+      v-el-drag-dialog
+      width="300"
+      custom-class="prod-verify"
+      title="编辑表头"
+    >
+      <headerSetting
+        :headerItemName="headerItemName"
+        @onSetHeader="onSetHeader"
+      ></headerSetting>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import headerSetting from "../headerSetting";
+import elDragDialog from "@/directive/el-drag-dialog";
+import { getAllCategory, createTemplate, updateTemplate } from "@/api/template";
+import { searchSourceDataCategory } from "@/api/sourceData";
+import { searchDocumentCategory } from "@/api/document";
+import { searchTemplateCategory, searchTemplate } from "@/api/template";
+
+export default {
+  name: "attributes",
+  components: { headerSetting },
+  directives: { elDragDialog },
+  emits: ["onRefresh"],
+  props: {
+    com: {
+      type: Object,
+      default: () => null,
     },
-    directives: { elDragDialog },
-    emits: ["onRefresh"],
-    props: {
-      com: {
-        type: Object,
-        default: () => {
-          return null;
-        },
+  },
+  watch: {
+    com: {
+      handler(newVal) {
+        if (newVal && newVal.content) {
+          this.processContent();
+        }
       },
+      deep: true,
     },
-    watch: {},
-    data() {
-      return {
-        dialogVisible: false,
-        activeNames: "0",
-        categoryList: [],
-        articleCategoryList: [],
-        activeHeaderIndex: -1,
-        headerItemName: "",
-        props: {
-          value: "id",
-          label: "name",
-          children: "children",
-        },
-      };
+  },
+  data() {
+    return {
+      dialogVisible: false,
+      activeNames: "0",
+      categoryList: [],
+      articleCategoryList: [],
+      activeHeaderIndex: -1,
+      headerItemName: "",
+      props: {
+        value: "id",
+        label: "name",
+        children: "children",
+      },
+      processedAttrs: [],
+    };
+  },
+  computed: {
+    filteredAttrs() {
+      return this.processedAttrs;
     },
-    mounted() {
-      this.initCategoryList();
+  },
+  mounted() {
+    this.initCategoryList();
+    if (this.com && this.com.content) {
+      this.processContent();
+    }
+  },
+  methods: {
+    isTextAreaType(type) {
+      return ![
+        "pager",
+        "constant",
+        "attr",
+        "formual",
+        "sourceData",
+        "Directory",
+      ].includes(type);
     },
-    methods: {
-      formatSourceData(id, e) {
-        var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
-        var reg = new RegExp(pattern);
-        let items = e.match(reg);
-        let data = id + "=" + items[2] + "." + items[3];
-  
-        var dataIndex = items[4];
-        dataIndex = items[4].split(",");
-        data +=
-          "." +
-          String.fromCharCode(65 + parseInt(dataIndex[1])) +
-          (parseInt(dataIndex[0]) + 1);
-        return data;
-      },
-  
-      onSaveAs(e) {
-        this.saveAs = true;
-        this.onSaveTemplate();
-      },
-  
-      onChangeCategory(e) {
-        let _this = this;
-        _this.com.category_id = e[1];
-      },
-  
-      onSaveTemplate(e) {
-        let _this = this;
-        /* e.category_id='1' */
-        let data = JSON.parse(JSON.stringify(e));
-        data.attrs = JSON.stringify(data.attrs);
-        data.status = 5;
-        delete data.category;
-        if (data.id == undefined || this.saveAs) {
-          createTemplate(data).then((res) => {
-            if (res.status != 200) return;
-            data.id = res.data;
-            _this.com.id = res.data;
-            _this.$alert("模板信息保存成功");
-            _this.$emit("onRefresh");
-            this.saveAs = false;
-          });
-        } else {
-          updateTemplate(data).then((res) => {
-            if (res.status != 200) return;
-            _this.$alert("模板信息更新成功");
-            _this.$emit("onRefresh");
-          });
+    extractChineseTemplates(content) {
+      const templateRegex = /\{\{(.*?)\}\}/g;
+      const chineseRegex = /[\u4e00-\u9fa5]/;
+      let match;
+      const chineseTemplates = [];
+
+      while ((match = templateRegex.exec(content)) !== null) {
+        if (chineseRegex.test(match[1])) {
+          chineseTemplates.push(match[1].trim());
         }
-      },
-  
-      /* initCategoryList(){
-            let _this=this;
-            searchSourceDataCategory({page:1,pageSize:99,status:''}).then(res=>{
-              _this.categoryList=res.data.sourcecategories;
-              
-            })
-        }, */
-      //获取模板分类信息
-      async initCategoryList() {
-        let _this = this;
-        let res = await searchTemplateCategory({
-          page: 1,
-          pageSize: 99,
-          status: 5,
-        });
-        if (res.status != 200) return;
-        _this.categoryList = res.data.dataList ||[];
-        for (var i = 0; i < _this.categoryList.length; i++) {
-          _this.categoryList[i].dataList = await _this.getTemplateList(
-            _this.categoryList[i].id
+      }
+
+      return chineseTemplates;
+    },
+    processContent() {
+      if (this.com && this.com.content) {
+        const chineseTemplates = this.extractChineseTemplates(this.com.content);
+        console.log("Chinese templates:", chineseTemplates);
+
+        if (this.com.attrs && Array.isArray(this.com.attrs)) {
+          this.processedAttrs = this.com.attrs.filter((el) =>
+            chineseTemplates.includes(el.id)
           );
         }
-      },
-  
-      onModify(index, subIndex, headerIndex) {
-        this.currentIndex = index;
-        this.componentIndex = subIndex;
-        this.activeHeaderIndex = headerIndex;
-        this.headerItemName =
-          this.components[index].components[subIndex].attrs.tableHeader[
-            headerIndex
-          ];
-        this.dialogVisible = true;
-      },
-      //设置名称
-      onSetHeader(name) {
-        if (this.currentIndex >= 0) {
-          if (this.activeHeaderIndex >= 0) {
-            this.components[this.currentIndex].components[
-              this.componentIndex
-            ].attrs.tableHeader[this.activeHeaderIndex] = name;
-          } else {
-            this.components[this.currentIndex].components[
-              this.componentIndex
-            ].attrs.tableHeader.push(name);
-          }
+      } else {
+        this.processedAttrs = [];
+      }
+    },
+    formatSourceData(id, e) {
+      const pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
+      const items = e.match(pattern);
+      const dataIndex = items[4].split(",");
+      return `${id}=${items[2]}.${items[3]}.${String.fromCharCode(
+        65 + parseInt(dataIndex[1])
+      )}${parseInt(dataIndex[0]) + 1}`;
+    },
+    async onSaveTemplate(e) {
+      const data = { ...e, attrs: JSON.stringify(e.attrs), status: 5 };
+      delete data.category;
+
+      if (data.id === undefined || this.saveAs) {
+        const res = await createTemplate(data);
+        if (res.status === 200) {
+          data.id = res.data;
+          this.com.id = res.data;
+          this.$alert("模板信息保存成功");
+          this.$emit("onRefresh");
+          this.saveAs = false;
         }
-        this.$emit("onSetComponents", [...this.components]);
-        this.dialogVisible = false;
-      },
-      onInsert(index, subIndex) {
-        this.currentIndex = index;
-        this.componentIndex = subIndex;
-        this.headerItemName = "";
-        this.dialogVisible = true;
-      },
-      //删除表头项
-      onDeleteHeaderItem(index, subIndex, headerIndex) {
-        this.components[index].components[subIndex].attrs.tableHeader.splice(
-          headerIndex,
-          1
-        );
-        this.$emit("onSetComponents", [...this.components]);
-      },
-  
-      onSetActiveIndex(e) {
-        if (e == this.activeHeaderIndex) {
-          this.activeHeaderIndex = -1;
+      } else {
+        const res = await updateTemplate(data);
+        if (res.status === 200) {
+          this.$alert("模板信息更新成功");
+          this.$emit("onRefresh");
+        }
+      }
+    },
+    async initCategoryList() {
+      const res = await searchTemplateCategory({
+        page: 1,
+        pageSize: 99,
+        status: 5,
+      });
+      if (res.status === 200) {
+        this.categoryList = res.data.dataList || [];
+        for (const category of this.categoryList) {
+          category.dataList = await this.getTemplateList(category.id);
+        }
+      }
+    },
+    async getTemplateList(categoryId) {
+      const res = await searchTemplate({
+        page: 1,
+        pageSize: 999,
+        category_id: categoryId,
+        status: 5,
+      });
+      if (res.status === 200) {
+        return res.data.dataList.map((item) => ({
+          ...item,
+          attrs: JSON.parse(item.attrs),
+        }));
+      }
+      return [];
+    },
+    onModify(index, subIndex, headerIndex) {
+      this.currentIndex = index;
+      this.componentIndex = subIndex;
+      this.activeHeaderIndex = headerIndex;
+      this.headerItemName =
+        this.components[index].components[subIndex].attrs.tableHeader[
+          headerIndex
+        ];
+      this.dialogVisible = true;
+    },
+    onSetHeader(name) {
+      if (this.currentIndex >= 0) {
+        const header =
+          this.components[this.currentIndex].components[this.componentIndex]
+            .attrs.tableHeader;
+        if (this.activeHeaderIndex >= 0) {
+          header[this.activeHeaderIndex] = name;
         } else {
-          this.activeHeaderIndex = e;
+          header.push(name);
         }
-      },
-      //获取模板列表
-      async getTemplateList(categoryId) {
-        let _this = this;
-        let res = await searchTemplate({
-          page: 1,
-          pageSize: 999,
-          category_id: categoryId,
-          status: 5,
-        });
-        if (res.status != 200) return [];
-  
-        let dataList = res.data.dataList.map((item) => {
-          item.attrs = JSON.parse(item.attrs);
-          return item;
-        });
-        return dataList;
-      },
+      }
+      this.$emit("onSetComponents", [...this.components]);
+      this.dialogVisible = false;
+    },
+    onInsert(index, subIndex) {
+      this.currentIndex = index;
+      this.componentIndex = subIndex;
+      this.headerItemName = "";
+      this.dialogVisible = true;
+    },
+    onDeleteHeaderItem(index, subIndex, headerIndex) {
+      this.components[index].components[subIndex].attrs.tableHeader.splice(
+        headerIndex,
+        1
+      );
+      this.$emit("onSetComponents", [...this.components]);
+    },
+    onSetActiveIndex(e) {
+      this.activeHeaderIndex = e === this.activeHeaderIndex ? -1 : e;
     },
-  };
-  </script>
-  
-  <style lang="scss">
-  @import "./index.scss";
-  </style>
-  
+  },
+};
+</script>
+
+<style lang="scss">
+@import "./index.scss";
+</style>

+ 76 - 11
src/views/document/com/components/Formula/dataInfo.vue

@@ -7,7 +7,12 @@
         </el-form-item>
 
         <el-form-item label="公式:">
-          <el-input type="textarea" v-model="dataForm.formula"></el-input>
+          <el-input
+            type="textarea"
+            v-model="dataForm.formula"
+            @input="handleFormulaInput"
+            ref="formulaInput"
+          ></el-input>
           <div style="display: flex; justify-content: flex-end">
             <el-button style="margin-top: 10px" @click="InsertTableData"
               >插入表格数据</el-button
@@ -60,6 +65,8 @@
       width="300"
       custom-class="prod-verify"
       :title="title"
+      :close-on-click-modal="false"
+       @close="close"
     >
       <el-form :model="insertForm" :rules="insertRules" ref="insertRef">
         <el-form-item label="模块名称:">
@@ -104,6 +111,8 @@
       width="400"
       custom-class="prod-verify"
       title="插入表格数据"
+      :close-on-click-modal="false"
+      @close="close"
     >
       <div class="com-formual">
         <el-form>
@@ -139,6 +148,7 @@
       width="500"
       align-center
       :append-to-body="true"
+      :close-on-click-modal="false"
     >
       <div>当前工作表:{{ position.sheet }}</div>
       <div>当前取值:{{ position.value }}</div>
@@ -191,8 +201,8 @@ export default {
       deep: true,
     },
     list: {
-      handler(value) {
-        console.log(value);
+      handler(newValue, oldValue) {
+        console.log("list changed:", newValue);
       },
       immediate: true,
       deep: true,
@@ -209,7 +219,7 @@ export default {
         name: "",
         formula: "",
         intro: "",
-        status: "",
+        status: 5,
         use_status: 5,
         params: "[]",
       },
@@ -230,10 +240,9 @@ export default {
       variablesVisible: false,
       title: "",
       insertForm: {
-        moduleName: "",
+        moduleName: '',
         Variable: "",
       },
-      attrList: [],
       insertRules: {
         Variable: [
           { required: true, message: "请选择变量", trigger: "change" },
@@ -251,6 +260,7 @@ export default {
         sheet: "",
         value: "",
       },
+      attrList: [],
     };
   },
 
@@ -259,19 +269,37 @@ export default {
     this.initTableList();
   },
   methods: {
+    /* 关闭 */
+    close() {
+      this.insertForm = {
+      };
+    },
+    /*  */
+    handleFormulaInput(value) {
+      // 更新 dataForm.formula 的值
+      this.dataForm.formula = value;
+    },
     //保存更新
     btnSave(e) {
       let _this = this;
 
       if (_this.dataForm.id > 0) {
         updateFormula(_this.dataForm).then((res) => {
-          _this.dataForm={}
-          _this.$alter("公式更新成功");
+          _this.dataForm = {
+            status: 5,
+            use_status: 5,
+            params: "[]",
+          };
+          _this.$message.success("公式更新成功");
         });
       } else {
         createFormula(_this.dataForm).then((res) => {
-          _this.dataForm={}
-          _this.$alter("公式创建的成功");
+          _this.dataForm = {
+            status: 5,
+            use_status: 5,
+            params: "[]",
+          };
+          _this.$message.success("公式创建的成功");
         });
       }
       _this.$emit("onClose");
@@ -303,9 +331,42 @@ export default {
       this.variablesVisible = true;
       this.title = "插入模块变量";
     },
+    extractChineseTemplates(content) {
+      const templateRegex = /\{\{(.*?)\}\}/g;
+      const chineseRegex = /[\u4e00-\u9fa5]/;
+      let match;
+      const chineseTemplates = [];
+
+      while ((match = templateRegex.exec(content)) !== null) {
+        if (chineseRegex.test(match[1])) {
+          chineseTemplates.push(match[1].trim());
+        }
+      }
+
+      return chineseTemplates;
+    },
+    processContent(val) {
+      console.log(val);
+      if (val && val.content) {
+        const chineseTemplates = this.extractChineseTemplates(val.content);
+        console.log("Chinese templates:", chineseTemplates);
+
+        if (val.attrs && Array.isArray(val.attrs)) {
+          this.attrList = val.attrs.filter((el) =>
+            chineseTemplates.includes(el.id)
+          );
+        }
+      } else {
+        this.attrList = [];
+      }
+    },
     /* 模块名称 */
     changeModule(value) {
-      this.attrList = value;
+      const selectedIndex = this.list.findIndex(
+        (option) => option.attrs === value
+      );
+      this.processContent(this.list[selectedIndex]);
+      //this.attrList = value; // 假设 attrs 属性包含了属性列表
     },
     /* 插入变量 */
     btnInster() {
@@ -350,6 +411,10 @@ export default {
       this.dataForm.formula += insertText;
       this.tableDataVisible = false;
       this.$message.success("表格数据插入成功");
+      this.insertForm = {
+        moduleName: {},
+        Variable: "",
+      };
     },
 
     onChangeTab(e) {

+ 10 - 2
src/views/document/com/components/Formula/index.vue

@@ -20,7 +20,7 @@
                 <div class="btns">
                   <el-button type="primary" size="mini" @click="btnPicked(scope.row)"><svg-icon icon-class="confirm"/>使用</el-button>
                   <el-button type="primary" size="mini" @click="btnOnEdit(scope.row.id)"><svg-icon icon-class="edit"/>编辑</el-button>
-                  <el-button type="danger" size="mini"><svg-icon icon-class="delete"/>删除</el-button>
+                  <el-button type="danger" size="mini" @click="btnDel(scope.row.id)"><svg-icon icon-class="delete"/>删除</el-button>
                 </div>
               </template>
             </el-table-column>
@@ -51,7 +51,7 @@
 </template>
 
 <script>
-  import{searchFormula} from'@/api/formula';
+  import{searchFormula,deleteFormula} from'@/api/formula';
   import dataInfo from "./dataInfo";
   import elDragDialog from '@/directive/el-drag-dialog'
 
@@ -131,6 +131,14 @@
      	_this.queryForm.page=e;
      	_this.search();
      },
+     /* 删除 */
+     btnDel(e){
+      let _this=this;
+      deleteFormula({id:e}).then(res=>{
+        _this.$message.success("删除成功!")
+        _this.search();
+      })
+     }
     }
   }
 </script>

+ 105 - 24
src/views/document/com/components/TextArea/index.vue

@@ -80,16 +80,19 @@ export default {
       deep: true,
     },
     com: {
-      handler(val) {
+      async handler(val) {
         let _this = this;
         if (val == null) return;
         if (val.content == undefined || val.content == null) return;
-        _this.replaceData(val.content).then((res) => {
+        try {
+          let res = await _this.replaceData(val.content);
           _this.content = res;
           _this.$nextTick(() => {
             _this.bindEvents();
           });
-        });
+        } catch (error) {
+          console.error("处理 com 时出错:", error);
+        }
       },
       immediate: true,
       deep: true,
@@ -126,12 +129,13 @@ export default {
       editor: null,
       loading: false,
       progress: 0,
-      isEditing:false
+      isEditing: false,
     };
   },
   mounted() {},
   methods: {
     async replaceData(data) {
+      console.log(this.com.attrs);
       let _this = this;
       for (var i = 0; i < _this.com.attrs.length; i++) {
         let attrId = _this.com.attrs[i].id;
@@ -227,19 +231,55 @@ export default {
             data = data.replace("{{" + item.id + "}}", selectHtml);
           }
         } else if (_this.com.attrs[i].type == "formual") {
-          // console.log('attrs',_this.com.attrs[i]);
+          //// console.log('attrs',_this.com.attrs[i]);
           //处理计算公式 不处理
-          let formual = await _this.analysisFormual(_this.com.attrs[i]);
+           let formual = await _this.analysisFormual(_this.com.attrs[i]);
 
           formual = await _this.getRemote(formual);
-
+          _this.com.attrs[i].content= eval(formual)
           data = data.replace("{{" + attrId + "}}", eval(formual));
+
+          /* let formual = await _this.analysisFormual(_this.com.attrs[i]);
+          formual = await _this.getRemote(formual);
+          // 使用 try-catch 来处理可能的计算错误
+          try {
+            let result = eval(formual);
+            data = data.replace("{{" + attrId + "}}", result);
+          } catch (error) {
+            data = data.replace("{{" + attrId + "}}", "计算错误");
+          } */
         } else if (_this.com.attrs[i].type == "sourceData") {
           let result = await _this.getRemote1(_this.com.attrs[i].formula);
           data = data.replace("{{" + attrId + "}}", result);
         } else if (_this.com.attrs[i].type == "Directory") {
+          const directoryContent = _this.com.attrs[i].content;
+          const attrId = _this.com.attrs[i].id;
+
+          // Create a more flexible regex pattern
+          const directoryRegex = new RegExp(`{{\\s*${attrId}\\s*}}`, "g");
+
+          // Replace the content, preserving surrounding HTML tags
+          data = data.replace(directoryRegex, (match, offset, string) => {
+            // Check if the match is inside a tag
+            const precedingText = string.substring(0, offset);
+            const followingText = string.substring(offset + match.length);
+            const precedingTag = precedingText.match(/<([^>]+)>$/);
+            const followingCloseTag = followingText.match(/^<\/([^>]+)>/);
+
+            if (
+              precedingTag &&
+              followingCloseTag &&
+              precedingTag[1] === followingCloseTag[1]
+            ) {
+              // If it's inside matching tags, replace the entire element
+              return `<h1>${directoryContent}</h1>`;
+            } else {
+              // Otherwise, just replace the placeholder
+              return directoryContent;
+            }
+          });
           //处理目录
-          data = data.replace(
+          /* data = data.replace(
             "<p>{{" + attrId + "}}</p>",
             "<h1>" + _this.com.attrs[i].content + "</h1>"
           );
@@ -250,7 +290,14 @@ export default {
           data = data.replace(
             "<span>{{" + attrId + "}}</span>",
             "<h1>" + _this.com.attrs[i].content + "</h1>"
+          ); */
+          //处理目录
+          /*  const directoryContent = _this.com.attrs[i].content;
+          const directoryRegex = new RegExp(
+            `<(p|div|span)>{{${attrId}}}</(p|div|span)>`,
+            "g"
           );
+          data = data.replace(directoryRegex, `<h1>${directoryContent}</h1>`); */
         } else {
           //处理常量及其它
           data = data.replace("{{" + attrId + "}}", _this.com.attrs[i].content);
@@ -294,6 +341,7 @@ export default {
     //分析公式
     async analysisFormual(attrs) {
       let _this = this;
+      // console.log("开始分析公式:", attrs.formula);
       var pattern = /(\[.*?\]){3}/;
       var formual = attrs.formula;
       var reg = new RegExp(pattern);
@@ -301,22 +349,39 @@ export default {
         var items = formual.match(reg);
         if (items == null) break;
         let itemName = items[0];
-        let data = await _this.getFormualData(itemName);
-        formual = formual.replace(itemName, "(" + parseFloat(data) + ")");
+        // console.log("处理项:", itemName);
+        try {
+          let data = await _this.getFormualData(itemName);
+          // console.log(`获取到的数据: ${itemName} = ${data}`);
+          if (data === null || data === undefined || isNaN(data)) {
+            console.warn(`获取到的数据无效: ${itemName}`);
+            formual = formual.replace(itemName, "(0)");
+          } else {
+            formual = formual.replace(itemName, `(${parseFloat(data)})`);
+          }
+        } catch (error) {
+          console.error(`处理 ${itemName} 时出错:`, error);
+          formual = formual.replace(itemName, "(0)");
+        }
       }
+      // console.log("分析后的公式:", formual);
       return formual;
     },
 
     async getFormualData(formualItem) {
       let _this = this;
+      // console.log("开始获取公式数据:", formualItem);
       var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
       var reg = new RegExp(pattern);
       let items = formualItem.match(reg);
+      // console.log("解析结果:", items);
       let calResult = 0;
-      if (items[1] == "T") {
-        //表示本地模板数据
+      if (items && items[1] == "T") {
         calResult = await _this.getModuleData(items[2], items[3]);
+      } else {
+        console.warn("无法解析公式项:", formualItem);
       }
+      // console.log("计算结果:", calResult);
       return calResult;
     },
 
@@ -347,7 +412,10 @@ export default {
           } else {
             formual = formual.replace(itemName, `"${calResult}"`);
           }
-          /* formual=formual.replace(itemName,"("+parseFloat(calResult)+")"); */
+          formual = formual.replace(
+            itemName,
+            "(" + parseFloat(calResult) + ")"
+          );
         }
       }
       return formual;
@@ -403,7 +471,7 @@ export default {
         col: col,
       };
 
-      if (!this.isEditing) {
+      /*  if (!this.isEditing) {
         this.loading = true;
         this.progress = 0;
 
@@ -429,30 +497,43 @@ export default {
             this.progress = 0;
           }, 1000);
         }
-      } else {
-        // 如果正在编辑,直接获取数据而不显示进度条
-        try {
-          let res = await findData(par);
-          if (res.status == 200) {
-            result = res.data.result;
+      } else { */
+      // 如果正在编辑,直接获取数据而不显示进度条
+      try {
+        let res = await findData(par);
+        if (res.status == 200) {
+          result = res.data.result;
+          // 添加数据类型检查和转换
+          if (typeof result === "string" && !isNaN(result)) {
+            result = parseFloat(result);
           }
-        } catch (error) {
-          console.error("Error fetching remote data:", error);
         }
+      } catch (error) {
+        console.error("获取远程数据错误:", error);
       }
+      /*   } */
 
       return result;
     },
     //获取本地文档模块数据
     async getModuleData(code, attrName) {
       let _this = this;
-      let item = _this.coms.filter((o) => o.code == code);
+      // console.log(`尝试获取模块数据: code=${code}, attrName=${attrName}`);
+      // console.log("当前 coms:", _this.coms);
+
+      let item = _this.coms.filter((o) => o.name == code);
+      // console.log(`找到的模块:`, item);
+
       if (item.length > 0) {
         let attr = item[0].attrs.filter((o) => o.name == attrName);
+        // console.log(`找到的属性:`, attr);
+
         if (attr.length > 0) {
+          // console.log(`返回的值:`, attr[0].content);
           return parseFloat(attr[0].content);
         }
       }
+      // console.log("未找到匹配的模块或属性,返回 0");
       return 0;
     },
 
@@ -493,7 +574,7 @@ export default {
       // e.editor.insertText("AAA");
     },
     onBlur(e) {
-      // console.log(' onBlur e',e);
+      //// console.log(' onBlur e',e);
       // this.$emit("onUploadAttr",this.dataIndex,this.dataAttr);
     }, */
   },

+ 47 - 7
src/views/document/com/components/Variable/index.vue

@@ -6,8 +6,8 @@
       v-if="type == 1"
       class="demo-form-inline"
     >
-      <!-- <el-form-item label="类型:">
-            <el-select v-model="queryForm.type"  placeholder="请选择状态" size="large" style="width:100%;">
+      <el-form-item label="类型:">
+            <el-select v-model="queryForm.type"  placeholder="请选择类型" size="large" style="width:100%;">
                 <el-option
                   v-for="item in typeList"
                   :key="item.value"
@@ -15,7 +15,7 @@
                   :value="item.value"
                 />
               </el-select>
-          </el-form-item> -->
+          </el-form-item>
       <el-form-item label="变名称:">
         <el-input
           v-model="queryForm.name"
@@ -31,15 +31,46 @@
         >
       </el-form-item>
     </el-form>
+    <el-form
+      :inline="true"
+      :model="queryForm"
+      v-if="type == 2"
+      class="demo-form-inline"
+    >
+      <!-- <el-form-item label="类型:">
+            <el-select v-model="queryForm.type"  placeholder="请选择类型" size="large" style="width:100%;">
+                <el-option
+                  v-for="item in typeList"
+                  :key="item.value"
+                  :label="item.name"
+                  :value="item.value"
+                />
+              </el-select>
+          </el-form-item>
+      <el-form-item label="变名称:">
+        <el-input
+          v-model="queryForm.name"
+          placeholder="请填写变量名称"
+        ></el-input>
+      </el-form-item> -->
+      <el-form-item>
+        <!-- <el-button type="primary" @click="onBtnSearch">
+          <svg-icon icon-class="search" /> 搜索</el-button
+        > -->
+        <el-button type="primary" @click="onBtnConst">
+          <svg-icon icon-class="plus" /> 新增常量</el-button
+        >
+      </el-form-item>
+    </el-form>
     <el-table
       :data="dataList"
       style="width: 100%"
       header-row-class-name="headerBg"
       empty-text="没有数据信息"
     >
-      <el-table-column prop="id" label="ID" align="center" width="80" />
-      <el-table-column prop="code" label="编码" align="left" width="150" />
-      <el-table-column prop="name" label="名称" align="left" width="150" />
+      <el-table-column prop="id" label="ID" align="center"  />
+      <el-table-column prop="code" label="编码" align="left" />
+      <el-table-column prop="name" label="名称" align="left" />
       <el-table-column
         prop="value"
         label="取值"
@@ -53,7 +84,7 @@
         label="操作"
         align="center"
         :width="type == 1 ? 250 : 100"
-        fixed="right"
+        
       >
         <template #default="scope">
           <div class="btns">
@@ -132,6 +163,7 @@ export default {
   watch: {
     type: {
       handler(val) {
+        console.log(val);
         this.queryForm.type = val;
         this.onBtnSearch();
       },
@@ -250,6 +282,14 @@ export default {
       _this.queryForm.page = e;
       _this.search();
     },
+    /* 新增常量 */
+    onBtnConst(){
+      let _this = this;
+      _this.dataId = 0;
+      _this.type=2
+      _this.title = "创建常量";
+      _this.dialogVisible = true;
+    }
   },
 };
 </script>

+ 7 - 7
src/views/document/com/menus.vue

@@ -35,7 +35,7 @@
       </el-dialog>
 
        <!-- ai -->
-       <el-dialog  :visible.sync="showSourceEs" append-to-body v-el-drag-dialog  width="300":close-on-click-modal="false" custom-class="prod-verify" title="AI随笔">
+       <el-dialog  :visible.sync="showSourceEs" append-to-body v-el-drag-dialog  width="300" :close-on-click-modal="false" custom-class="prod-verify" title="AI随笔">
           <sourceEs  @onPicked="onPickedAi"></sourceEs>
       </el-dialog>
 
@@ -103,11 +103,11 @@
                 name:"变量",
                 icon:"insertParams",
               },
-              // {
-              //   key:"constant",
-              //   name:"常量",
-              //   icon:"constant",
-              // },
+              {
+                key:"constant",
+                name:"常量",
+                icon:"constant",
+              },
               {
                 key:"attr",
                 name:"属性",
@@ -203,6 +203,7 @@
             content:e,
         }
         this.$emit("onEvents",item);
+        console.log(item);
         this.showFormula=false;
       },
       onPickedVariable(e){
@@ -216,7 +217,6 @@
         this.showVariable=false;
       },
       onClickMenus(e){
-        console.log(e);
           e.type="insert";
           if(e.key=="formual"){
               this.showFormula=true;

+ 189 - 1
src/views/document/com/view.vue

@@ -4,7 +4,7 @@
       <template v-for="(item, index) in coms">
         <component
           :key="index"
-          :is="item.type"
+          :is="getComponentType(item.type)"
           :com="item"
           :coms="comList"
           :currentIndex="index"
@@ -25,6 +25,7 @@ import TextArea from "./components/TextView";
 import htmlDocx from "html-docx-js/dist/html-docx";
 import saveAs from "file-saver";
 import jsPDF from "jspdf";
+import { findData } from "@/api/sourceData";
 import { createDocument } from "html-to-docx";
 
 export default {
@@ -54,6 +55,7 @@ export default {
         if (val == null) return;
         this.comList = JSON.parse(JSON.stringify(val));
         console.log("comList", this.comList);
+        this.replaceData(val);
       },
       immediate: true,
       deep: true,
@@ -66,15 +68,201 @@ export default {
     };
   },
   methods: {
+    async replaceData(data) {
+      for (let item of this.comList) {
+        for (let el of item.attrs) {
+          let attrId = el.id;
+          if (el.type == "formual") {
+            try {
+              let formual = await this.analysisFormual(el);
+
+              formual = await this.getRemote(formual);
+              el.content = eval(formual);
+              
+              /* data = data.replace("{{" + attrId + "}}", eval(formual)); */
+            } catch (error) {
+              console.error("处理公式时出错:", error);
+            }
+          }
+        }
+      }
+      this.$emit('update:coms', [...this.comList])
+      return data;
+    },
+    //分析公式
+    async analysisFormual(attrs) {
+      let _this = this;
+      // console.log("开始分析公式:", attrs.formula);
+      var pattern = /(\[.*?\]){3}/;
+      var formual = attrs.formula;
+      var reg = new RegExp(pattern);
+      while (true) {
+        var items = formual.match(reg);
+        if (items == null) break;
+        let itemName = items[0];
+        // console.log("处理项:", itemName);
+        try {
+          let data = await _this.getFormualData(itemName);
+          // console.log(`获取到的数据: ${itemName} = ${data}`);
+          if (data === null || data === undefined || isNaN(data)) {
+            console.warn(`获取到的数据无效: ${itemName}`);
+            formual = formual.replace(itemName, "(0)");
+          } else {
+            formual = formual.replace(itemName, `(${parseFloat(data)})`);
+          }
+        } catch (error) {
+          console.error(`处理 ${itemName} 时出错:`, error);
+          formual = formual.replace(itemName, "(0)");
+        }
+      }
+      // console.log("分析后的公式:", formual);
+      return formual;
+    },
+    async getFormualData(formualItem) {
+      let _this = this;
+      // console.log("开始获取公式数据:", formualItem);
+      var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
+      var reg = new RegExp(pattern);
+      let items = formualItem.match(reg);
+      // console.log("解析结果:", items);
+      let calResult = 0;
+      if (items && items[1] == "T") {
+        calResult = await _this.getModuleData(items[2], items[3]);
+      } else {
+        console.warn("无法解析公式项:", formualItem);
+      }
+      // console.log("计算结果:", calResult);
+      return calResult;
+    },
+    //获取本地文档模块数据
+    async getModuleData(code, attrName) {
+      let _this = this;
+      // console.log(`尝试获取模块数据: code=${code}, attrName=${attrName}`);
+      // console.log("当前 coms:", _this.coms);
+
+      let item = _this.comList.filter((o) => o.name == code);
+      // console.log(`找到的模块:`, item);
+
+      if (item.length > 0) {
+        let attr = item[0].attrs.filter((o) => o.name == attrName);
+        // console.log(`找到的属性:`, attr);
+
+        if (attr.length > 0) {
+          // console.log(`返回的值:`, attr[0].content);
+          return parseFloat(attr[0].content);
+        }
+      }
+      // console.log("未找到匹配的模块或属性,返回 0");
+      return 0;
+    },
+
+    async getRemote(formual) {
+      let _this = this;
+      var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
+      var reg = new RegExp(pattern);
+      while (true) {
+        let items = formual.match(reg);
+        if (items == null) break;
+        if (items[1] == "R") {
+          //表示获取远程数据
+          var dataIndex = items[4];
+          dataIndex = items[4].split(",");
+          let calResult = await _this.getRemoteData(
+            items[2],
+            items[3],
+            dataIndex[0],
+            dataIndex[1]
+          );
+          let itemName = items[0];
+          // 检查calResult是否为数字
+          if (!isNaN(calResult)) {
+            formual = formual.replace(
+              itemName,
+              "(" + parseFloat(calResult) + ")"
+            );
+          } else {
+            formual = formual.replace(itemName, `"${calResult}"`);
+          }
+          formual = formual.replace(
+            itemName,
+            "(" + parseFloat(calResult) + ")"
+          );
+        }
+      }
+      return formual;
+    },
+    async getRemoteData(code, sheet, row, col) {
+      let _this = this;
+      let result = 0;
+      let par = {
+        code: code,
+        sheetName: sheet,
+        row: row,
+        col: col,
+      };
+
+      /*  if (!this.isEditing) {
+        this.loading = true;
+        this.progress = 0;
+
+        try {
+          const updateProgress = setInterval(() => {
+            if (this.progress < 90) {
+              this.progress += 10;
+            }
+          }, 100);
+
+          let res = await findData(par);
+          if (res.status == 200) {
+            result = res.data.result;
+          }
+
+          this.progress = 100;
+          clearInterval(updateProgress);
+        } catch (error) {
+          console.error("Error fetching remote data:", error);
+        } finally {
+          setTimeout(() => {
+            this.loading = false;
+            this.progress = 0;
+          }, 1000);
+        }
+      } else { */
+      // 如果正在编辑,直接获取数据而不显示进度条
+      try {
+        let res = await findData(par);
+        if (res.status == 200) {
+          result = res.data.result;
+          // 添加数据类型检查和转换
+          if (typeof result === "string" && !isNaN(result)) {
+            result = parseFloat(result);
+          }
+        }
+      } catch (error) {
+        console.error("获取远程数据错误:", error);
+      }
+      /*   } */
+
+      return result;
+    },
+    getComponentType(type) {
+      if (type === "textarea") {
+        return TextArea;
+      }
+      // Add other component types if needed
+      return type;
+    },
     onUpdateData(index, data) {
       this.comList[index].content = data;
       this.rebuildContent();
+      this.$emit('update:coms', [...this.comList])
     },
     rebuildContent() {
       this.content = this.comList.map((item) => item.content).join("");
       console.log(this.content);
     },
     onExport() {
+      this.$emit('update:coms', [...this.comList])
       // Clone the content element to avoid modifying the original DOM
       let contentClone = this.$refs.content.cloneNode(true);
 

+ 1 - 1
src/views/document/create.scss

@@ -189,7 +189,7 @@
  */
  .right-sidebarew{
   position: absolute;
-  left: 203px;
+  left: 198px;
   top: 10px;
   display: flex;
   writing-mode: vertical-rl;

+ 262 - 35
src/views/document/create.vue

@@ -21,13 +21,25 @@
           v-if="docAttr.is_template == 0 && docAttr.id > 0"
           >更新文档</el-button
         >
-        <el-button
+        <el-popover placement="bottom" trigger="click">
+          <el-button @click="onSaveUpload">保存</el-button>
+          <el-button @click="onUpload">更新</el-button>
+          <el-button
+            slot="reference"
+            type="primary"
+            size="mini"
+            style="margin: 0 10px"
+            v-if="$store.state.user.name == 'admin'"
+            >保存并更新模版</el-button
+          >
+        </el-popover>
+        <!-- <el-button
           type="primary"
           size="mini"
           v-if="$store.state.user.name == 'admin'"
           @click="onSaveUpload"
           >保存并更新模版</el-button
-        >
+        > -->
         <el-button type="primary" size="mini" @click="onOpenView"
           >预览导出
         </el-button>
@@ -157,21 +169,21 @@
             </el-collapse>
           </div>
         </div>
-      </div>
-      <div class="right-sidebarew">
-        <div
-          class="sidebar-item"
-          :class="showView == 0 ? 'active-item' : ''"
-          @click="viewDocument"
-        >
-          查看文档
-        </div>
-        <div
-          class="sidebar-item"
-          :class="showView == 1 ? 'active-item' : ''"
-          @click="viewModule"
-        >
-          查看模块
+        <div class="right-sidebarew">
+          <div
+            class="sidebar-item"
+            :class="showView == 0 ? 'active-item' : ''"
+            @click="viewDocument"
+          >
+            查看文档
+          </div>
+          <div
+            class="sidebar-item"
+            :class="showView == 1 ? 'active-item' : ''"
+            @click="viewModule"
+          >
+            查看模块
+          </div>
         </div>
       </div>
 
@@ -300,6 +312,7 @@
 </template>
 
 <script>
+import { findData } from "@/api/sourceData";
 import utils from "@/utils/fun"; // 方法类
 import { searchDocument } from "@/api/document";
 import menus from "./com/menus";
@@ -390,8 +403,8 @@ export default {
   },
   watch: {
     coms: {
-      handler(val) {
-        // console.log("watch com val:",val);
+      handler(val, value) {
+        this.replaceData(val);
       },
       immediate: true, //立即执行
       deep: true,
@@ -421,6 +434,186 @@ export default {
   },
 
   methods: {
+
+    async replaceData(data) {
+      for (let item of this.coms) {
+        for (let el of item.attrs) {
+          let attrId = el.id;
+          if (el.type == "formual") {
+            try {
+              let formual = await this.analysisFormual(el);
+
+              formual = await this.getRemote(formual);
+              el.content = eval(formual);
+              
+              /* data = data.replace("{{" + attrId + "}}", eval(formual)); */
+            } catch (error) {
+              console.error("处理公式时出错:", error);
+            }
+          }
+        }
+      }
+      console.log("this.coms",this.coms);
+      return data;
+    },
+    //分析公式
+    async analysisFormual(attrs) {
+      let _this = this;
+      // console.log("开始分析公式:", attrs.formula);
+      var pattern = /(\[.*?\]){3}/;
+      var formual = attrs.formula;
+      var reg = new RegExp(pattern);
+      while (true) {
+        var items = formual.match(reg);
+        if (items == null) break;
+        let itemName = items[0];
+        // console.log("处理项:", itemName);
+        try {
+          let data = await _this.getFormualData(itemName);
+          // console.log(`获取到的数据: ${itemName} = ${data}`);
+          if (data === null || data === undefined || isNaN(data)) {
+            console.warn(`获取到的数据无效: ${itemName}`);
+            formual = formual.replace(itemName, "(0)");
+          } else {
+            formual = formual.replace(itemName, `(${parseFloat(data)})`);
+          }
+        } catch (error) {
+          console.error(`处理 ${itemName} 时出错:`, error);
+          formual = formual.replace(itemName, "(0)");
+        }
+      }
+      // console.log("分析后的公式:", formual);
+      return formual;
+    },
+    async getFormualData(formualItem) {
+      let _this = this;
+      // console.log("开始获取公式数据:", formualItem);
+      var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
+      var reg = new RegExp(pattern);
+      let items = formualItem.match(reg);
+      // console.log("解析结果:", items);
+      let calResult = 0;
+      if (items && items[1] == "T") {
+        calResult = await _this.getModuleData(items[2], items[3]);
+      } else {
+        console.warn("无法解析公式项:", formualItem);
+      }
+      // console.log("计算结果:", calResult);
+      return calResult;
+    },
+    //获取本地文档模块数据
+    async getModuleData(code, attrName) {
+      let _this = this;
+      // console.log(`尝试获取模块数据: code=${code}, attrName=${attrName}`);
+      // console.log("当前 coms:", _this.coms);
+
+      let item = _this.coms.filter((o) => o.name == code);
+      // console.log(`找到的模块:`, item);
+
+      if (item.length > 0) {
+        let attr = item[0].attrs.filter((o) => o.name == attrName);
+        // console.log(`找到的属性:`, attr);
+
+        if (attr.length > 0) {
+          // console.log(`返回的值:`, attr[0].content);
+          return parseFloat(attr[0].content);
+        }
+      }
+      // console.log("未找到匹配的模块或属性,返回 0");
+      return 0;
+    },
+
+    async getRemote(formual) {
+      let _this = this;
+      var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
+      var reg = new RegExp(pattern);
+      while (true) {
+        let items = formual.match(reg);
+        if (items == null) break;
+        if (items[1] == "R") {
+          //表示获取远程数据
+          var dataIndex = items[4];
+          dataIndex = items[4].split(",");
+          let calResult = await _this.getRemoteData(
+            items[2],
+            items[3],
+            dataIndex[0],
+            dataIndex[1]
+          );
+          let itemName = items[0];
+          // 检查calResult是否为数字
+          if (!isNaN(calResult)) {
+            formual = formual.replace(
+              itemName,
+              "(" + parseFloat(calResult) + ")"
+            );
+          } else {
+            formual = formual.replace(itemName, `"${calResult}"`);
+          }
+          formual = formual.replace(
+            itemName,
+            "(" + parseFloat(calResult) + ")"
+          );
+        }
+      }
+      return formual;
+    },
+    async getRemoteData(code, sheet, row, col) {
+      let _this = this;
+      let result = 0;
+      let par = {
+        code: code,
+        sheetName: sheet,
+        row: row,
+        col: col,
+      };
+
+      /*  if (!this.isEditing) {
+        this.loading = true;
+        this.progress = 0;
+
+        try {
+          const updateProgress = setInterval(() => {
+            if (this.progress < 90) {
+              this.progress += 10;
+            }
+          }, 100);
+
+          let res = await findData(par);
+          if (res.status == 200) {
+            result = res.data.result;
+          }
+
+          this.progress = 100;
+          clearInterval(updateProgress);
+        } catch (error) {
+          console.error("Error fetching remote data:", error);
+        } finally {
+          setTimeout(() => {
+            this.loading = false;
+            this.progress = 0;
+          }, 1000);
+        }
+      } else { */
+      // 如果正在编辑,直接获取数据而不显示进度条
+      try {
+        let res = await findData(par);
+        if (res.status == 200) {
+          result = res.data.result;
+          // 添加数据类型检查和转换
+          if (typeof result === "string" && !isNaN(result)) {
+            result = parseFloat(result);
+          }
+        }
+      } catch (error) {
+        console.error("获取远程数据错误:", error);
+      }
+      /*   } */
+
+      return result;
+    },
+
+/*  */
     handleItemVal(value) {
       this.$forceUpdate();
     },
@@ -538,6 +731,7 @@ export default {
     },
 
     onOpenView(e) {
+      console.log("this.coms", this.coms);
       this.showViewForm = true;
     },
     onClose() {
@@ -625,6 +819,7 @@ export default {
         projects: e.projects,
       };
       _this.coms = JSON.parse(e.data);
+      console.log(JSON.parse(e.data));
       this.uptadeSearch();
     },
     onRemove(index) {
@@ -641,6 +836,9 @@ export default {
         this.comIndex = 0;
         this.AttributeIndex = 0;
       }
+      this.$nextTick(() => {
+        this.$forceUpdate();
+      });
     },
     //设置当前索引
     onSetActiveIndex(e) {
@@ -709,6 +907,34 @@ export default {
         });
       }
     },
+    /*更新  */
+    onUpload() {
+      let _this = this;
+      if (_this.coms.length <= 0) {
+        _this.$alert("增加组件");
+        return;
+      }
+      if (_this.docAttr.category_id == "" || _this.docAttr.category_id <= 0) {
+        _this.$alert("请选择分类");
+        return;
+      }
+      if (_this.docAttr.title == "") {
+        _this.$alert("请填写模版标题");
+        return;
+      }
+      _this.docAttr.links = JSON.stringify(_this.docAttr.linkProduct);
+      _this.docAttr.projects = JSON.stringify(_this.docAttr.linkProject);
+      _this.docAttr.data = JSON.stringify(_this.coms);
+      _this.docAttr.is_template = 1;
+      _this.docAttr.user_name = _this.$store.state.user.name;
+      _this.docAttr.user_id = _this.$store.state.user.id;
+      updateDocument(_this.docAttr).then((res) => {
+        if (res.status != 200) return; //更新文档
+        _this.docAttr.id = res.data;
+        _this.$alert("模版更新成功");
+        _this.searchArticle();
+      });
+    },
     /* 保存并更新模版 */
     onSaveUpload(e) {
       let _this = this;
@@ -731,21 +957,21 @@ export default {
       _this.docAttr.is_template = 1;
       _this.docAttr.user_name = _this.$store.state.user.name;
       _this.docAttr.user_id = _this.$store.state.user.id;
-      if (_this.docAttr.id > 0) {
+      /* if (_this.docAttr.id > 0) {
         updateDocument(_this.docAttr).then((res) => {
           if (res.status != 200) return; //更新文档
           _this.docAttr.id = res.data;
           _this.$alert("模版更新成功");
           _this.searchArticle();
         });
-      } else {
-        createDocument(_this.docAttr).then((res) => {
-          if (res.status != 200) return; //保存文档
-          _this.docAttr.id = res.data;
-          _this.$alert("模版保存成功");
-          _this.searchArticle();
-        });
-      }
+      } else { */
+      createDocument(_this.docAttr).then((res) => {
+        if (res.status != 200) return; //保存文档
+        _this.docAttr.id = res.data;
+        _this.$alert("模版保存成功");
+        _this.searchArticle();
+      });
+      /*   } */
     },
 
     //设置组件值
@@ -844,19 +1070,20 @@ export default {
         _this.$alert("请选择插入图层");
         return false;
       }
-      console.log(e);
+
       let com = _this.coms[_this.comIndex];
-      console.log("com:", com);
+      let uniqueId = "Directory" + (com.attrs.length + 1);
       let data = {
         type: "Directory",
-        id: "Directory" + (com.attrs.length + 1),
+        id: uniqueId,
         name: "目录信息",
-        intor: "目录信息",
-        content: "",
+        intro: "目录信息",
+        content: "目录信息",
       };
       com.attrs.push(data);
+      console.log(_this.coms);
       _this.insertCmd = {
-        content: "<div>{{" + data.id + "}}</div>",
+        content: "<div>{{" + uniqueId + "}}</div>",
       };
       // com.content+='{{'+data.id+'}}';
     },
@@ -1084,7 +1311,7 @@ export default {
       } else {
         //仅对图表中插入有效
         if (_this.comIndex >= 0) {
-          // _this.setTableData(data.id);
+          _this.setTableData(data.id);
         }
       }
     },

+ 155 - 62
src/views/login/index.vue

@@ -1,13 +1,18 @@
 <template>
   <div class="login-container">
-
     <div class="form-content">
-
       <div class="title-container">
-        <img src="../../assets/images/login-head.png" class="images">
+        <img src="../../assets/images/login-head.png" class="images" />
       </div>
-      <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form" autocomplete="on" label-position="left">
-
+      <el-form
+        v-if="loginOrRetrieve=='login'"
+        ref="loginForm"
+        :model="loginForm"
+        :rules="loginRules"
+        class="login-form"
+        autocomplete="on"
+        label-position="left"
+      >
         <el-form-item prop="username">
           <span class="svg-container">
             <svg-icon icon-class="user" />
@@ -23,7 +28,12 @@
           />
         </el-form-item>
 
-        <el-tooltip v-model="capsTooltip" content="Caps lock is On" placement="right" manual>
+        <el-tooltip
+          v-model="capsTooltip"
+          content="Caps lock is On"
+          placement="right"
+          manual
+        >
           <el-form-item prop="password">
             <span class="svg-container">
               <svg-icon icon-class="password" />
@@ -42,81 +52,159 @@
               @keyup.enter.native="handleLogin"
             />
             <span class="show-pwd" @click="showPwd">
-              <svg-icon :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'" />
+              <svg-icon
+                :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
+              />
             </span>
           </el-form-item>
         </el-tooltip>
 
-        <el-button :loading="loading" type="primary" style="width:100%;margin-bottom:30px;" @click="handleLogin">立即登录</el-button>
+        <el-button
+          :loading="loading"
+          type="primary"
+          style="width: 100%; margin-bottom: 30px"
+          @click="handleLogin"
+          >立即登录</el-button
+        >
         <div class="tips">
-          <div>找回密码</div>
+          <div @click="Retrieve" style="cursor: pointer">找回密码</div>
         </div>
       </el-form>
+      <div v-if="loginOrRetrieve=='retrieve'">
+        <el-form
+          ref="loginForm"
+          :model="loginForm"
+          :rules="loginRules"
+          class="login-form"
+          autocomplete="on"
+          label-position="left"
+        >
+          <el-form-item prop="username">
+            <span class="svg-container">
+              <svg-icon icon-class="user" />
+            </span>
+            <el-input
+              ref="username"
+              v-model="loginForm.username"
+              placeholder="登录用户名"
+              name="username"
+              type="text"
+              tabindex="1"
+              autocomplete="on"
+            />
+          </el-form-item>
 
-    </div>
+          <el-tooltip
+            v-model="capsTooltip"
+            content="Caps lock is On"
+            placement="right"
+            manual
+          >
+            <el-form-item prop="password">
+              <span class="svg-container">
+                <svg-icon icon-class="password" />
+              </span>
+              <el-input
+                :key="passwordType"
+                ref="password"
+                v-model="loginForm.password"
+                :type="passwordType"
+                placeholder="登录密码"
+                name="password"
+                tabindex="2"
+                autocomplete="on"
+                @keyup.native="checkCapslock"
+                @blur="capsTooltip = false"
+                @keyup.enter.native="handleLogin"
+              />
+              <span class="show-pwd" @click="showPwd">
+                <svg-icon
+                  :icon-class="passwordType === 'password' ? 'eye' : 'eye-open'"
+                />
+              </span>
+            </el-form-item>
+          </el-tooltip>
 
+          <el-button
+            :loading="loading"
+            type="primary"
+            style="width: 100%; margin-bottom: 30px"
+            @click="handleLogin"
+            >立即登录</el-button
+          >
+          <div class="tips">
+            <div @click="Retrieve" style="cursor: pointer">找回密码</div>
+          </div>
+        </el-form>
+      </div>
+    </div>
   </div>
 </template>
 
 <script>
-import { validUsername } from '@/utils/validate'
-import SocialSign from './components/SocialSignin'
+import { validUsername } from "@/utils/validate";
+import SocialSign from "./components/SocialSignin";
 
 export default {
-  name: 'Login',
+  name: "Login",
   components: { SocialSign },
   data() {
     const validateUsername = (rule, value, callback) => {
-      if(value.length<3){
-        callback(new Error('请填写正确的登录用户名'))
+      if (value.length < 3) {
+        callback(new Error("请填写正确的登录用户名"));
       } else {
-        callback()
+        callback();
       }
-    }
+    };
     const validatePassword = (rule, value, callback) => {
       if (value.length < 6) {
-        callback(new Error('请填写正确的密码,密码不得小于6位'))
+        callback(new Error("请填写正确的密码,密码不得小于6位"));
       } else {
-        callback()
+        callback();
       }
-    }
+    };
     return {
       loginForm: {
-        username: '',
-        password: ''
+        username: "",
+        password: "",
       },
       loginRules: {
-        username: [{ required: true, trigger: 'blur', validator: validateUsername }],
-        password: [{ required: true, trigger: 'blur', validator: validatePassword }]
+        username: [
+          { required: true, trigger: "blur", validator: validateUsername },
+        ],
+        password: [
+          { required: true, trigger: "blur", validator: validatePassword },
+        ],
       },
-      passwordType: 'password',
+      passwordType: "password",
       capsTooltip: false,
       loading: false,
       showDialog: false,
       redirect: undefined,
-      otherQuery: {}
-    }
+      otherQuery: {},
+      loginOrRetrieve:'login'
+    };
   },
   watch: {
     $route: {
-      handler: function(route) {
-        const query = route.query
+      handler: function (route) {
+        const query = route.query;
         if (query) {
-          this.redirect = query.redirect
-          this.otherQuery = this.getOtherQuery(query)
+          this.redirect = query.redirect;
+          this.otherQuery = this.getOtherQuery(query);
         }
       },
-      immediate: true
-    }
+      immediate: true,
+    },
   },
   created() {
     // window.addEventListener('storage', this.afterQRScan)
   },
   mounted() {
-    if (this.loginForm.username === '') {
-      this.$refs.username.focus()
-    } else if (this.loginForm.password === '') {
-      this.$refs.password.focus()
+    if (this.loginForm.username === "") {
+      this.$refs.username.focus();
+    } else if (this.loginForm.password === "") {
+      this.$refs.password.focus();
     }
   },
   destroyed() {
@@ -124,46 +212,49 @@ export default {
   },
   methods: {
     checkCapslock(e) {
-      const { key } = e
-      this.capsTooltip = key && key.length === 1 && (key >= 'A' && key <= 'Z')
+      const { key } = e;
+      this.capsTooltip = key && key.length === 1 && key >= "A" && key <= "Z";
     },
     showPwd() {
-      if (this.passwordType === 'password') {
-        this.passwordType = ''
+      if (this.passwordType === "password") {
+        this.passwordType = "";
       } else {
-        this.passwordType = 'password'
+        this.passwordType = "password";
       }
       this.$nextTick(() => {
-        this.$refs.password.focus()
-      })
+        this.$refs.password.focus();
+      });
     },
     handleLogin() {
-      this.$refs.loginForm.validate(valid => {
-
+      this.$refs.loginForm.validate((valid) => {
         if (valid) {
-          this.loading = true
-          this.$store.dispatch('user/login', this.loginForm)
+          this.loading = true;
+          this.$store
+            .dispatch("user/login", this.loginForm)
             .then(() => {
-              this.$router.push({ path: this.redirect || '/', query: this.otherQuery })
-              this.loading = false
+              this.$router.push({
+                path: this.redirect || "/",
+                query: this.otherQuery,
+              });
+              this.loading = false;
             })
             .catch(() => {
-              this.loading = false
-            })
+              this.loading = false;
+            });
         } else {
-          console.log('error submit!!')
-          return false
+          console.log("error submit!!");
+          return false;
         }
-      })
+      });
     },
     getOtherQuery(query) {
       return Object.keys(query).reduce((acc, cur) => {
-        if (cur !== 'redirect') {
-          acc[cur] = query[cur]
+        if (cur !== "redirect") {
+          acc[cur] = query[cur];
         }
-        return acc
-      }, {})
-    }
+        return acc;
+      }, {});
+    },
     // afterQRScan() {
     //   if (e.key === 'x-admin-oauth-code') {
     //     const code = getQueryObject(e.newValue)
@@ -182,8 +273,10 @@ export default {
     //     }
     //   }
     // }
-  }
-}
+    /* 找回密码 */
+    Retrieve() {},
+  },
+};
 </script>
 
 <style lang="scss">

+ 19 - 0
src/views/product/components/dataList.scss

@@ -53,3 +53,22 @@
   }
 
 }
+.el-table {
+  /* 适用于WebKit浏览器(Chrome、Safari等) */
+  &::-webkit-scrollbar {
+    height: 8px; /* 滚动条高度 */
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background-color: #efefef; /* 滚动条颜色 */
+    border-radius: 4px; /* 滚动条圆角 */
+  }
+
+  &::-webkit-scrollbar-track {
+    background-color: #fff; /* 滚动条轨道颜色 */
+  }
+
+  /* 适用于Firefox */
+  scrollbar-color: #efefef #fff; /* 滚动条颜色 轨道颜色 */
+  scrollbar-width: thin; /* 滚动条宽度 */
+}

Some files were not shown because too many files changed in this diff