Ver código fonte

feat(user table): add

xiaoxian521 4 anos atrás
pai
commit
18bde6e5dc
5 arquivos alterados com 437 adições e 21 exclusões
  1. 10 10
      index.html
  2. 11 6
      package-lock.json
  3. 3 2
      package.json
  4. 0 1
      src/main.ts
  5. 413 2
      src/views/user.vue

+ 10 - 10
index.html

@@ -52,15 +52,15 @@
           border: 3px solid transparent;
           /* COLOR 1 */
           border-top-color: #FFF;
-          -webkit-animation: spin 2s linear infinite;
+          -webkit-animation: spin 1s linear infinite;
           /* Chrome, Opera 15+, Safari 5+ */
-          -ms-animation: spin 2s linear infinite;
+          -ms-animation: spin 1s linear infinite;
           /* Chrome, Opera 15+, Safari 5+ */
-          -moz-animation: spin 2s linear infinite;
+          -moz-animation: spin 1s linear infinite;
           /* Chrome, Opera 15+, Safari 5+ */
-          -o-animation: spin 2s linear infinite;
+          -o-animation: spin 1s linear infinite;
           /* Chrome, Opera 15+, Safari 5+ */
-          animation: spin 2s linear infinite;
+          animation: spin 1s linear infinite;
           /* Chrome, Firefox 16+, IE 10+, Opera */
           z-index: 1001;
         }
@@ -76,15 +76,15 @@
           border: 3px solid transparent;
           /* COLOR 2 */
           border-top-color: #FFF;
-          -webkit-animation: spin 3s linear infinite;
+          -webkit-animation: spin 1s linear infinite;
           /* Chrome, Opera 15+, Safari 5+ */
-          -moz-animation: spin 3s linear infinite;
+          -moz-animation: spin 1s linear infinite;
           /* Chrome, Opera 15+, Safari 5+ */
-          -o-animation: spin 3s linear infinite;
+          -o-animation: spin 1s linear infinite;
           /* Chrome, Opera 15+, Safari 5+ */
-          -ms-animation: spin 3s linear infinite;
+          -ms-animation: spin 1s linear infinite;
           /* Chrome, Opera 15+, Safari 5+ */
-          animation: spin 3s linear infinite;
+          animation: spin 1s linear infinite;
           /* Chrome, Firefox 16+, IE 10+, Opera */
         }
 

+ 11 - 6
package-lock.json

