Kaynağa Gözat

fix: some small chang

xiaoxian521 3 yıl önce
ebeveyn
işleme
074213c656

+ 18 - 13
package-lock.json

@@ -33,7 +33,7 @@
         "vue-types": "^3.0.2",
         "vuedraggable": "^4.0.1",
         "vuex": "^4.0.0",
-        "vxe-table": "^4.0.14",
+        "vxe-table": "^4.0.15-beta.2",
         "wangeditor": "^4.0.3",
         "xe-ajax": "^4.0.5",
         "xe-utils": "^3.1.12",
@@ -2710,9 +2710,13 @@
       "integrity": "sha1-rId6p2qcRTaMl5Rx5GG1INOObPU="
     },
     "node_modules/vxe-table": {
-      "version": "4.0.14",
-      "resolved": "https://registry.npmjs.org/vxe-table/-/vxe-table-4.0.14.tgz",
-      "integrity": "sha512-0fwddIk7X+NPneZuucvy6BbTmZ9oRfTxP02ZfWOu5c4KegVSFTIxMWlGkDOhtwf67HcA6gh9UwWkyoPiKhvvCQ=="
+      "version": "4.0.15-beta.2",
+      "resolved": "https://registry.npmjs.org/vxe-table/-/vxe-table-4.0.15-beta.2.tgz",
+      "integrity": "sha512-XbyoVFAbvwnOzCcvNiGpe8vHBCUTwQzv2GBv5HjlzGKEy+e99eEAeIcEzYfXvu4ttIva+5u+at9svwRNKT8EBA==",
+      "peerDependencies": {
+        "vue": "^3.0.0",
+        "xe-utils": "^3.2.0"
+      }
     },
     "node_modules/wangeditor": {
       "version": "4.6.14",
@@ -2750,9 +2754,9 @@
       "integrity": "sha1-N2kPiaN9m19U7yrk79PpJXDzLfM="
     },
     "node_modules/xe-utils": {
-      "version": "3.1.13",
-      "resolved": "https://registry.npm.taobao.org/xe-utils/download/xe-utils-3.1.13.tgz",
-      "integrity": "sha1-6YPu28XoJNEnbOfvB3wFbfsdakk="
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/xe-utils/-/xe-utils-3.2.1.tgz",
+      "integrity": "sha512-NiupDI5mIziz4i152UCk78c/qxYH/TDexGylLj81kxPbrePEg43LQ8hITCbsqpJDTcu9dmXESUtZyQDD1oB0hw=="
     },
     "node_modules/xgplayer": {
       "version": "2.19.1",
@@ -5050,9 +5054,10 @@
       "integrity": "sha1-rId6p2qcRTaMl5Rx5GG1INOObPU="
     },
     "vxe-table": {
-      "version": "4.0.14",
-      "resolved": "https://registry.npmjs.org/vxe-table/-/vxe-table-4.0.14.tgz",
-      "integrity": "sha512-0fwddIk7X+NPneZuucvy6BbTmZ9oRfTxP02ZfWOu5c4KegVSFTIxMWlGkDOhtwf67HcA6gh9UwWkyoPiKhvvCQ=="
+      "version": "4.0.15-beta.2",
+      "resolved": "https://registry.npmjs.org/vxe-table/-/vxe-table-4.0.15-beta.2.tgz",
+      "integrity": "sha512-XbyoVFAbvwnOzCcvNiGpe8vHBCUTwQzv2GBv5HjlzGKEy+e99eEAeIcEzYfXvu4ttIva+5u+at9svwRNKT8EBA==",
+      "requires": {}
     },
     "wangeditor": {
       "version": "4.6.14",
@@ -5086,9 +5091,9 @@
       "integrity": "sha1-N2kPiaN9m19U7yrk79PpJXDzLfM="
     },
     "xe-utils": {
-      "version": "3.1.13",
-      "resolved": "https://registry.npm.taobao.org/xe-utils/download/xe-utils-3.1.13.tgz",
-      "integrity": "sha1-6YPu28XoJNEnbOfvB3wFbfsdakk="
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/xe-utils/-/xe-utils-3.2.1.tgz",
+      "integrity": "sha512-NiupDI5mIziz4i152UCk78c/qxYH/TDexGylLj81kxPbrePEg43LQ8hITCbsqpJDTcu9dmXESUtZyQDD1oB0hw=="
     },
     "xgplayer": {
       "version": "2.19.1",

+ 1 - 1
package.json

@@ -36,7 +36,7 @@
     "vue-types": "^3.0.2",
     "vuedraggable": "^4.0.1",
     "vuex": "^4.0.0",
-    "vxe-table": "^4.0.14",
+    "vxe-table": "^4.0.15-beta.2",
     "wangeditor": "^4.0.3",
     "xe-ajax": "^4.0.5",
     "xe-utils": "^3.1.12",

+ 4 - 1
src/plugins/vxe-table/index.ts

@@ -53,13 +53,16 @@ VXETable.setup({
   version: 0,
   zIndex: 100,
   table: {
+    // 自动监听父元素的变化去重新计算表格
     autoResize: true,
+    // 鼠标移到行是否要高亮显示
+    highlightHoverRow: true,
   },
   // 对组件内置的提示语进行国际化翻译
   i18n: (key, args) => i18n.global.t(key, args),
   // 可选,对参数中的列头、校验提示..等进行自动翻译(只对支持国际化的有效)
   translate(key, args) {
-    // 例如,只翻译 "app." 开头的键值
+    // 例如,只翻译 "message." 开头的键值
     if (key && key.indexOf("message.") > -1) {
       return i18n.global.t(key, args);
     }

+ 72 - 0
src/utils/useCopyToClipboard.ts

@@ -0,0 +1,72 @@
+import { ref, watch } from "vue";
+
+import { isDef } from "/@/utils/is";
+interface Options {
+  target?: HTMLElement;
+}
+export function useCopyToClipboard(initial?: string) {
+  const clipboardRef = ref(initial || "");
+  const isSuccessRef = ref(false);
+  const copiedRef = ref(false);
+
+  watch(
+    clipboardRef,
+    (str?: string) => {
+      if (isDef(str)) {
+        copiedRef.value = true;
+        isSuccessRef.value = copyTextToClipboard(str);
+      }
+    },
+    { immediate: !!initial, flush: "sync" }
+  );
+
+  return { clipboardRef, isSuccessRef, copiedRef };
+}
+
+export function copyTextToClipboard(
+  input: string,
+  { target = document.body }: Options = {}
+) {
+  const element = document.createElement("textarea");
+  const previouslyFocusedElement = document.activeElement;
+
+  element.value = input;
+
+  element.setAttribute("readonly", "");
+
+  (element.style as any).contain = "strict";
+  element.style.position = "absolute";
+  element.style.left = "-9999px";
+  element.style.fontSize = "12pt";
+
+  const selection = document.getSelection();
+  let originalRange;
+  if (selection && selection.rangeCount > 0) {
+    originalRange = selection.getRangeAt(0);
+  }
+
+  target.append(element);
+  element.select();
+
+  element.selectionStart = 0;
+  element.selectionEnd = input.length;
+
+  let isSuccess = false;
+  try {
+    isSuccess = document.execCommand("copy");
+  } catch (e) {
+    throw new Error(e);
+  }
+
+  element.remove();
+
+  if (originalRange && selection) {
+    selection.removeAllRanges();
+    selection.addRange(originalRange);
+  }
+
+  if (previouslyFocusedElement) {
+    (previouslyFocusedElement as HTMLElement).focus();
+  }
+  return isSuccess;
+}

+ 142 - 81
src/views/system/dict.vue

@@ -1,15 +1,20 @@
 <template>
   <div class="dict-container">
+    <!-- 工具栏 -->
     <vxe-toolbar>
       <template #buttons>
         <vxe-input
-          v-model="demo1.filterName"
+          v-model="dictData.filterName"
           :placeholder="$t('message.hssearch')"
           @keyup="searchEvent"
         ></vxe-input>
       </template>
       <template #tools>
-        <vxe-button icon="el-icon-circle-plus-outline" status="primary">{{$t('message.hsadd')}}</vxe-button>
+        <vxe-button
+          icon="el-icon-circle-plus-outline"
+          status="primary"
+          @click="onAdd"
+        >{{$t('message.hsadd')}}</vxe-button>
         <vxe-button
           icon="el-icon-folder-opened"
           status="primary"
@@ -23,108 +28,75 @@
       </template>
     </vxe-toolbar>
 
+    <!-- 列表 -->
     <vxe-table
       ref="xTree"
       border
       resizable
       :tree-config="{children: 'children', iconOpen: 'fa fa-minus-square-o', iconClose: 'fa fa-plus-square-o'}"
-      :data="demo1.tableData"
+      :data="dictData.tableData"
       @cell-dblclick="cellDBLClickEvent"
     >
       <vxe-table-column tree-node field="name" title="字典名称"></vxe-table-column>
-      <vxe-table-column field="model" title="字典类型"></vxe-table-column>
+      <vxe-table-column title="字典类型">
+        <template #default="{ row }">
+          <el-tooltip effect="dark" :content="'双击复制:'+row.model" placement="top-end">
+            <span class="text-model">{{ row.model }}</span>
+          </el-tooltip>
+        </template>
+      </vxe-table-column>
       <vxe-table-column title="操作" width="330" fixed="right">
         <template #default="{ row }">
-          <vxe-button type="text" icon="el-icon-edit" @click="demo1.value8 = true">编辑</vxe-button>
-          <vxe-button type="text" icon="el-icon-circle-plus-outline">新增子类型</vxe-button>
+          <vxe-button type="text" icon="el-icon-edit" @click="onEdit(row)">编辑</vxe-button>
+          <vxe-button type="text" icon="el-icon-circle-plus-outline" @click="onAddChild(row)">新增子类型</vxe-button>
           <vxe-button v-show="row.model" type="text" icon="el-icon-setting">字典配置</vxe-button>
           <vxe-button type="text" icon="el-icon-delete" @click="confirmEvent">删除</vxe-button>
         </template>
       </vxe-table-column>
     </vxe-table>
 
+    <!-- 配置弹框 -->
     <vxe-modal
-      v-model="demo1.showEdit"
-      :title="demo1.selectRow ? '编辑&保存' : '新增&保存'"
-      width="800"
-      min-width="600"
-      min-height="300"
-      :loading="demo1.submitLoading"
       resize
-      destroy-on-close
+      width="450"
+      v-model="dictData.showEdit"
+      :title="dictData.selectRow ? '编辑' : '新增'"
+      :loading="dictData.submitLoading"
+      @hide="$refs.xForm.reset();"
     >
       <template #default>
         <vxe-form
-          :data="demo1.formData"
-          :items="demo1.formItems"
-          :rules="demo1.formRules"
+          ref="xForm"
+          :data="dictData.formData"
+          :items="dictData.formItems"
           title-align="right"
           title-width="100"
-          @submit="demo1.submitEvent"
+          @submit="dictData.submitEvent"
         ></vxe-form>
       </template>
     </vxe-modal>
-    <!-- <vxe-modal
-      v-model="demo1.value8"
-      title="记忆功能的窗口"
-      width="440"
-      height="230"
-      show-zoom
-      resize
-      remember
-    >
-      <template #default>
-        <vxe-form>
-          <vxe-form-item span="24">
-            <template #default>
-              <vxe-form
-                :data="demo1.formData3"
-                :rules="demo1.formRules3"
-                title-align="right"
-                title-width="80"
-              >
-                <vxe-form-item
-                  title="字典名称"
-                  field="name"
-                  span="24"
-                  :item-render="{name: 'input', attrs: {placeholder: '请输入字典名称'}}"
-                ></vxe-form-item>
-                <vxe-form-item
-                  title="字典类型"
-                  field="nickname"
-                  span="24"
-                  :item-render="{name: 'input', attrs: {placeholder: '请输入字典类型'}}"
-                ></vxe-form-item>
-                <vxe-form-item align="right" span="24">
-                  <template #default>
-                    <vxe-button @click="demo1.value8 = false">取消</vxe-button>
-                    <vxe-button status="primary" @click="onEdit">保存</vxe-button>
-                  </template>
-                </vxe-form-item>
-              </vxe-form>
-            </template>
-          </vxe-form-item>
-        </vxe-form>
-      </template>
-    </vxe-modal>-->
   </div>
 </template>
 <script  lang="ts">
-import { reactive, ref, nextTick } from "vue";
+import { reactive, ref, unref, nextTick } from "vue";
 import XEUtils from "xe-utils";
 import { cloneDeep } from "lodash-es";
 import { templateRef } from "@vueuse/core";
+import { useCopyToClipboard } from "/@/utils/useCopyToClipboard";
 import {
-  VxeTablePropTypes,
-  VxeTableInstance,
   VXETable,
-  VxeTableEvents
+  VxeTableInstance,
+  VxeTableEvents,
+  VxeTablePropTypes,
+  VxeFormPropTypes
 } from "vxe-table";
 
 export default {
   setup() {
-    const demo1 = reactive({
+    const dictData = reactive({
+      submitLoading: false,
       showEdit: false,
+      selectRow: null,
       filterName: "",
       tableData: [
         {
@@ -145,26 +117,65 @@ export default {
           ]
         },
         { id: 2, name: "操作系统", model: "operatingSystem" }
-      ]
+      ],
+      formData: {
+        name: "",
+        model: ""
+      },
+      formItems: [
+        {
+          field: "name",
+          title: "字典名称",
+          span: 24,
+          itemRender: {
+            name: "$input",
+            props: { placeholder: "请输入字典名称", clearable: true }
+          }
+        },
+        {
+          field: "model",
+          title: "字典类型",
+          span: 24,
+          itemRender: {
+            name: "$input",
+            props: {
+              placeholder: "请输入字典类型",
+              //这里vxe-table文档并没有提到,可以配置所选组件的所有属性,比如这里可以配置关于vxe-input的所有属性
+              disabled: true,
+              clearable: true
+            }
+          }
+        },
+        {
+          align: "right",
+          span: 24,
+          itemRender: {
+            name: "$buttons",
+            children: [
+              { props: { type: "submit", content: "提交", status: "primary" } },
+              { props: { type: "reset", content: "重置" } }
+            ]
+          }
+        }
+      ] as VxeFormPropTypes.Items
     });
 
-    let originData = cloneDeep(demo1.tableData);
+    let originData = cloneDeep(dictData.tableData);
 
-    const xTree = templateRef<HTMLElement | null>("xTree", null);
-    // const  = ref({} as VxeTableInstance);
+    const xTree = templateRef<HTMLElement | any>("xTree", null);
 
     const formatDate = (value: any) => {
       return XEUtils.toDateString(value, "yyyy-MM-dd HH:mm:ss.S");
     };
 
     const handleSearch = () => {
-      const filterName = XEUtils.toValueString(demo1.filterName).trim();
+      const filterName = XEUtils.toValueString(dictData.filterName).trim();
 
       if (filterName) {
         const options = { children: "children" };
         const searchProps = ["name"];
 
-        demo1.tableData = XEUtils.searchTree(
+        dictData.tableData = XEUtils.searchTree(
           originData,
           item =>
             searchProps.some(
@@ -179,7 +190,7 @@ export default {
           $table.setAllTreeExpand(true);
         });
       } else {
-        demo1.tableData = originData;
+        dictData.tableData = originData;
       }
     };
 
@@ -201,29 +212,74 @@ export default {
         });
     };
 
-    function onEdit() {
-      demo1.value8 = false;
-      VXETable.modal.message({
-        content: "测试数据,不可编辑",
-        status: "error"
-      });
+    function commonFn(value, disabled) {
+      dictData.selectRow = value;
+      dictData.showEdit = true;
+      dictData.formItems[1].itemRender.props.disabled = disabled;
     }
 
-    const cellDBLClickEvent: VxeTableEvents.CellDblclick = ({ row }) => {
+    // 新增
+    function onAdd() {
+      commonFn(null, false);
+    }
+
+    // 新增子类型
+    function onAddChild(row: any) {
       console.log(
         "%crow===>>>: ",
         "color: MidnightBlue; background: Aquamarine; font-size: 20px;",
         row
       );
+      commonFn(null, false);
+    }
+
+    // 编辑
+    function onEdit(row: any) {
+      dictData.formData = {
+        name: row.name,
+        model: row.model ? row.model : "暂无字典类型"
+      };
+      commonFn(row, true);
+      // VXETable.modal.message({
+      //   content: "测试数据,不可编辑",
+      //   status: "error"
+      // });
+    }
+
+    // 拷贝当前列表项的数据(字典类型)
+    const { clipboardRef } = useCopyToClipboard();
+    const cellDBLClickEvent: VxeTableEvents.CellDblclick = ({ row }) => {
+      clipboardRef.value = unref(row).model;
+    };
+
+    const xTable = ref({} as VxeTableInstance);
+
+    const submitEvent = () => {
+      dictData.submitLoading = true;
+      setTimeout(() => {
+        const $table = xTable.value;
+        dictData.submitLoading = false;
+        dictData.showEdit = false;
+        if (dictData.selectRow) {
+          VXETable.modal.message({ content: "保存成功", status: "success" });
+          Object.assign(dictData.selectRow, dictData.formData);
+        } else {
+          VXETable.modal.message({ content: "新增成功", status: "success" });
+          $table.insert(dictData.formData);
+        }
+      }, 500);
     };
 
     return {
-      demo1,
+      dictData,
       formatDate,
       searchEvent,
       confirmEvent,
+      cellDBLClickEvent,
+      submitEvent,
       onEdit,
-      cellDBLClickEvent
+      onAddChild,
+      onAdd
     };
   }
 };
@@ -244,4 +300,9 @@ export default {
 .vxe-button.size--medium.type--button {
   margin-right: 0.07em;
 }
+.text-model {
+  &:hover {
+    cursor: pointer;
+  }
+}
 </style>

+ 2 - 1
vite.config.ts

@@ -15,7 +15,8 @@ const { VITE_PORT, VITE_PUBLIC_PATH, VITE_PROXY, VITE_OPEN } = loadEnv();
 
 const alias: Record<string, string> = {
   "/@": pathResolve("src"),
-  "vue-i18n": "vue-i18n/dist/vue-i18n.cjs.js", //解决警告You are running the esm-bundler build of vue-i18n. It is recommended to configure your bundler to explicitly replace feature flag globals with boolean literals to get proper tree-shaking in the final bundle.
+  //解决开发环境下的警告 You are running the esm-bundler build of vue-i18n. It is recommended to configure your bundler to explicitly replace feature flag globals with boolean literals to get proper tree-shaking in the final bundle.
+  "vue-i18n": "vue-i18n/dist/vue-i18n.cjs.js",
 };
 
 const root: string = process.cwd();