瀏覽代碼

feat: print and perf style

xiaoxian521 3 年之前
父節點
當前提交
727c0fe3c0

+ 6 - 8
index.html

@@ -14,20 +14,16 @@
   <body>
     <div id="app">
       <style>
-        * {
-          margin: 0;
-          padding: 0;
-        }
-
         html,
-        body {
+        body,
+        #app {
           width: 100%;
           height: 100%;
           display: flex;
+          position: relative;
           justify-content: center;
           align-items: center;
           overflow: hidden;
-          font-family: "Reggae One", cursive;
         }
 
         .loader,
@@ -53,6 +49,8 @@
           transform: translateZ(0);
           -webkit-animation-delay: -0.16s;
           animation-delay: -0.16s;
+          top: 0;
+          transform: translate(-50%, 0);
         }
 
         .loader:before,
@@ -96,7 +94,7 @@
           }
         }
       </style>
-      <div class="loader">Loading...</div>
+      <div class="loader"></div>
     </div>
     <script type="module" src="/src/main.ts"></script>
   </body>

+ 1 - 1
mock/asyncRoutes.ts

@@ -76,7 +76,7 @@ const frameRouter = {
   },
   children: [
     {
-      path: "/frame/pure",
+      path: "/iframe/pure",
       name: "reFramePure",
       meta: {
         i18n: true,

+ 1 - 1
package.json

@@ -116,7 +116,7 @@
     "stylelint-order": "^5.0.0",
     "typescript": "^4.5.5",
     "unplugin-element-plus": "^0.2.0",
-    "vite": "^2.8.5",
+    "vite": "^2.8.6",
     "vite-plugin-live-reload": "^2.1.0",
     "vite-plugin-mock": "^2.9.6",
     "vite-plugin-remove-console": "^0.0.6",

File diff suppressed because it is too large
+ 454 - 287
pnpm-lock.yaml


+ 1 - 1
src/components/ReFlowChart/src/Control.vue

@@ -126,7 +126,7 @@ onMounted(() => {
 }
 
 .iconfont {
-  font-size: 25px;
+  font-size: 18px;
 }
 
 .control-container p {

+ 4 - 0
src/components/ReIcon/src/iconifyIconOffline.ts

@@ -24,6 +24,8 @@ import Location from "@iconify-icons/ep/location";
 import Tickets from "@iconify-icons/ep/tickets";
 import OfficeBuilding from "@iconify-icons/ep/office-building";
 import Notebook from "@iconify-icons/ep/notebook";
+import Rank from "@iconify-icons/ep/rank";
+import videoPlay from "@iconify-icons/ep/video-play";
 import Monitor from "@iconify-icons/ep/monitor";
 addIcon("check", Check);
 addIcon("menu", Menu);
@@ -47,6 +49,8 @@ addIcon("location", Location);
 addIcon("tickets", Tickets);
 addIcon("office-building", OfficeBuilding);
 addIcon("notebook", Notebook);
+addIcon("video-play", videoPlay);
+addIcon("rank", Rank);
 addIcon("monitor", Monitor);
 
 // remixicon

+ 4 - 0
src/layout/frameView.vue

@@ -55,4 +55,8 @@ onMounted(() => {
     box-sizing: border-box;
   }
 }
+
+.main-content {
+  margin: 0;
+}
 </style>

+ 0 - 1
src/layout/hooks/nav.ts

@@ -8,7 +8,6 @@ import { useAppStoreHook } from "/@/store/modules/app";
 import { remainingPaths } from "/@/router/modules/index";
 import { Title } from "../../../public/serverConfig.json";
 import { useEpThemeStoreHook } from "/@/store/modules/epTheme";
-import { remainingPaths } from "/@/router/modules/index";
 
 export function useNav() {
   const pureApp = useAppStoreHook();

+ 13 - 1
src/plugins/element-plus/index.ts

@@ -44,6 +44,12 @@ import {
   ElCollapse,
   ElCollapseItem,
   ElTreeV2,
+  ElTable,
+  ElTableColumn,
+  ElLink,
+  ElColorPicker,
+  ElSelect,
+  ElOption,
   // 指令
   ElLoading,
   ElInfiniteScroll
@@ -96,7 +102,13 @@ const components = [
   ElEmpty,
   ElCollapse,
   ElCollapseItem,
-  ElTreeV2
+  ElTreeV2,
+  ElTable,
+  ElTableColumn,
+  ElLink,
+  ElColorPicker,
+  ElSelect,
+  ElOption
 ];
 
 export function useElementPlus(app: App) {

+ 1 - 0
src/plugins/i18n/en/menus.ts

@@ -37,6 +37,7 @@ export default {
   hsAble: "Able",
   hsMenuTree: "Menu Tree",
   hsWatermark: "Water Mark",
+  hsPrint: "Print",
   hsExternalPage: "External Page",
   hsPureDocument: "Pure Document",
   hsEpDocument: "Element Plus Document"

+ 1 - 0
src/plugins/i18n/zh-CN/menus.ts

@@ -37,6 +37,7 @@ export default {
   hsAble: "功能",
   hsMenuTree: "菜单树结构",
   hsWatermark: "水印",
+  hsPrint: "打印",
   hsExternalPage: "外部页面",
   hsPureDocument: "平台文档",
   hsEpDocument: "Element Plus文档"

+ 9 - 0
src/router/modules/able.ts

@@ -30,6 +30,15 @@ const ableRouter = {
         title: $t("menus.hsWatermark"),
         i18n: true
       }
+    },
+    {
+      path: "/able/print",
+      name: "rePrint",
+      component: () => import("/@/views/able/print.vue"),
+      meta: {
+        title: $t("menus.hsPrint"),
+        i18n: true
+      }
     }
   ]
 };

+ 2 - 2
src/style/index.scss

@@ -12,8 +12,8 @@ body {
   -moz-osx-font-smoothing: grayscale;
   -webkit-font-smoothing: antialiased;
   text-rendering: optimizelegibility;
-  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
-    Microsoft YaHei, Arial, sans-serif;
+  font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB",
+    "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
 }
 
 html {

+ 226 - 0
src/utils/print.ts

@@ -0,0 +1,226 @@
+interface PrintFunction {
+  extendOptions: Function;
+  getStyle: Function;
+  setDomHeight: Function;
+  toPrint: Function;
+}
+
+const Print = function (dom, options?: object): PrintFunction {
+  options = options || {};
+  // @ts-expect-error
+  if (!(this instanceof Print)) return new Print(dom, options);
+  this.conf = {
+    styleStr: "",
+    // Elements that need to dynamically get and set the height
+    setDomHeightArr: [],
+    // Echart dom List
+    echartDomArr: [],
+    // Callback before printing
+    printBeforeFn: null,
+    // Callback after printing
+    printDoneCallBack: null
+  };
+  for (const key in this.conf) {
+    // eslint-disable-next-line no-prototype-builtins
+    if (key && options.hasOwnProperty(key)) {
+      this.conf[key] = options[key];
+    }
+  }
+  if (typeof dom === "string") {
+    this.dom = document.querySelector(dom);
+  } else {
+    this.dom = this.isDOM(dom) ? dom : dom.$el;
+  }
+  if (this.conf.setDomHeightArr && this.conf.setDomHeightArr.length) {
+    this.setDomHeight(this.conf.setDomHeightArr);
+  }
+  this.init();
+};
+
+Print.prototype = {
+  /**
+   * init
+   */
+  init: function (): void {
+    const content = this.getStyle() + this.getHtml();
+    this.writeIframe(content);
+  },
+  /**
+   * Configuration property extension
+   * @param {Object} obj
+   * @param {Object} obj2
+   */
+  extendOptions: function <T>(obj, obj2: T): T {
+    for (const k in obj2) {
+      obj[k] = obj2[k];
+    }
+    return obj;
+  },
+  /**
+    Copy all styles of the original page
+  */
+  getStyle: function (): string {
+    let str = "";
+    const styles: NodeListOf<Element> = document.querySelectorAll("style,link");
+    for (let i = 0; i < styles.length; i++) {
+      str += styles[i].outerHTML;
+    }
+    str += `<style>.no-print{display:none;}${this.conf.styleStr}</style>`;
+    return str;
+  },
+  // form assignment
+  getHtml: function (): Element {
+    const inputs = document.querySelectorAll("input");
+    const selects = document.querySelectorAll("select");
+    const textareas = document.querySelectorAll("textarea");
+    for (let k = 0; k < inputs.length; k++) {
+      if (inputs[k].type == "checkbox" || inputs[k].type == "radio") {
+        if (inputs[k].checked == true) {
+          inputs[k].setAttribute("checked", "checked");
+        } else {
+          inputs[k].removeAttribute("checked");
+        }
+      } else if (inputs[k].type == "text") {
+        inputs[k].setAttribute("value", inputs[k].value);
+      } else {
+        inputs[k].setAttribute("value", inputs[k].value);
+      }
+    }
+
+    for (let k2 = 0; k2 < textareas.length; k2++) {
+      if (textareas[k2].type == "textarea") {
+        textareas[k2].innerHTML = textareas[k2].value;
+      }
+    }
+
+    for (let k3 = 0; k3 < selects.length; k3++) {
+      if (selects[k3].type == "select-one") {
+        const child = selects[k3].children;
+        for (const i in child) {
+          if (child[i].tagName == "OPTION") {
+            // @ts-ignore
+            if (child[i].selected == true) {
+              child[i].setAttribute("selected", "selected");
+            } else {
+              child[i].removeAttribute("selected");
+            }
+          }
+        }
+      }
+    }
+
+    return this.dom.outerHTML;
+  },
+  /**
+    create iframe
+  */
+  writeIframe: function (content) {
+    let w: Document | Window;
+    let doc: Document;
+    const iframe: HTMLIFrameElement = document.createElement("iframe");
+    const f: HTMLIFrameElement = document.body.appendChild(iframe);
+    iframe.id = "myIframe";
+    iframe.setAttribute(
+      "style",
+      "position:absolute;width:0;height:0;top:-10px;left:-10px;"
+    );
+    // eslint-disable-next-line prefer-const
+    w = f.contentWindow || f.contentDocument;
+    // eslint-disable-next-line prefer-const
+    doc = f.contentDocument || f.contentWindow.document;
+    doc.open();
+    doc.write(content);
+    doc.close();
+    // eslint-disable-next-line @typescript-eslint/no-this-alias
+    const _this = this;
+    iframe.onload = function (): void {
+      // Before popping, callback
+      if (_this.conf.printBeforeFn) {
+        _this.conf.printBeforeFn({ doc });
+      }
+
+      _this.drawEchartImg(doc).then(() => {
+        _this.toPrint(w);
+        setTimeout(function () {
+          document.body.removeChild(iframe);
+          // After popup, callback
+          if (_this.conf.printDoneCallBack) {
+            _this.conf.printDoneCallBack();
+          }
+        }, 100);
+      });
+    };
+  },
+  /**
+   * echarts printing
+   * @param {Object} doc iframe window
+   */
+  drawEchartImg(doc): Promise<void> {
+    return new Promise<void>(resolve => {
+      if (this.conf.echartDomArr && this.conf.echartDomArr.length > 0) {
+        this.conf.echartDomArr.forEach(e => {
+          const dom = doc.querySelector("#" + e.$el.id);
+          const img = new Image();
+          const w = dom.offsetWidth + "px";
+          const H = dom.offsetHeight + "px";
+
+          img.style.width = w;
+          img.style.height = H;
+          img.src = e.imgSrc;
+          dom.innerHTML = "";
+          dom.appendChild(img);
+        });
+      }
+      resolve();
+    });
+  },
+  /**
+    Print
+  */
+  toPrint: function (frameWindow): void {
+    try {
+      setTimeout(function () {
+        frameWindow.focus();
+        try {
+          if (!frameWindow.document.execCommand("print", false, null)) {
+            frameWindow.print();
+          }
+        } catch (e) {
+          frameWindow.print();
+        }
+        frameWindow.close();
+      }, 10);
+    } catch (err) {
+      console.error(err);
+    }
+  },
+  isDOM:
+    typeof HTMLElement === "object"
+      ? function (obj) {
+          return obj instanceof HTMLElement;
+        }
+      : function (obj) {
+          return (
+            obj &&
+            typeof obj === "object" &&
+            obj.nodeType === 1 &&
+            typeof obj.nodeName === "string"
+          );
+        },
+  /**
+   * Set the height of the specified dom element by getting the existing height of the dom element and setting
+   * @param {Array} arr
+   */
+  setDomHeight(arr) {
+    if (arr && arr.length) {
+      arr.forEach(name => {
+        const domArr = document.querySelectorAll(name);
+        domArr.forEach(dom => {
+          dom.style.height = dom.offsetHeight + "px";
+        });
+      });
+    }
+  }
+};
+
+export default Print;

+ 57 - 10
src/views/able/menu-tree.vue

@@ -6,31 +6,78 @@ export default {
 
 <script setup lang="ts">
 import { ref, computed } from "vue";
+import type { ElTreeV2 } from "element-plus";
+import { transformI18n } from "/@/plugins/i18n";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
 import { extractPathList, deleteChildren } from "/@/utils/tree";
 import { usePermissionStoreHook } from "/@/store/modules/permission";
+import type { TreeNode } from "element-plus/es/components/tree-v2/src/types";
 
+interface treeNode extends TreeNode {
+  meta: {
+    title: string;
+    i18n: boolean;
+  };
+}
+
+const query = ref("");
 let dataProps = ref({
   value: "uniqueId",
   children: "children"
 });
+const treeRef = ref<InstanceType<typeof ElTreeV2>>();
 
 let menusData = computed(() => {
   return deleteChildren(usePermissionStoreHook().menusTree);
 });
 
 let expandedKeys = extractPathList(menusData.value);
+
+const onQueryChanged = (query: string) => {
+  // @ts-expect-error
+  treeRef.value!.filter(query);
+};
+
+const filterMethod = (query: string, node: treeNode) => {
+  return transformI18n(node.meta.title, node.meta.i18n)!.indexOf(query) !== -1;
+};
 </script>
 
 <template>
-  <el-tree-v2
-    :data="menusData"
-    :props="dataProps"
-    show-checkbox
-    :height="500"
-    :default-expanded-keys="expandedKeys"
-  >
-    <template #default="{ data }">
-      <span>{{ $t(data.meta.title) }}</span>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium"
+          >菜单树结构(采用element-plus的
+          <el-link
+            href="https://element-plus.gitee.io/zh-CN/component/tree-v2.html"
+            target="_blank"
+            :icon="useRenderIcon('node-tree')"
+            style="font-size: 16px; margin: 0 5px 4px 0"
+            >Tree V2</el-link
+          >组件并支持国际化)</span
+        >
+      </div>
     </template>
-  </el-tree-v2>
+    <el-input
+      class="mb-4"
+      v-model="query"
+      placeholder="请输入关键字查找"
+      clearable
+      @input="onQueryChanged"
+    ></el-input>
+    <el-tree-v2
+      ref="treeRef"
+      :data="menusData"
+      :props="dataProps"
+      show-checkbox
+      :height="500"
+      :filter-method="filterMethod"
+      :default-expanded-keys="expandedKeys"
+    >
+      <template #default="{ data }">
+        <span>{{ $t(data.meta.title) }}</span>
+      </template>
+    </el-tree-v2>
+  </el-card>
 </template>

+ 329 - 0
src/views/able/print.vue

@@ -0,0 +1,329 @@
+<script setup lang="ts">
+import Print from "/@/utils/print";
+import { reactive, ref } from "vue";
+import { VxeTablePropTypes } from "vxe-table";
+import { ReLine } from "/@/components/ReCharts/index";
+
+interface User {
+  date: string;
+  name: string;
+  address: string;
+}
+
+const demo1 = reactive({
+  tableData: [
+    {
+      id: 10001,
+      name: "Test1",
+      role: "Develop",
+      sex: "Man",
+      age: 28,
+      address: "test abc"
+    },
+    {
+      id: 10002,
+      name: "Test2",
+      role: "Test",
+      sex: "Women",
+      age: 22,
+      address: "Guangzhou"
+    },
+    {
+      id: 10003,
+      name: "Test3",
+      role: "PM",
+      sex: "Man",
+      age: 32,
+      address: "Shanghai"
+    },
+    {
+      id: 10004,
+      name: "Test4",
+      role: "Designer",
+      sex: "Women",
+      age: 24,
+      address: "Shanghai"
+    }
+  ]
+});
+
+const value = ref("1");
+
+const options = [
+  {
+    value: "1",
+    el: ".el-table",
+    label: "Element-Plus Table"
+  },
+  {
+    value: "2",
+    el: ".vxe-table",
+    label: "Vxe Table"
+  },
+  {
+    value: "3",
+    el: ".echart",
+    label: "Echart"
+  },
+  {
+    value: "4",
+    el: ".img",
+    label: "Image"
+  }
+];
+
+function onPrint() {
+  let el = options.filter(v => v.value === value.value)[0]?.el;
+  Print(el).toPrint;
+}
+
+const headerCellStyle: VxeTablePropTypes.HeaderCellStyle = ({ column }) => {
+  if (column.property === "name") {
+    return {
+      backgroundColor: "#f60",
+      color: "#ffffff"
+    };
+  }
+};
+
+const rowStyle: VxeTablePropTypes.RowStyle = ({ rowIndex }) => {
+  if ([2, 3, 5].includes(rowIndex)) {
+    return {
+      backgroundColor: "red",
+      color: "#ffffff"
+    };
+  }
+};
+
+const cellStyle: VxeTablePropTypes.CellStyle = ({ row, column }) => {
+  if (column.property === "sex") {
+    if (row.sex >= "1") {
+      return {
+        backgroundColor: "#187"
+      };
+    } else if (row.age === 26) {
+      return {
+        backgroundColor: "#2db7f5"
+      };
+    }
+  }
+};
+
+const tableRowClassName = ({ rowIndex }: { row: User; rowIndex: number }) => {
+  if (rowIndex === 1) {
+    return "warning-row";
+  } else if (rowIndex === 3) {
+    return "success-row";
+  }
+  return "";
+};
+
+const tableData: User[] = [
+  {
+    date: "2016-05-03",
+    name: "Tom",
+    address: "No. 189, Grove St, Los Angeles"
+  },
+  {
+    date: "2016-05-02",
+    name: "Tom",
+    address: "No. 189, Grove St, Los Angeles"
+  },
+  {
+    date: "2016-05-04",
+    name: "Tom",
+    address: "No. 189, Grove St, Los Angeles"
+  },
+  {
+    date: "2016-05-01",
+    name: "Tom",
+    address: "No. 189, Grove St, Los Angeles"
+  }
+];
+</script>
+
+<template>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium">打印功能(报表、图表、图片)</span>
+        <div>
+          <el-select
+            v-model="value"
+            class="m-2"
+            placeholder="Select"
+            size="small"
+          >
+            <el-option
+              v-for="item in options"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            >
+            </el-option>
+          </el-select>
+          <el-button size="small" type="primary" @click="onPrint"
+            >打印</el-button
+          >
+        </div>
+      </div>
+    </template>
+    <el-row :gutter="24">
+      <el-col
+        :xs="22"
+        :sm="22"
+        :md="11"
+        :lg="11"
+        :xl="11"
+        style="margin: 10px; border: 0.01rem solid var(--el-color-primary)"
+        v-motion
+        :initial="{
+          opacity: 0,
+          y: 100
+        }"
+        :enter="{
+          opacity: 1,
+          y: 0,
+          transition: {
+            delay: 200
+          }
+        }"
+      >
+        <p class="font-medium pt-1">Element-Plus Table</p>
+        <el-table
+          class="el-table"
+          :data="tableData"
+          border
+          style="margin: 40px auto; width: 100%"
+          :row-class-name="tableRowClassName"
+        >
+          <el-table-column prop="date" label="Date" width="180" />
+          <el-table-column prop="name" label="Name" width="180" />
+          <el-table-column prop="address" label="Address" />
+        </el-table>
+      </el-col>
+
+      <el-col
+        :xs="22"
+        :sm="22"
+        :md="11"
+        :lg="11"
+        :xl="11"
+        style="margin: 10px; border: 0.01rem solid var(--el-color-primary)"
+        v-motion
+        :initial="{
+          opacity: 0,
+          y: 100
+        }"
+        :enter="{
+          opacity: 1,
+          y: 0,
+          transition: {
+            delay: 200
+          }
+        }"
+      >
+        <p class="font-medium pt-1">Vxe Table</p>
+        <vxe-table
+          class="vxe-table"
+          border
+          style="margin: 40px auto"
+          :header-cell-style="headerCellStyle"
+          :row-style="rowStyle"
+          :cell-style="cellStyle"
+          :data="demo1.tableData"
+        >
+          <vxe-column type="seq" width="60"></vxe-column>
+          <vxe-column field="name" title="Name"></vxe-column>
+          <vxe-column field="sex" title="Sex"></vxe-column>
+          <vxe-column field="age" title="Age"></vxe-column>
+          <vxe-column field="attr1" title="Attr1"></vxe-column>
+          <vxe-column
+            field="address"
+            title="Address"
+            show-overflow
+          ></vxe-column>
+        </vxe-table>
+      </el-col>
+
+      <el-col
+        :xs="22"
+        :sm="22"
+        :md="11"
+        :lg="11"
+        :xl="11"
+        style="
+          width: 200px;
+          height: 300px;
+          margin: 10px;
+          border: 0.01rem solid var(--el-color-primary);
+        "
+        v-motion
+        :initial="{
+          opacity: 0,
+          y: 100
+        }"
+        :enter="{
+          opacity: 1,
+          y: 0,
+          transition: {
+            delay: 200
+          }
+        }"
+      >
+        <p class="font-medium pt-1">Echart</p>
+        <ReLine class="echart" style="margin: 0 auto" />
+      </el-col>
+
+      <el-col
+        :xs="22"
+        :sm="22"
+        :md="11"
+        :lg="11"
+        :xl="11"
+        style="
+          width: 200px;
+          height: 300px;
+          margin: 10px;
+          border: 0.01rem solid var(--el-color-primary);
+        "
+        v-motion
+        :initial="{
+          opacity: 0,
+          y: 100
+        }"
+        :enter="{
+          opacity: 1,
+          y: 0,
+          transition: {
+            delay: 200
+          }
+        }"
+      >
+        <p class="font-medium pt-1">Image</p>
+        <img
+          src="../../assets/avatars.jpg"
+          alt="avatars"
+          class="img"
+          style="width: 200px; height: 200px; margin: 50px auto"
+        />
+      </el-col>
+    </el-row>
+  </el-card>
+</template>
+
+<style lang="scss" scoped>
+:deep(.el-table__row.warning-row) {
+  --el-table-tr-bg-color: var(--el-color-warning-light-9);
+}
+
+:deep(.el-table__row.success-row) {
+  --el-table-tr-bg-color: var(--el-color-success-light-9);
+}
+
+.card-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+</style>

+ 24 - 3
src/views/able/watermark.vue

@@ -1,13 +1,34 @@
 <script setup lang="ts">
+import { ref } from "vue";
 import { useWatermark } from "/@/utils/watermark";
+
+let color = ref("#409EFF");
+let value = ref("vue-pure-admin");
 const { setWatermark, clear } = useWatermark();
 </script>
 
 <template>
-  <div>
-    <el-button @click="setWatermark('vue-pure-admin')">创建</el-button>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium">页面水印功能</span>
+      </div>
+    </template>
+    <span>请输入要创建水印的值:</span
+    ><el-input
+      class="mb-4 mr-4"
+      style="width: 200px"
+      v-model="value"
+      clearable
+    ></el-input>
+    <span>请选择要创建水印的颜色:</span
+    ><el-color-picker v-model="color" show-alpha />
+    <br />
+    <el-button @click="setWatermark(value, { fillStyle: color })"
+      >创建</el-button
+    >
     <el-button @click="clear">清除</el-button>
-  </div>
+  </el-card>
 </template>
 
 <style scoped></style>

+ 10 - 4
src/views/components/button/index.vue

@@ -7,13 +7,19 @@ const url = ref(`${VITE_PUBLIC_PATH}html/button.html`);
 </script>
 
 <template>
-  <iframe :src="url" frameborder="0" class="iframe"></iframe>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium">通过iframe引入按钮页面</span>
+      </div>
+    </template>
+    <iframe :src="url" frameborder="0" class="iframe"></iframe>
+  </el-card>
 </template>
 
 <style scoped>
 .iframe {
-  width: 98%;
-  height: 90vh;
-  border-radius: 6px;
+  width: 100%;
+  height: 60vh;
 }
 </style>

+ 7 - 2
src/views/components/contextmenu/index.vue

@@ -5,7 +5,12 @@ import menuDynamic from "./menuDynamic.vue";
 </script>
 
 <template>
-  <div>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium">右键菜单组件</span>
+      </div>
+    </template>
     <el-row :gutter="24">
       <el-col :xs="24" :sm="10" :md="10" :lg="8" :xl="10">
         <!-- 基本使用 -->
@@ -20,5 +25,5 @@ import menuDynamic from "./menuDynamic.vue";
         <menuDynamic />
       </el-col>
     </el-row>
-  </div>
+  </el-card>
 </template>

+ 26 - 29
src/views/components/count-to/index.vue

@@ -3,35 +3,32 @@ import { ReNormalCountTo, ReboundCountTo } from "/@/components/ReCountTo";
 </script>
 
 <template>
-  <div>
-    <el-row :gutter="24">
-      <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-        <el-card shadow="always">
-          <ReNormalCountTo
-            prefix="$"
-            :duration="1000"
-            :color="'#409EFF'"
-            :fontSize="'2.3em'"
-            :startVal="1"
-            :endVal="1000"
-          />
-        </el-card>
-      </el-col>
-      <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12">
-        <el-card shadow="always">
-          <ul class="flex">
-            <ReboundCountTo
-              v-for="(num, inx) of [1, 6, 6, 6]"
-              :key="inx"
-              :i="num"
-              :blur="inx"
-              :delay="inx + 1"
-            />
-          </ul>
-        </el-card>
-      </el-col>
-    </el-row>
-  </div>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium">数字动画组件</span>
+      </div>
+    </template>
+    <div class="flex items-center">
+      <ReNormalCountTo
+        prefix="$"
+        :duration="1000"
+        :color="'#409EFF'"
+        :fontSize="'2em'"
+        :startVal="1"
+        :endVal="1000"
+      />
+      <ul class="flex ml-8">
+        <ReboundCountTo
+          v-for="(num, inx) of [1, 6, 6, 6]"
+          :key="inx"
+          :i="num"
+          :blur="inx"
+          :delay="inx + 1"
+        />
+      </ul>
+    </div>
+  </el-card>
 </template>
 
 <style lang="scss" scoped>

+ 8 - 3
src/views/components/cropping/index.vue

@@ -3,9 +3,9 @@ import { ref, nextTick, getCurrentInstance } from "vue";
 import Cropper from "/@/components/ReCropper";
 import img from "./picture.jpeg";
 
-const instance = getCurrentInstance();
 let info = ref<object>(null);
 let cropperImg = ref<string>("");
+const instance = getCurrentInstance();
 
 const onCropper = (): void => {
   nextTick(() => {
@@ -25,14 +25,19 @@ const onCropper = (): void => {
 </script>
 
 <template>
-  <div>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium">图片裁剪组件</span>
+      </div>
+    </template>
     <div class="cropper-container">
       <Cropper ref="refCropper" :width="'40vw'" :src="img" />
       <img :src="cropperImg" class="croppered" v-if="cropperImg" />
     </div>
     <el-button type="primary" @click="onCropper">裁剪</el-button>
     <p v-if="cropperImg">裁剪后图片信息:{{ info }}</p>
-  </div>
+  </el-card>
 </template>
 
 <style scoped>

+ 82 - 66
src/views/components/draggable/index.vue

@@ -1,6 +1,7 @@
 <script setup lang="ts">
 import { ref, onMounted } from "vue";
 import draggable from "vuedraggable/src/vuedraggable";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
 
 let gridLists = ref<Array<Object>>([
   { grid: "cn", num: 1 },
@@ -47,77 +48,92 @@ onMounted(() => {
 </script>
 
 <template>
-  <div class="drag-container">
-    <!-- grid列表拖拽 -->
-    <el-row :gutter="25">
-      <el-col :xs="25" :sm="8" :md="8" :lg="8">
-        <el-card>
-          <template #header>
-            <div class="card-header">
-              <span>grid列表拖拽</span>
-            </div>
-          </template>
-          <draggable
-            v-model="gridLists"
-            class="grid-container"
-            item-key="grid"
-            animation="300"
-            chosenClass="chosen"
-            forceFallback="true"
-          >
-            <template #item="{ element }">
-              <div :class="'item' + ' ' + 'item-' + element.num">
-                {{ element.num }}
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span
+          >拖拽组件,采用开源的<el-link
+            href="https://sortablejs.github.io/vue.draggable.next/#/simple"
+            target="_blank"
+            :icon="useRenderIcon('rank')"
+            style="font-size: 16px; margin: 0 4px 5px"
+            >vuedraggable</el-link
+          ></span
+        >
+      </div>
+    </template>
+    <div class="drag-container">
+      <!-- grid列表拖拽 -->
+      <el-row :gutter="25">
+        <el-col :xs="25" :sm="8" :md="8" :lg="8">
+          <el-card>
+            <template #header>
+              <div class="card-header">
+                <span>grid列表拖拽</span>
               </div>
             </template>
-          </draggable>
-        </el-card>
-      </el-col>
-
-      <el-col :xs="25" :sm="8" :md="8" :lg="8">
-        <el-card>
-          <template #header>
-            <div class="card-header">
-              <span>单列拖拽</span>
-            </div>
-          </template>
-          <!-- 单列拖拽 -->
-          <draggable
-            v-model="lists"
-            item-key="name"
-            @change="change"
-            chosen-class="chosen"
-            force-fallback="true"
-            animation="300"
-          >
-            <template #item="{ element, index }">
-              <div class="item-single">{{ element.name }} {{ index }}</div>
+            <draggable
+              v-model="gridLists"
+              class="grid-container"
+              item-key="grid"
+              animation="300"
+              chosenClass="chosen"
+              forceFallback="true"
+            >
+              <template #item="{ element }">
+                <div :class="'item' + ' ' + 'item-' + element.num">
+                  {{ element.num }}
+                </div>
+              </template>
+            </draggable>
+          </el-card>
+        </el-col>
+
+        <el-col :xs="25" :sm="8" :md="8" :lg="8">
+          <el-card>
+            <template #header>
+              <div class="card-header">
+                <span>单列拖拽</span>
+              </div>
             </template>
-          </draggable>
-        </el-card>
-      </el-col>
-
-      <el-col :xs="25" :sm="8" :md="8" :lg="8">
-        <el-card>
-          <template #header>
-            <div class="card-header">
-              <span>拖拽实现元素位置切换</span>
-            </div>
-          </template>
-          <!-- 拖拽实现元素位置切换 -->
-          <div class="cut-container">
-            <div
-              class="item-cut"
-              v-for="(item, index) in cutLists"
-              :key="index"
+            <!-- 单列拖拽 -->
+            <draggable
+              v-model="lists"
+              item-key="name"
+              @change="change"
+              chosen-class="chosen"
+              force-fallback="true"
+              animation="300"
             >
-              <p>{{ item.name }}</p>
+              <template #item="{ element, index }">
+                <div class="item-single">{{ element.name }} {{ index }}</div>
+              </template>
+            </draggable>
+          </el-card>
+        </el-col>
+
+        <el-col :xs="25" :sm="8" :md="8" :lg="8">
+          <el-card>
+            <template #header>
+              <div class="card-header">
+                <span>拖拽实现元素位置切换</span>
+              </div>
+            </template>
+            <!-- 拖拽实现元素位置切换 -->
+            <div class="cut-container">
+              <div
+                class="item-cut"
+                v-for="(item, index) in cutLists"
+                :key="index"
+              >
+                <p>{{ item.name }}</p>
+              </div>
             </div>
-          </div>
-        </el-card>
-      </el-col>
-    </el-row>
-  </div>
+          </el-card>
+        </el-col>
+      </el-row>
+    </div>
+  </el-card>
 </template>
 
 <style lang="scss" scoped>

+ 28 - 21
src/views/components/split-pane/index.vue

@@ -16,27 +16,34 @@ const settingTB: ContextProps = reactive({
 </script>
 
 <template>
-  <div class="split-pane">
-    <splitpane :splitSet="settingLR">
-      <!-- #paneL 表示指定该组件为左侧面板 -->
-      <template #paneL>
-        <!-- 自定义左侧面板的内容 -->
-        <div class="dv-a">A</div>
-      </template>
-      <!-- #paneR 表示指定该组件为右侧面板 -->
-      <template #paneR>
-        <!-- 再次将右侧面板进行拆分 -->
-        <splitpane :splitSet="settingTB">
-          <template #paneL>
-            <div class="dv-b">B</div>
-          </template>
-          <template #paneR>
-            <div class="dv-c">C</div>
-          </template>
-        </splitpane>
-      </template>
-    </splitpane>
-  </div>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium">切割面板组件</span>
+      </div>
+    </template>
+    <div class="split-pane">
+      <splitpane :splitSet="settingLR">
+        <!-- #paneL 表示指定该组件为左侧面板 -->
+        <template #paneL>
+          <!-- 自定义左侧面板的内容 -->
+          <div class="dv-a">A</div>
+        </template>
+        <!-- #paneR 表示指定该组件为右侧面板 -->
+        <template #paneR>
+          <!-- 再次将右侧面板进行拆分 -->
+          <splitpane :splitSet="settingTB">
+            <template #paneL>
+              <div class="dv-b">B</div>
+            </template>
+            <template #paneR>
+              <div class="dv-c">C</div>
+            </template>
+          </splitpane>
+        </template>
+      </splitpane>
+    </div>
+  </el-card>
 </template>
 
 <style lang="scss" scoped>

+ 20 - 2
src/views/components/video/index.vue

@@ -2,13 +2,16 @@
 import { onMounted } from "vue";
 import Player from "xgplayer/dist/simple_player";
 import volume from "xgplayer/es/controls/volume";
-import playbackRate from "xgplayer/es/controls/playbackRate";
 import screenShot from "xgplayer/es/controls/screenShot";
 import { deviceDetection } from "/@/utils/deviceDetection";
+import playbackRate from "xgplayer/es/controls/playbackRate";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
 
 onMounted(() => {
   new Player({
     id: "mse",
+    // 默认静音
+    volume: 0,
     autoplay: false,
     screenShot: true,
     url: "https://sf1-hscdn-tos.pstatp.com/obj/media-fe/xgplayer_doc_video/mp4/xgplayer-demo-720p.mp4",
@@ -23,7 +26,22 @@ onMounted(() => {
 </script>
 
 <template>
-  <div id="mse"></div>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium"
+          >视频组件,采用开源的<el-link
+            href="https://v2.h5player.bytedance.com"
+            target="_blank"
+            :icon="useRenderIcon('video-play')"
+            style="font-size: 16px; margin: 0 4px 5px"
+            >西瓜播放器</el-link
+          ></span
+        >
+      </div>
+    </template>
+    <div id="mse"></div>
+  </el-card>
 </template>
 
 <style scoped>

+ 18 - 9
src/views/editor/index.vue

@@ -5,12 +5,12 @@ export default {
 </script>
 
 <script setup lang="ts">
-import { onMounted, onBeforeUnmount, ref, unref } from "vue";
 import WangEditor from "wangeditor";
+import { onMounted, onBeforeUnmount, ref, unref } from "vue";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
 
-// eslint-disable-next-line no-undef
-const editor = ref(null);
 const html = ref(null);
+const editor = ref(null);
 let instance: WangEditor;
 
 onMounted(() => {
@@ -29,17 +29,26 @@ onBeforeUnmount(() => {
 </script>
 
 <template>
-  <div>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium"
+          >编辑器组件,采用开源的<el-link
+            href="https://www.wangeditor.com"
+            target="_blank"
+            :icon="useRenderIcon('edit')"
+            style="font-size: 16px; margin: 0 4px 5px"
+            >wangeditor</el-link
+          ></span
+        >
+      </div>
+    </template>
     <div ref="editor"></div>
     <div :innerHTML="html"></div>
-  </div>
+  </el-card>
 </template>
 
 <style lang="scss" scoped>
-.main-content {
-  margin: 40px;
-}
-
 :deep(.w-e-text-container) {
   z-index: 99 !important;
 }

+ 48 - 35
src/views/flow-chart/index.vue

@@ -1,13 +1,15 @@
 <script setup lang="ts">
-import { ref, unref, onMounted } from "vue";
-import LogicFlow from "@logicflow/core";
-import { Snapshot, BpmnElement, Menu } from "@logicflow/extension";
+import demoData from "./dataTurbo.json";
 import "@logicflow/core/dist/style/index.css";
 import "@logicflow/extension/lib/style/index.css";
+
+import LogicFlow from "@logicflow/core";
+import { ref, unref, onMounted } from "vue";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
+import { BpmnNode } from "/@/components/ReFlowChart/src/config";
+import { Snapshot, BpmnElement, Menu } from "@logicflow/extension";
 import { Control, NodePanel, DataDialog } from "/@/components/ReFlowChart";
 import { toLogicflowData } from "/@/components/ReFlowChart/src/adpterForTurbo";
-import { BpmnNode } from "/@/components/ReFlowChart/src/config";
-import demoData from "./dataTurbo.json";
 
 let lf = ref(null);
 let graphData = ref(null);
@@ -57,37 +59,52 @@ onMounted(() => {
 </script>
 
 <template>
-  <div class="logic-flow-view">
-    <!-- 辅助工具栏 -->
-    <Control
-      class="demo-control"
-      v-if="lf"
-      :lf="lf"
-      :catTurboData="false"
-      @catData="catData"
-    ></Control>
-    <!-- 节点面板 -->
-    <NodePanel :lf="lf" :nodeList="nodeList"></NodePanel>
-    <!-- 画布 -->
-    <div id="LF-Turbo"></div>
-    <!-- 数据查看面板 -->
-    <el-dialog
-      customClass="flow-dialog"
-      title="数据"
-      v-model="dataVisible"
-      width="50%"
-    >
-      <el-scrollbar>
-        <DataDialog :graphData="graphData"></DataDialog>
-      </el-scrollbar>
-    </el-dialog>
-  </div>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium"
+          >流程图组件,采用开源的<el-link
+            href="http://logic-flow.org/"
+            target="_blank"
+            :icon="useRenderIcon('set-up')"
+            style="font-size: 16px; margin: 0 4px 5px"
+            >LogicFlow</el-link
+          ></span
+        >
+      </div>
+    </template>
+    <div class="logic-flow-view">
+      <!-- 辅助工具栏 -->
+      <Control
+        class="demo-control"
+        v-if="lf"
+        :lf="lf"
+        :catTurboData="false"
+        @catData="catData"
+      ></Control>
+      <!-- 节点面板 -->
+      <NodePanel :lf="lf" :nodeList="nodeList"></NodePanel>
+      <!-- 画布 -->
+      <div id="LF-Turbo"></div>
+      <!-- 数据查看面板 -->
+      <el-dialog
+        customClass="flow-dialog"
+        title="数据"
+        v-model="dataVisible"
+        width="50%"
+      >
+        <el-scrollbar>
+          <DataDialog :graphData="graphData"></DataDialog>
+        </el-scrollbar>
+      </el-dialog>
+    </div>
+  </el-card>
 </template>
 
 <style scoped>
 #LF-Turbo {
   width: 100%;
-  height: calc(100vh - 90px);
+  height: 70vh;
 }
 
 .logic-flow-view {
@@ -137,8 +154,4 @@ onMounted(() => {
   height: 85vh;
   overflow: auto;
 }
-
-.main-content {
-  margin: 0;
-}
 </style>

+ 9 - 10
src/views/guide/index.vue

@@ -1,14 +1,7 @@
-<script lang="ts">
-export default {
-  name: "reGuide"
-};
-</script>
-
 <script setup lang="ts">
 import Driver from "driver.js";
 import "driver.js/dist/driver.min.css";
 
-// 步骤
 const steps = [
   {
     element: "#header-notice",
@@ -72,8 +65,14 @@ const guide = () => {
 </script>
 
 <template>
-  <div>
-    <p>引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能</p>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium"
+          >引导页对于一些第一次进入项目的人很有用,你可以简单介绍下项目的功能</span
+        >
+      </div>
+    </template>
     <el-button
       type="primary"
       style="margin-top: 10px"
@@ -81,7 +80,7 @@ const guide = () => {
     >
       打开引导页
     </el-button>
-  </div>
+  </el-card>
 </template>
 
 <style>

+ 10 - 6
src/views/permission/button/index.vue

@@ -20,12 +20,16 @@ function changRole(value) {
 </script>
 
 <template>
-  <div>
-    <el-radio-group v-model="auth" @change="changRole">
-      <el-radio-button label="admin"></el-radio-button>
-      <el-radio-button label="test"></el-radio-button>
-    </el-radio-group>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <el-radio-group v-model="auth" @change="changRole">
+          <el-radio-button label="admin"></el-radio-button>
+          <el-radio-button label="test"></el-radio-button>
+        </el-radio-group>
+      </div>
+    </template>
     <p v-auth="'v-admin'">只有admin可看</p>
     <p v-auth="'v-test'">只有test可看</p>
-  </div>
+  </el-card>
 </template>

+ 13 - 9
src/views/permission/page/index.vue

@@ -29,19 +29,23 @@ function changRole() {
 </script>
 
 <template>
-  <div>
-    <h4>
-      当前角色:
-      <span style="font-size: 26px">{{ purview }}</span>
-      <p style="color: #ffa500">
-        查看左侧菜单变化(系统管理),模拟后台根据不同角色返回对应路由
-      </p>
-    </h4>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span>
+          当前角色:
+          <span style="font-size: 26px">{{ purview }}</span>
+          <p style="color: #ffa500">
+            查看左侧菜单变化(系统管理),模拟后台根据不同角色返回对应路由
+          </p></span
+        >
+      </div>
+    </template>
     <el-button
       type="primary"
       @click="changRole"
       :icon="useRenderIcon('user', { color: '#fff' })"
       >切换角色</el-button
     >
-  </div>
+  </el-card>
 </template>

+ 12 - 31
src/views/tabs/index.vue

@@ -1,11 +1,9 @@
 <script setup lang="ts">
-import { ref } from "vue";
 import { useRouter, useRoute } from "vue-router";
 import { useMultiTagsStoreHook } from "/@/store/modules/multiTags";
 
 const router = useRouter();
 const route = useRoute();
-const activeName = ref("tag");
 
 function toDetail(index: number) {
   useMultiTagsStoreHook().handleTags("push", {
@@ -25,33 +23,16 @@ function toDetail(index: number) {
 </script>
 
 <template>
-  <el-collapse v-model="activeName" class="tabs-container">
-    <el-collapse-item
-      title="标签页复用超出限制自动关闭(使用场景: 动态路由)"
-      name="tag"
-    >
-      <el-button v-for="index in 6" :key="index" @click="toDetail(index)">
-        打开{{ index }}详情页
-      </el-button>
-    </el-collapse-item>
-  </el-collapse>
+  <el-card>
+    <template #header>
+      <div class="card-header">
+        <span class="font-medium"
+          >标签页复用,超出限制自动关闭(使用场景: 动态路由)</span
+        >
+      </div>
+    </template>
+    <el-button v-for="index in 6" :key="index" @click="toDetail(index)">
+      打开{{ index }}详情页
+    </el-button>
+  </el-card>
 </template>
-
-<style lang="scss" scoped>
-.tabs-container {
-  padding: 10px;
-  background: #fff;
-
-  ::v-deep(.el-collapse-item__header) {
-    line-height: 20px;
-  }
-
-  ::v-deep(.el-collapse-item__wrap) {
-    border-bottom: none;
-  }
-
-  button {
-    margin: 10px;
-  }
-}
-</style>

+ 2 - 2
src/views/welcome.vue

@@ -61,7 +61,7 @@ const openDepot = (): void => {
           }
         }"
       >
-        <el-card>
+        <el-card style="height: 360px">
           <template #header>
             <span style="font-size: 16px; font-weight: 500">GitHub信息</span>
           </template>
@@ -93,7 +93,7 @@ const openDepot = (): void => {
           }
         }"
       >
-        <el-card>
+        <el-card style="height: 360px">
           <template #header>
             <span style="font-size: 16px; font-weight: 500"
               >GitHub滚动信息</span

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