@@ -1567,14 +1567,19 @@
       "integrity": "sha1-rId6p2qcRTaMl5Rx5GG1INOObPU="
     },
     "vxe-table": {
-      "version": "4.0.0-beta.10",
-      "resolved": "http://192.168.250.101:4873/vxe-table/-/vxe-table-4.0.0-beta.10.tgz",
-      "integrity": "sha1-kLeS8zRh+VHxWloNsDN/zc4fxGY="
+      "version": "4.0.7-beta.4",
+      "resolved": "http://192.168.250.101:4873/vxe-table/-/vxe-table-4.0.7-beta.4.tgz",
+      "integrity": "sha1-scanU3yNmioYybtEwqF0GNYAEok="
+    },
+    "xe-ajax": {
+      "version": "4.0.5",
+      "resolved": "http://192.168.250.101:4873/xe-ajax/-/xe-ajax-4.0.5.tgz",
+      "integrity": "sha1-N2kPiaN9m19U7yrk79PpJXDzLfM="
     },
     "xe-utils": {
-      "version": "3.1.8",
-      "resolved": "http://192.168.250.101:4873/xe-utils/-/xe-utils-3.1.8.tgz",
-      "integrity": "sha1-I2mxYblYwPi9R9nA/rNZCSCIcPE="
+      "version": "3.1.12",
+      "resolved": "http://192.168.250.101:4873/xe-utils/-/xe-utils-3.1.12.tgz",
+      "integrity": "sha1-YTfxGrvSJu0DXMAmfWkZHwpFQaM="
     },
     "xgplayer": {
       "version": "2.18.3",

+ 3 - 2
package.json

@@ -28,8 +28,9 @@
     "vue-router": "^4.0.4",
     "vuedraggable": "^4.0.1",
     "vuex": "^4.0.0",
-    "vxe-table": "^4.0.0-beta.10",
-    "xe-utils": "^3.1.8",
+    "vxe-table": "^4.0.7-beta.4",
+    "xe-ajax": "^4.0.5",
+    "xe-utils": "^3.1.12",
     "xgplayer": "^2.18.3"
   },
   "devDependencies": {

+ 0 - 1
src/main.ts

@@ -9,7 +9,6 @@ import ElementPlus from 'element-plus'
 import 'element-plus/lib/theme-chalk/index.css'
 
 // 内置vxe-table
-import 'xe-utils'
 import VXETable from 'vxe-table'
 import 'vxe-table/lib/style.css'
 

+ 413 - 2
src/views/user.vue

@@ -1,12 +1,423 @@
 <template>
-  <div>用户管理页面</div>
+  <vxe-grid ref="xGrid" v-bind="gridOptions" style="width:98%"></vxe-grid>
 </template>
 
 <script lang='ts'>
+import { defineComponent, onMounted, reactive, ref, Ref } from "vue";
+import { VXETable, VxeGridInstance, VxeGridProps } from "vxe-table";
+import XEUtils from "xe-utils";
+import XEAjax from "xe-ajax";
 export default {
   name: "user",
   setup() {
-    return {};
+    const xGrid = ref({} as VxeGridInstance);
+
+    const gridOptions = reactive({
+      border: true,
+      resizable: true,
+      showHeaderOverflow: true,
+      showOverflow: true,
+      highlightHoverRow: true,
+      keepSource: true,
+      id: "full_edit_1",
+      height: 600,
+      rowId: "id",
+      customConfig: {
+        storage: true,
+        checkMethod({ column }) {
+          if (["nickname", "role"].includes(column.property)) {
+            return false;
+          }
+          return true;
+        },
+      },
+      printConfig: {
+        columns: [
+          { field: "name" },
+          { field: "email" },
+          { field: "nickname" },
+          { field: "age" },
+          { field: "amount" },
+        ],
+      },
+      sortConfig: {
+        trigger: "cell",
+        remote: true,
+      },
+      filterConfig: {
+        remote: true,
+      },
+      pagerConfig: {
+        pageSize: 10,
+        pageSizes: [5, 10, 15, 20, 50, 100, 200, 500, 1000],
+      },
+      formConfig: {
+        titleWidth: 100,
+        titleAlign: "right",
+        items: [
+          {
+            field: "name",
+            title: "app.body.label.name",
+            span: 8,
+            titlePrefix: {
+              message: "app.body.valid.rName",
+              icon: "fa fa-exclamation-circle",
+            },
+            itemRender: {
+              name: "$input",
+              props: { placeholder: "请输入名称" },
+            },
+          },
+          {
+            field: "email",
+            title: "邮件",
+            span: 8,
+            itemRender: {
+              name: "$input",
+              props: { placeholder: "请输入邮件" },
+            },
+          },
+          {
+            field: "nickname",
+            title: "昵称",
+            span: 8,
+            itemRender: {
+              name: "$input",
+              props: { placeholder: "请输入昵称" },
+            },
+          },
+          {
+            field: "role",
+            title: "角色",
+            span: 8,
+            folding: true,
+            itemRender: {
+              name: "$input",
+              props: { placeholder: "请输入角色" },
+            },
+          },
+          {
+            field: "sex",
+            title: "性别",
+            span: 8,
+            folding: true,
+            titleSuffix: {
+              message: "注意,必填信息!",
+              icon: "fa fa-info-circle",
+            },
+            itemRender: { name: "$select", options: [] },
+          },
+          {
+            field: "age",
+            title: "年龄",
+            span: 8,
+            folding: true,
+            itemRender: {
+              name: "$input",
+              props: {
+                type: "number",
+                min: 1,
+                max: 120,
+                placeholder: "请输入年龄",
+              },
+            },
+          },
+          {
+            span: 24,
+            align: "center",
+            collapseNode: true,
+            itemRender: {
+              name: "$buttons",
+              children: [
+                {
+                  props: {
+                    type: "submit",
+                    content: "app.body.label.search",
+                    status: "primary",
+                  },
+                },
+                { props: { type: "reset", content: "app.body.label.reset" } },
+              ],
+            },
+          },
+        ],
+      },
+      toolbarConfig: {
+        buttons: [
+          { code: "insert_actived", name: "新增", icon: "fa fa-plus" },
+          { code: "delete", name: "直接删除", icon: "fa fa-trash-o" },
+          { code: "mark_cancel", name: "删除/取消", icon: "fa fa-trash-o" },
+          {
+            code: "save",
+            name: "app.body.button.save",
+            icon: "fa fa-save",
+            status: "success",
+          },
+        ],
+        refresh: true,
+        import: true,
+        export: true,
+        print: true,
+        zoom: true,
+        custom: true,
+      },
+      proxyConfig: {
+        seq: true, // 启用动态序号代理
+        sort: true, // 启用排序代理
+        filter: true, // 启用筛选代理
+        form: true, // 启用表单代理
+        props: {
+          result: "result",
+          total: "page.total",
+        },
+        ajax: {
+          // 接收 Promise
+          query: ({ page, sorts, filters, form }) => {
+            const queryParams: any = Object.assign({}, form);
+            // 处理排序条件
+            const firstSort = sorts[0];
+            if (firstSort) {
+              queryParams.sort = firstSort.property;
+              queryParams.order = firstSort.order;
+            }
+            // 处理筛选条件
+            filters.forEach(({ property, values }) => {
+              queryParams[property] = values.join(",");
+            });
+            return XEAjax.get(
+              `https://api.xuliangzhan.com:10443/api/pub/page/list/${page.pageSize}/${page.currentPage}`,
+              queryParams
+            );
+          },
+          delete: ({ body }) =>
+            XEAjax.post("https://api.xuliangzhan.com:10443/api/pub/save", body),
+          save: ({ body }) =>
+            XEAjax.post("https://api.xuliangzhan.com:10443/api/pub/save", body),
+        },
+      },
+      columns: [
+        { type: "checkbox", title: "ID", width: 120 },
+        {
+          field: "name",
+          title: "Name",
+          sortable: true,
+          titleHelp: { message: "名称必须填写!" },
+          editRender: { name: "input", attrs: { placeholder: "请输入名称" } },
+        },
+        {
+          field: "role",
+          title: "Role",
+          sortable: true,
+          filters: [
+            { label: "前端开发", value: "前端" },
+            { label: "后端开发", value: "后端" },
+            { label: "测试", value: "测试" },
+            { label: "程序员鼓励师", value: "程序员鼓励师" },
+          ],
+          filterMultiple: false,
+          editRender: { name: "input", attrs: { placeholder: "请输入角色" } },
+        },
+        {
+          field: "email",
+          title: "Email",
+          width: 160,
+          editRender: { name: "$input", props: { placeholder: "请输入邮件" } },
+        },
+        {
+          field: "nickname",
+          title: "Nickname",
+          editRender: { name: "input", attrs: { placeholder: "请输入昵称" } },
+        },
+        {
+          field: "sex",
+          title: "Sex",
+          editRender: {
+            name: "$select",
+            options: [],
+            props: { placeholder: "请选择性别" },
+          },
+        },
+        {
+          field: "age",
+          title: "Age",
+          visible: false,
+          sortable: true,
+          editRender: {
+            name: "$input",
+            props: { type: "number", min: 1, max: 120 },
+          },
+        },
+        {
+          field: "amount",
+          title: "Amount",
+          formatter({ cellValue }) {
+            return cellValue
+              ? `¥${XEUtils.commafy(XEUtils.toNumber(cellValue), {
+                  digits: 2,
+                })}`
+              : "";
+          },
+          editRender: {
+            name: "$input",
+            props: { type: "float", digits: 2, placeholder: "请输入数值" },
+          },
+        },
+        {
+          field: "updateDate",
+          title: "Update Date",
+          width: 160,
+          visible: false,
+          sortable: true,
+          formatter({ cellValue }) {
+            return XEUtils.toDateString(cellValue, "yyyy-MM-dd HH:ss:mm");
+          },
+        },
+        {
+          field: "createDate",
+          title: "Create Date",
+          width: 160,
+          visible: false,
+          sortable: true,
+          formatter({ cellValue }) {
+            return XEUtils.toDateString(cellValue, "yyyy-MM-dd");
+          },
+        },
+      ],
+      importConfig: {
+        remote: true,
+        types: ["xlsx"],
+        modes: ["insert"],
+        // 自定义服务端导入
+        importMethod({ file }) {
+          const $grid = xGrid.value;
+          const formBody = new FormData();
+          formBody.append("file", file);
+          return XEAjax.post(
+            "https://api.xuliangzhan.com:10443/api/pub/import",
+            formBody
+          )
+            .then((data) => {
+              VXETable.modal.message({
+                message: `成功导入 ${data.result.insertRows} 条记录!`,
+                status: "success",
+              });
+              // 导入完成,刷新表格
+              $grid.commitProxy("query");
+            })
+            .catch(() => {
+              VXETable.modal.message({
+                message: "导入失败,请检查数据是否正确!",
+                status: "error",
+              });
+            });
+        },
+      },
+      exportConfig: {
+        remote: true,
+        types: ["xlsx"],
+        modes: ["current", "selected", "all"],
+        // 自定义服务端导出
+        exportMethod({ options }) {
+          const $grid = xGrid.value;
+          const proxyInfo = $grid.getProxyInfo();
+          // 传给服务端的参数
+          const body = {
+            filename: options.filename,
+            sheetName: options.sheetName,
+            isHeader: options.isHeader,
+            original: options.original,
+            mode: options.mode,
+            pager: proxyInfo ? proxyInfo.pager : null,
+            ids:
+              options.mode === "selected"
+                ? options.data.map((item) => item.id)
+                : [],
+            fields: options.columns.map((column) => {
+              return {
+                field: column.property,
+                title: column.title,
+              };
+            }),
+          };
+          // 开始服务端导出
+          return XEAjax.post(
+            "https://api.xuliangzhan.com:10443/api/pub/export",
+            body
+          )
+            .then((data) => {
+              if (data.id) {
+                VXETable.modal.message({
+                  message: "导出成功,开始下载",
+                  status: "success",
+                });
+                // 读取路径,请求文件
+                XEAjax.fetch(
+                  `https://api.xuliangzhan.com:10443/api/pub/export/download/${data.id}`
+                ).then((response) => {
+                  response.blob().then((blob) => {
+                    // 开始下载
+                    VXETable.saveFile({
+                      filename: "导出数据",
+                      type: "xlsx",
+                      content: blob,
+                    });
+                  });
+                });
+              }
+            })
+            .catch(() => {
+              VXETable.modal.message({
+                message: "导出失败!",
+                status: "error",
+              });
+            });
+        },
+      },
+      checkboxConfig: {
+        labelField: "id",
+        reserve: true,
+        highlight: true,
+        range: true,
+      },
+      editRules: {
+        name: [
+          { required: true, message: "app.body.valid.rName" },
+          { min: 3, max: 50, message: "名称长度在 3 到 50 个字符" },
+        ],
+        email: [{ required: true, message: "邮件必须填写" }],
+        role: [{ required: true, message: "角色必须填写" }],
+      },
+      editConfig: {
+        trigger: "click",
+        mode: "row",
+        showStatus: true,
+      },
+    } as VxeGridProps);
+
+    onMounted(() => {
+      const sexList = [
+        { label: "女", value: "0" },
+        { label: "男", value: "1" },
+      ];
+      const { formConfig, columns } = gridOptions;
+      if (columns) {
+        const sexColumn = columns[5];
+        if (sexColumn && sexColumn.editRender) {
+          sexColumn.editRender.options = sexList;
+        }
+      }
+      if (formConfig && formConfig.items) {
+        const sexItem = formConfig.items[4];
+        if (sexItem && sexItem.itemRender) {
+          sexItem.itemRender.options = sexList;
+        }
+      }
+    });
+
+    return {
+      xGrid,
+      gridOptions,
+    };
   },
 };
 </script>