bianjiang 1 year ago
parent
commit
11ae7258eb
59 changed files with 1447 additions and 3070 deletions
  1. 180 38
      package-lock.json
  2. 7 3
      package.json
  3. 0 2
      src/components/Image.tsx
  4. 0 0
      src/components/Provider/index.tsx
  5. 202 0
      src/controllers/ListController.ts
  6. 162 0
      src/modules/admin/components/CategoryModal.tsx
  7. 15 0
      src/modules/admin/http.ts
  8. 2 18
      src/modules/admin/index.ts
  9. 11 0
      src/modules/admin/module/auth/index.ts
  10. 32 0
      src/modules/admin/module/category/actions.tsx
  11. 31 0
      src/modules/admin/module/category/https.ts
  12. 41 0
      src/modules/admin/module/category/index.ts
  13. 0 27
      src/modules/queenjs/adapter/vue/components/loading/index.less
  14. 0 31
      src/modules/queenjs/adapter/vue/components/loading/index.tsx
  15. 0 42
      src/modules/queenjs/adapter/vue/components/modal/ModalConfirm.tsx
  16. 0 59
      src/modules/queenjs/adapter/vue/components/modal/ModalInput.tsx
  17. 0 118
      src/modules/queenjs/adapter/vue/components/modal/index.less
  18. 0 265
      src/modules/queenjs/adapter/vue/components/modal/index.tsx
  19. 0 14
      src/modules/queenjs/adapter/vue/components/provider/index.tsx
  20. 0 3
      src/modules/queenjs/adapter/vue/index.ts
  21. 0 38
      src/modules/queenjs/adapter/vue/register/feedback.ts
  22. 0 3
      src/modules/queenjs/api/bus.ts
  23. 0 84
      src/modules/queenjs/api/feedback.ts
  24. 0 29
      src/modules/queenjs/api/file.ts
  25. 0 13
      src/modules/queenjs/api/index.ts
  26. 0 38
      src/modules/queenjs/api/url.ts
  27. 0 35
      src/modules/queenjs/core/comm/bus.ts
  28. 0 141
      src/modules/queenjs/core/comm/event.ts
  29. 0 13
      src/modules/queenjs/core/defineUI/DefaultUI.tsx
  30. 0 51
      src/modules/queenjs/core/defineUI/index.tsx
  31. 0 433
      src/modules/queenjs/core/defineUI/typings.ts
  32. 0 123
      src/modules/queenjs/core/dict/index.ts
  33. 0 164
      src/modules/queenjs/core/effect/index.ts
  34. 0 59
      src/modules/queenjs/core/exception/index.ts
  35. 0 82
      src/modules/queenjs/core/http/index.ts
  36. 0 11
      src/modules/queenjs/core/index.ts
  37. 0 126
      src/modules/queenjs/core/module/actions.ts
  38. 0 23
      src/modules/queenjs/core/module/control.ts
  39. 0 62
      src/modules/queenjs/core/module/hook.ts
  40. 0 31
      src/modules/queenjs/core/module/https.ts
  41. 0 142
      src/modules/queenjs/core/module/index.ts
  42. 0 108
      src/modules/queenjs/core/module/store.ts
  43. 0 12
      src/modules/queenjs/core/module/subModule.ts
  44. 0 147
      src/modules/queenjs/core/state/index.ts
  45. 0 15
      src/modules/queenjs/core/use/useCapturedFunc.ts
  46. 0 2
      src/modules/queenjs/index.ts
  47. 0 91
      src/modules/queenjs/typing.ts
  48. 13 0
      src/typings/asset.d.ts
  49. 1 0
      src/utils/index.ts
  50. 29 0
      src/utils/request.ts
  51. 5 5
      src/views/admin/App.tsx
  52. 123 0
      src/views/admin/category/CategoryTree.tsx
  53. 36 0
      src/views/admin/category/index.tsx
  54. 215 35
      src/views/admin/components/Editor.tsx
  55. 4 0
      src/views/admin/config/menus.ts
  56. 1 3
      src/views/admin/intro/index.tsx
  57. 3 1
      src/views/admin/main.ts
  58. 4 0
      src/views/admin/router/index.ts
  59. 330 330
      yarn.lock

+ 180 - 38
package-lock.json

@@ -18,14 +18,17 @@
         "@types/rollup-plugin-css-only": "^3.1.0",
         "@vitejs/plugin-vue-jsx": "^3.0.1",
         "ant-design-vue": "^3.2.19",
-        "froala-editor": "^4.0.18",
+        "axios": "^1.4.0",
+        "eventemitter3": "4.0.7",
         "less": "^4.1.3",
         "less-loader": "^11.1.0",
+        "moduse": "^0.0.7",
         "rollup-plugin-css-only": "^4.3.0",
         "swiper": "^9.2.4",
         "unplugin-vue-components": "^0.24.1",
         "vite-plugin-windicss": "^1.8.10",
         "vue": "^3.2.47",
+        "vue-moduse": "^0.0.10",
         "vue-router": "^4.1.6",
         "vue-types": "^5.0.2",
         "windicss": "^3.5.6"
@@ -2188,12 +2191,6 @@
       "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
       "license": "MIT"
     },
-    "node_modules/@types/rollup-plugin-css-only/node_modules/@types/node": {
-      "version": "18.16.2",
-      "resolved": "http://124.70.149.18:4873/@types%2fnode/-/node-18.16.2.tgz",
-      "integrity": "sha512-GQW/JL/5Fz/0I8RpeBG9lKp0+aNcXEaVL71c0D2Q0QHDTFvlYKT7an0onCUXj85anv7b4/WesqdfchLc0jtsCg==",
-      "license": "MIT"
-    },
     "node_modules/@types/rollup-plugin-css-only/node_modules/rollup": {
       "version": "0.63.5",
       "resolved": "http://124.70.149.18:4873/rollup/-/rollup-0.63.5.tgz",
@@ -2693,9 +2690,9 @@
       }
     },
     "node_modules/acorn-import-assertions": {
-      "version": "1.8.0",
-      "resolved": "http://124.70.149.18:4873/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
-      "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
+      "version": "1.9.0",
+      "resolved": "http://124.70.149.18:4873/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
+      "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
       "license": "MIT",
       "peer": true,
       "peerDependencies": {
@@ -2831,6 +2828,23 @@
       "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==",
       "license": "MIT"
     },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "http://124.70.149.18:4873/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+      "license": "MIT"
+    },
+    "node_modules/axios": {
+      "version": "1.4.0",
+      "resolved": "http://124.70.149.18:4873/axios/-/axios-1.4.0.tgz",
+      "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
+      "license": "MIT",
+      "dependencies": {
+        "follow-redirects": "^1.15.0",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
     "node_modules/babel-merge": {
       "version": "3.0.0",
       "resolved": "http://124.70.149.18:4873/babel-merge/-/babel-merge-3.0.0.tgz",
@@ -3067,6 +3081,18 @@
       "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
       "license": "MIT"
     },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "http://124.70.149.18:4873/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "license": "MIT",
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
     "node_modules/commander": {
       "version": "2.20.3",
       "resolved": "http://124.70.149.18:4873/commander/-/commander-2.20.3.tgz",
@@ -3185,6 +3211,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "http://124.70.149.18:4873/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
     "node_modules/dom-align": {
       "version": "1.12.4",
       "resolved": "http://124.70.149.18:4873/dom-align/-/dom-align-1.12.4.tgz",
@@ -3363,6 +3398,12 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/eventemitter3": {
+      "version": "4.0.7",
+      "resolved": "http://124.70.149.18:4873/eventemitter3/-/eventemitter3-4.0.7.tgz",
+      "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+      "license": "MIT"
+    },
     "node_modules/events": {
       "version": "3.3.0",
       "resolved": "http://124.70.149.18:4873/events/-/events-3.3.0.tgz",
@@ -3440,11 +3481,39 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/froala-editor": {
-      "version": "4.0.18",
-      "resolved": "http://124.70.149.18:4873/froala-editor/-/froala-editor-4.0.18.tgz",
-      "integrity": "sha512-FLTe9OrgFgEe1x+lOwl2tmJxPPyW6HgMLh5A0C/x6TQlziixjp6P8kMLjyG3wv4ve8hgWm+iCxfAbnd1KxvDZA==",
-      "license": "https://www.froala.com/wysiwyg-editor/pricing"
+    "node_modules/follow-redirects": {
+      "version": "1.15.2",
+      "resolved": "http://124.70.149.18:4873/follow-redirects/-/follow-redirects-1.15.2.tgz",
+      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.0",
+      "resolved": "http://124.70.149.18:4873/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
     },
     "node_modules/fsevents": {
       "version": "2.3.2",
@@ -4030,7 +4099,6 @@
       "resolved": "http://124.70.149.18:4873/mime-db/-/mime-db-1.52.0.tgz",
       "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
       "license": "MIT",
-      "peer": true,
       "engines": {
         "node": ">= 0.6"
       }
@@ -4040,7 +4108,6 @@
       "resolved": "http://124.70.149.18:4873/mime-types/-/mime-types-2.1.35.tgz",
       "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
       "license": "MIT",
-      "peer": true,
       "dependencies": {
         "mime-db": "1.52.0"
       },
@@ -4063,6 +4130,15 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
+    "node_modules/moduse": {
+      "version": "0.0.7",
+      "resolved": "http://124.70.149.18:4873/moduse/-/moduse-0.0.7.tgz",
+      "integrity": "sha512-9FyEh/sg4pObHbF79BHA2ZvUOzlOkFMcvn798U7YrpDAgFMXtS4HY1CNYEgB75MpdNr8ryeDVEdAHw1AQkzlgg==",
+      "license": "MIT",
+      "dependencies": {
+        "lodash": "^4.17.21"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.2",
       "resolved": "http://124.70.149.18:4873/ms/-/ms-2.1.2.tgz",
@@ -4318,6 +4394,12 @@
         "node": "^10 || ^12 || >=14"
       }
     },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "http://124.70.149.18:4873/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+      "license": "MIT"
+    },
     "node_modules/prr": {
       "version": "1.0.1",
       "resolved": "http://124.70.149.18:4873/prr/-/prr-1.0.1.tgz",
@@ -4490,9 +4572,9 @@
       }
     },
     "node_modules/rollup": {
-      "version": "3.21.6",
-      "resolved": "http://124.70.149.18:4873/rollup/-/rollup-3.21.6.tgz",
-      "integrity": "sha512-SXIICxvxQxR3D4dp/3LDHZIJPC8a4anKMHd4E3Jiz2/JnY+2bEjqrOokAauc5ShGVNFHlEFjBXAXlaxkJqIqSg==",
+      "version": "3.21.7",
+      "resolved": "http://124.70.149.18:4873/rollup/-/rollup-3.21.7.tgz",
+      "integrity": "sha512-KXPaEuR8FfUoK2uHwNjxTmJ18ApyvD6zJpYv9FOJSqLStmt6xOY84l1IjK2dSolQmoXknrhEFRaPRgOPdqCT5w==",
       "license": "MIT",
       "bin": {
         "rollup": "dist/bin/rollup"
@@ -5066,6 +5148,12 @@
         "@vue/shared": "3.2.47"
       }
     },
+    "node_modules/vue-moduse": {
+      "version": "0.0.10",
+      "resolved": "http://124.70.149.18:4873/vue-moduse/-/vue-moduse-0.0.10.tgz",
+      "integrity": "sha512-lS0tf4kvJKw+sohwuObujk90NGD024H+pOulVRv73q+75+pccKz6R6VnENMM11AgygOmYK0fioUlgOGYMFYgrw==",
+      "license": "MIT"
+    },
     "node_modules/vue-router": {
       "version": "4.1.6",
       "resolved": "http://124.70.149.18:4873/vue-router/-/vue-router-4.1.6.tgz",
@@ -6680,11 +6768,6 @@
           "resolved": "http://124.70.149.18:4873/@types%2festree/-/estree-0.0.39.tgz",
           "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="
         },
-        "@types/node": {
-          "version": "18.16.2",
-          "resolved": "http://124.70.149.18:4873/@types%2fnode/-/node-18.16.2.tgz",
-          "integrity": "sha512-GQW/JL/5Fz/0I8RpeBG9lKp0+aNcXEaVL71c0D2Q0QHDTFvlYKT7an0onCUXj85anv7b4/WesqdfchLc0jtsCg=="
-        },
         "rollup": {
           "version": "0.63.5",
           "resolved": "http://124.70.149.18:4873/rollup/-/rollup-0.63.5.tgz",
@@ -7101,9 +7184,9 @@
       "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw=="
     },
     "acorn-import-assertions": {
-      "version": "1.8.0",
-      "resolved": "http://124.70.149.18:4873/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
-      "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
+      "version": "1.9.0",
+      "resolved": "http://124.70.149.18:4873/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
+      "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
       "peer": true,
       "requires": {}
     },
@@ -7197,6 +7280,21 @@
       "resolved": "http://124.70.149.18:4873/async-validator/-/async-validator-4.2.5.tgz",
       "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg=="
     },
+    "asynckit": {
+      "version": "0.4.0",
+      "resolved": "http://124.70.149.18:4873/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+    },
+    "axios": {
+      "version": "1.4.0",
+      "resolved": "http://124.70.149.18:4873/axios/-/axios-1.4.0.tgz",
+      "integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
+      "requires": {
+        "follow-redirects": "^1.15.0",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
     "babel-merge": {
       "version": "3.0.0",
       "resolved": "http://124.70.149.18:4873/babel-merge/-/babel-merge-3.0.0.tgz",
@@ -7340,6 +7438,14 @@
       "resolved": "http://124.70.149.18:4873/color-name/-/color-name-1.1.3.tgz",
       "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
     },
+    "combined-stream": {
+      "version": "1.0.8",
+      "resolved": "http://124.70.149.18:4873/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "requires": {
+        "delayed-stream": "~1.0.0"
+      }
+    },
     "commander": {
       "version": "2.20.3",
       "resolved": "http://124.70.149.18:4873/commander/-/commander-2.20.3.tgz",
@@ -7417,6 +7523,11 @@
       "resolved": "http://124.70.149.18:4873/deepmerge/-/deepmerge-2.2.1.tgz",
       "integrity": "sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA=="
     },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "http://124.70.149.18:4873/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+    },
     "dom-align": {
       "version": "1.12.4",
       "resolved": "http://124.70.149.18:4873/dom-align/-/dom-align-1.12.4.tgz",
@@ -7547,6 +7658,11 @@
       "resolved": "http://124.70.149.18:4873/esutils/-/esutils-2.0.3.tgz",
       "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
     },
+    "eventemitter3": {
+      "version": "4.0.7",
+      "resolved": "http://124.70.149.18:4873/eventemitter3/-/eventemitter3-4.0.7.tgz",
+      "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+    },
     "events": {
       "version": "3.3.0",
       "resolved": "http://124.70.149.18:4873/events/-/events-3.3.0.tgz",
@@ -7602,10 +7718,20 @@
         "path-exists": "^4.0.0"
       }
     },
-    "froala-editor": {
-      "version": "4.0.18",
-      "resolved": "http://124.70.149.18:4873/froala-editor/-/froala-editor-4.0.18.tgz",
-      "integrity": "sha512-FLTe9OrgFgEe1x+lOwl2tmJxPPyW6HgMLh5A0C/x6TQlziixjp6P8kMLjyG3wv4ve8hgWm+iCxfAbnd1KxvDZA=="
+    "follow-redirects": {
+      "version": "1.15.2",
+      "resolved": "http://124.70.149.18:4873/follow-redirects/-/follow-redirects-1.15.2.tgz",
+      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
+    },
+    "form-data": {
+      "version": "4.0.0",
+      "resolved": "http://124.70.149.18:4873/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "requires": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      }
     },
     "fsevents": {
       "version": "2.3.2",
@@ -7979,14 +8105,12 @@
     "mime-db": {
       "version": "1.52.0",
       "resolved": "http://124.70.149.18:4873/mime-db/-/mime-db-1.52.0.tgz",
-      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
-      "peer": true
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
     },
     "mime-types": {
       "version": "2.1.35",
       "resolved": "http://124.70.149.18:4873/mime-types/-/mime-types-2.1.35.tgz",
       "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
-      "peer": true,
       "requires": {
         "mime-db": "1.52.0"
       }
@@ -7999,6 +8123,14 @@
         "brace-expansion": "^2.0.1"
       }
     },
+    "moduse": {
+      "version": "0.0.7",
+      "resolved": "http://124.70.149.18:4873/moduse/-/moduse-0.0.7.tgz",
+      "integrity": "sha512-9FyEh/sg4pObHbF79BHA2ZvUOzlOkFMcvn798U7YrpDAgFMXtS4HY1CNYEgB75MpdNr8ryeDVEdAHw1AQkzlgg==",
+      "requires": {
+        "lodash": "^4.17.21"
+      }
+    },
     "ms": {
       "version": "2.1.2",
       "resolved": "http://124.70.149.18:4873/ms/-/ms-2.1.2.tgz",
@@ -8153,6 +8285,11 @@
         "source-map-js": "^1.0.2"
       }
     },
+    "proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "http://124.70.149.18:4873/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+    },
     "prr": {
       "version": "1.0.1",
       "resolved": "http://124.70.149.18:4873/prr/-/prr-1.0.1.tgz",
@@ -8267,9 +8404,9 @@
       "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
     },
     "rollup": {
-      "version": "3.21.6",
-      "resolved": "http://124.70.149.18:4873/rollup/-/rollup-3.21.6.tgz",
-      "integrity": "sha512-SXIICxvxQxR3D4dp/3LDHZIJPC8a4anKMHd4E3Jiz2/JnY+2bEjqrOokAauc5ShGVNFHlEFjBXAXlaxkJqIqSg==",
+      "version": "3.21.7",
+      "resolved": "http://124.70.149.18:4873/rollup/-/rollup-3.21.7.tgz",
+      "integrity": "sha512-KXPaEuR8FfUoK2uHwNjxTmJ18ApyvD6zJpYv9FOJSqLStmt6xOY84l1IjK2dSolQmoXknrhEFRaPRgOPdqCT5w==",
       "requires": {
         "fsevents": "~2.3.2"
       }
@@ -8584,6 +8721,11 @@
         "@vue/shared": "3.2.47"
       }
     },
+    "vue-moduse": {
+      "version": "0.0.10",
+      "resolved": "http://124.70.149.18:4873/vue-moduse/-/vue-moduse-0.0.10.tgz",
+      "integrity": "sha512-lS0tf4kvJKw+sohwuObujk90NGD024H+pOulVRv73q+75+pccKz6R6VnENMM11AgygOmYK0fioUlgOGYMFYgrw=="
+    },
     "vue-router": {
       "version": "4.1.6",
       "resolved": "http://124.70.149.18:4873/vue-router/-/vue-router-4.1.6.tgz",

+ 7 - 3
package.json

@@ -16,17 +16,21 @@
     "@linaria/rollup": "^4.3.7",
     "@rollup/plugin-inject": "^5.0.3",
     "@types/lodash": "^4.14.194",
+    "@types/quill": "^2.0.10",
     "@types/rollup-plugin-css-only": "^3.1.0",
     "@vitejs/plugin-vue-jsx": "^3.0.1",
     "ant-design-vue": "^3.2.19",
-    "froala-editor": "^4.0.18",
+    "axios": "^1.4.0",   
     "less": "^4.1.3",
-    "less-loader": "^11.1.0",
+    "less-loader": "^11.1.0",   
+    "pinia": "^2.0.36",
+    "quill": "^1.3.7",
+    "quill-better-table": "^1.2.10",
     "rollup-plugin-css-only": "^4.3.0",
     "swiper": "^9.2.4",
     "unplugin-vue-components": "^0.24.1",
     "vite-plugin-windicss": "^1.8.10",
-    "vue": "^3.2.47",
+    "vue": "^3.2.47",   
     "vue-router": "^4.1.6",
     "vue-types": "^5.0.2",
     "windicss": "^3.5.6"

+ 0 - 2
src/components/Image.tsx

@@ -1,8 +1,6 @@
 import { defineComponent, ref, reactive } from "vue";
 import { any } from "vue-types";
 
-// const defaultImg = getImageUrl("image-error.svg");
-
 export default defineComponent({
   props: {
     src: any<string | undefined>().isRequired,

+ 0 - 0
src/components/Provider/Provider.tsx → src/components/Provider/index.tsx


+ 202 - 0
src/controllers/ListController.ts

@@ -0,0 +1,202 @@
+
+
+class ListItemBase {
+  _id?: string = "";
+}
+
+class StatePageList<T extends ListItemBase, Q> extends StateRoot {
+  size = 10;
+  page = 1;
+  total = 0;
+  list: T[] = [];
+  query: Q = {} as any;
+  fields = ""; //字段使用逗号隔开
+  loading = false;
+
+  canLoadNext = this.computed((state) => {
+    const { size, page, total } = state;
+    return page * size < total;
+  });
+}
+
+/**
+ * 分页列表控制器
+ */
+export class PageListController<T extends ListItemBase, Q> {
+  state = new StatePageList<T, Q>().reactive();
+  http: any;
+  dataList: any[] = [];
+  httpGet?: (
+    page: number,
+    size: number,
+    query?: any,
+    fields?: string
+  ) => Promise<any>;
+  httpDelete?: (id: string) => Promise<any>;
+  httpDetail?: (id: string) => Promise<any>;
+  httpAdd?: (query?: any) => Promise<any>;
+  httpSave?: (item: T) => Promise<any>;
+  hasLimit = false;
+  listFilter: ((item: T) => T) | null = null;
+
+  constructor(
+    http: any,
+    get?: () => (
+      page: number,
+      size: number,
+      query?: any,
+      fields?: string
+    ) => Promise<any>
+  ) {
+    this.http = http;
+
+    if (get) {
+      this.httpGet = get();
+    }
+  }
+
+  crud(
+    prefix: string,
+    type: "list" | "create" | "update" | "delete" | "detail",
+    data?: any
+  ) {
+    const config: any = { method: "POST" };
+    if (type == "list") {
+      config.method = "GET";
+      config.params = data;
+    } else if (type == "detail") {
+      config.method = "GET";
+    } else {
+      config.data = data;
+    }
+    let uri = `${prefix}/${type}`;
+    if (type == "delete" || type == "detail") uri += `/${data}`;
+
+    return this.http.request(uri, config);
+  }
+  setCrudPrefix(prefix: string) {
+    this.httpGet = (
+      page: number,
+      size: number,
+      query: any,
+      fields?: string
+    ) => {
+      return this.crud(prefix, "list", {
+        page,
+        size,
+        query,
+        fields,
+      });
+    };
+    this.httpAdd = (data: any) => {
+      return this.crud(prefix, "create", data);
+    };
+    this.httpSave = (data: any) => {
+      return this.crud(prefix, "update", data);
+    };
+    this.httpDelete = (id: string) => {
+      return this.crud(prefix, "delete", id);
+    };
+    this.httpDetail = (id: string) => {
+      return this.crud(prefix, "detail", id);
+    };
+  }
+  async resumeShow() {
+    if (this.state.list.length < 1) {
+      await this.loadPage(1);
+    }
+  }
+  //刷新页面,重新获取数据
+  async fresh() {
+    await this.loadPage(this.state.page, this.state.size);
+    if (this.state.list.length == 0 && this.state.page != 1) {
+      await this.loadPage(this.state.page - 1, this.state.size);
+    }
+  }
+
+  loadNextPage = () => {
+    return this.loadPage(this.state.page + 1);
+  };
+
+  async loadPage(page: number, size?: number): Promise<boolean> {
+    if (!this.httpGet) return false;
+    this.state.loading = true;
+
+    if (!size) size = this.state.size;
+    const ret = await this.httpGet(
+      page,
+      size,
+      this.state.query,
+      this.state.fields
+    );
+    this.state.loading = false;
+
+    if (ret.errorNo == 200) {
+      const result = ret.result;
+      this.state.page = page;
+      this.state.size = size;
+
+      let list = [];
+      if (this.listFilter) {
+        list = result.list.map(this.listFilter) || [];
+      } else {
+        list = [...result.list];
+      }
+      if (page == 1 || !this.hasLimit) {
+        this.dataList = [...result.list];
+        this.state.list = list;
+      } else {
+        this.state.list = [...this.state.list, ...list];
+        this.dataList = [...this.dataList, ...result.list];
+      }
+      setTimeout(() => {
+        this.state.total = result.total;
+      }, 100);
+      return true;
+    }
+
+    return false;
+  }
+  async addItem(data: ListItemBase) {
+    if (!this.httpAdd) return { errorNo: 500, errorDesc: "httpAdd 未定义" };
+    this.state.loading = true;
+    const ret = await this.httpAdd(data);
+    this.state.loading = false;
+    if (ret.errorNo == 200) {
+      await this.fresh();
+    }
+    return ret;
+  }
+
+  async deleteItem(id: string) {
+    if (!this.httpDelete) return;
+
+    this.state.loading = true;
+
+    const ret = await this.httpDelete(id);
+    this.state.loading = false;
+
+    if (ret.errorNo == 200) {
+      await this.fresh();
+    }
+    return ret;
+  }
+
+  async saveItem(item: T) {
+    if (!this.httpSave) return;
+    this.state.loading = true;
+    const ret = await this.httpSave(item);
+    this.state.loading = false;
+    if (ret.errorNo == 200) {
+      await this.fresh();
+    }
+    return ret;
+  }
+  async itemDetail(id: string) {
+    if (!this.httpDetail) return;
+    this.state.loading = true;
+    const ret = await this.httpDetail(id);
+    this.state.loading = false;
+    return ret;
+  }
+}

+ 162 - 0
src/modules/admin/components/CategoryModal.tsx

@@ -0,0 +1,162 @@
+import { Button, Col, Form, Input, Row } from "ant-design-vue";
+import { defineComponent, onMounted, reactive, ref } from "vue";
+import { any } from "vue-types";
+import Modal from "@/components/Provider/Modal";
+import { css } from "@linaria/core";
+
+const layout = {
+  wrapperCol: { span: 24 },
+};
+
+export default defineComponent({
+  props: {
+    data: any(),
+  },
+  setup(props) {
+    const modal = Modal.use();
+    const formState: { [name: string]: any } = reactive({
+      formData: {
+        ...{
+          name: "",
+          designer: "",
+          thumbnail: "",
+          compCounts: 0,
+          components: [],
+        },
+        ...props.data,
+      },
+    });
+
+    onMounted(() => {});
+
+    const rules = reactive({
+      name: [
+        { required: true, message: "名称不能为空", trigger: "change" },
+        {
+          min: 2,
+          max: 20,
+          message: "长度为2~20位字符",
+          trigger: "change",
+        },
+      ],
+    });
+
+    const loading = ref(false);
+    const { validate, validateInfos } = Form.useForm(formState.formData, rules);
+
+    function submit() {
+      validate().then(async () => {
+        // loading.value = true;
+        // let res;
+        // formState.formData.compCounts = formState.formData.components.length;
+        // if (isCreate) {
+        //   res = await controls.packList.addItem(formState.formData);
+        // } else {
+        //   res = await controls.packList.saveItem(formState.formData);
+        // }
+        // loading.value = false;
+        // if (res.errorNo != 200) return;
+
+        modal.submit();
+      });
+    }
+
+    return () => {
+      return (
+        <div class={EditStyle}>
+          <div class={"edit_content"}>
+            <div class={"form_content"}>
+              <Form {...layout} class={EditFormStyle} onSubmit={submit}>
+                <Row>
+                  <Col span={22}>
+                    <Row>
+                      <Col>
+                        <Form.Item style={{ marginBottom: 0 }}>
+                          <div class={"thumb"}></div>
+                        </Form.Item>
+                      </Col>
+                      <Col class={"pl-10px"}>
+                        <Form.Item {...validateInfos.name}>
+                          <Input
+                            placeholder={"请输入包装名称"}
+                            v-model={[formState.formData.name, "value"]}
+                            maxlength={30}
+                          />
+                        </Form.Item>
+
+                        <Form.Item {...validateInfos.designer}>
+                          <Input
+                            placeholder={"请输入设计师名字"}
+                            v-model={[formState.formData.designer, "value"]}
+                            maxlength={10}
+                          />
+                        </Form.Item>
+                      </Col>
+                    </Row>
+                  </Col>
+                  <Col span={2}>
+                    <Form.Item
+                      style={{ marginBottom: 0, textAlign: "right" }}
+                      wrapperCol={{ span: 24 }}
+                    >
+                      <Button
+                        type="primary"
+                        htmlType="submit"
+                        loading={loading.value}
+                      >
+                        保存
+                      </Button>
+                    </Form.Item>
+                  </Col>
+                </Row>
+              </Form>
+            </div>
+            <div class={"comp_content mt-20px"}></div>
+          </div>
+        </div>
+      );
+    };
+  },
+});
+const EditStyle = css`
+  .edit_content {
+    display: flex;
+    flex-direction: column;
+    padding: 24px;
+    height: 100%;
+  }
+  .comp_content {
+    flex: 1;
+    height: 0;
+    overflow: hidden;
+
+    .ant-tabs {
+      height: 100%;
+      .ant-tabs-nav {
+        .ant-tabs-nav-wrap {
+          overflow-x: auto;
+        }
+      }
+      .ant-tabs-tab {
+        user-select: none;
+      }
+      .ant-tabs-content {
+        height: 100%;
+        overflow-y: hidden;
+      }
+    }
+  }
+`;
+const CompTabPane = css`
+  height: 100%;
+`;
+const EditFormStyle = css`
+  .thumb {
+    width: 180px;
+    height: 180px;
+  }
+  .updatime {
+    margin-bottom: 24px;
+    font-size: 12px;
+  }
+`;

+ 15 - 0
src/modules/admin/http.ts

@@ -0,0 +1,15 @@
+import { createRequest } from "@/utils/request";
+const token = localStorage.getItem("token");
+export const request = createRequest({
+  baseURL: "https://3dqueen.cloud/adhuaxi/v1",
+  interceptors: {
+    request(req: any) {
+      if (!req.headers) req.headers = {};
+      req.headers["authorization"] = `Bearer ${token}`;
+      return req;
+    },
+    response: (res: any) => {
+     
+    },
+  },
+});

+ 2 - 18
src/modules/admin/index.ts

@@ -1,18 +1,2 @@
-import { ModuleRoot } from "../queenjs";
-
-export class AdminModule extends ModuleRoot {
-  config = this.setConfig({});
-  //   actions = this.createActions([]);
-  https = this.createHttps([]);
-
-  controls = {
-    // usersList: new PageListController(this.https),
-  };
-  async onReady() {
-    console.log("ready");
-  }
-}
-
-const hooks = AdminModule.hook("Admin");
-
-export const { useAdmin, initAdmin, setAdmin } = hooks;
+export * from "./module/category";
+export * from "./module/auth";

+ 11 - 0
src/modules/admin/module/auth/index.ts

@@ -0,0 +1,11 @@
+import { defineStore } from "pinia";
+
+export const useAuth = defineStore("auth", {
+  state: () => ({
+    userInfo: {},
+  }),
+  getters: {},
+  actions: {
+    initAuth() {},
+  },
+});

+ 32 - 0
src/modules/admin/module/category/actions.tsx

@@ -0,0 +1,32 @@
+import Modal from "@/components/Provider/Modal";
+import CategoryModal from "../../components/CategoryModal";
+
+export const categoryActions = {
+  // categoryItem的【添加】
+  async addCategoryItem(pid = "top") {
+    const base: any = await Modal.show(<CategoryModal data={{}} />, {
+      title: "添加分类",
+    });
+    const item = { pid, ...base };
+    // return this.store.addCategory(item);
+  },
+
+  // categoryItem的【重命名】
+  async renameCategoryItem(item: any) {
+    // const name = await queenApi.showInput({
+    //   title: "分类名称",
+    //   defaultValue: item.name,
+    //   placeholder: "请输入分类名称",
+    // });
+    // return this.store.updateCategory({ id: item.id, name });
+  },
+
+  // categoryItem的【删除】
+  async deleteCategoryItem(item: any) {
+    // await queenApi.showConfirm({
+    //   type: "danger",
+    //   content: "确定删除该分类?",
+    // });
+    // return this.store.deleteCategory(item);
+  },
+};

+ 31 - 0
src/modules/admin/module/category/https.ts

@@ -0,0 +1,31 @@
+import { request } from "../http";
+export const https = {
+  createCategory(data: any) {
+    return request("/category/create", {
+      method: "POST",
+      data,
+    });
+  },
+  listCategory(params: any) {
+    return request("/category/list", {
+      method: "GET",
+      params,
+    });
+  },
+  deleteCategory(id: string) {
+    return request(`/category/delete/${id}`, {
+      method: "POST",
+    });
+  },
+  detailCategory(id: string) {
+    return request(`/category/detail/${id}`, {
+      method: "GET",
+    });
+  },
+  updateCategory(data: any) {
+    return request("/category/update", {
+      method: "POST",
+      data,
+    });
+  },
+};

+ 41 - 0
src/modules/admin/module/category/index.ts

@@ -0,0 +1,41 @@
+import { CategoryItem } from "@/typings/asset";
+
+import { defineStore } from "pinia";
+import { categoryActions } from "./actions";
+function setMapItem(
+  id: string,
+  item: any,
+  itemMaps: Map<string, CategoryItem>
+) {
+  itemMaps.set(id, item);
+  if (item.children instanceof Array) {
+    return item.children.forEach((d: any) => {
+      d.pid = item.id;
+      setMapItem(d.id, d, itemMaps);
+    });
+  }
+}
+export const useCategory = defineStore("category", {
+  state: () => ({
+    categories: [],
+  }),
+  getters: {
+    categories(state) {
+      return state.categories;
+    },
+    categoryMap(state) {
+      const itemMaps = new Map<string, CategoryItem>();
+      setMapItem("_", { children: state.categories }, itemMaps);
+      return itemMaps;
+    },
+  },
+  actions: {
+    initCategories() {},
+    addCategoryItem() {
+      categoryActions.addCategoryItem();
+    },
+    renameCategoryItem(item: any) {},
+
+    deleteCategoryItem(item: any) {},
+  },
+});

+ 0 - 27
src/modules/queenjs/adapter/vue/components/loading/index.less

@@ -1,27 +0,0 @@
-.que-loading{
-  position: fixed;
-  z-index: 9999;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-
-  .que-loading-box {
-    position: absolute;
-    top: 50%;
-    left: 50%;
-    transform: translate(-50%, -50%);
-    display: flex;
-    flex-direction: column;
-    justify-content: center;
-    align-items: center;
-    background: rgba(0, 0, 0, 0.4);
-    padding: 20px;
-    border-radius: 6px;
-    color: #fff;
-
-    .ant-spin-dot-item {
-      background-color: #fff;
-    }
-  }
-}

+ 0 - 31
src/modules/queenjs/adapter/vue/components/loading/index.tsx

@@ -1,31 +0,0 @@
-import { Spin } from "ant-design-vue";
-import { defineComponent, reactive } from "vue";
-import "./index.less";
-
-const state = reactive({
-  visible: false,
-  tip: "",
-});
-
-export default {
-  show(tip: string) {
-    state.tip = tip;
-    state.visible = true;
-  },
-  hidden() {
-    state.visible = false;
-    state.tip = "";
-  },
-};
-
-export const LoadingProvider = defineComponent(() => {
-  return () =>
-    state.visible ? (
-      <div class="que-loading">
-        <div class="que-loading-box">
-          <Spin />
-          <div>{state.tip || "加载中"}</div>
-        </div>
-      </div>
-    ) : null;
-});

+ 0 - 42
src/modules/queenjs/adapter/vue/components/modal/ModalConfirm.tsx

@@ -1,42 +0,0 @@
-import { Button } from "ant-design-vue";
-import { defineComponent } from "vue";
-import { any, string } from "vue-types";
-import Modal from ".";
-
-export default defineComponent({
-  props: {
-    type: string().def("default"),
-    content: any().isRequired,
-    okText: string().def("确定"),
-    cancelText: string().def("取消"),
-    refuseText: string(),
-  },
-  setup(props) {
-    const modal = Modal.use();
-
-    return () => (
-      <div class="ant-modal-confirm">
-        <div class="confirm-content">{props.content}</div>
-        <div class="confirm-btns">
-          <Button onClick={() => modal.cancel()}>{props.cancelText}</Button>
-
-          {props.refuseText && (
-            <>
-              <div class="btns-space"></div>
-              <Button onClick={() => modal.submit(false)}>
-                {props.refuseText}
-              </Button>
-            </>
-          )}
-          <Button
-            type="primary"
-            onClick={() => modal.submit(true)}
-            danger={props.type === "danger"}
-          >
-            {props.okText}
-          </Button>
-        </div>
-      </div>
-    );
-  },
-});

+ 0 - 59
src/modules/queenjs/adapter/vue/components/modal/ModalInput.tsx

@@ -1,59 +0,0 @@
-import { Input, Button } from "ant-design-vue";
-import { defineComponent, ref } from "vue";
-import { bool, number, string } from "vue-types";
-import Modal from ".";
-
-export default defineComponent({
-  props: {
-    title: string().def("请填写"),
-    defaultValue: string().def(""),
-    placeholder: string().def(""),
-    maxLength: number(),
-    selection: bool().def(false),
-    okText: string().def("确定"),
-    cancelText: string().def("取消"),
-  },
-  setup(props) {
-    const modal = Modal.use();
-    const firstLoad = ref(true);
-    const inputValue = ref(props.defaultValue);
-    return () => (
-      <div class="ant-modal-input">
-        <Input
-          maxlength={props.maxLength}
-          ref={(input: any) => {
-            if (input) {
-              if (
-                props.selection &&
-                inputValue.value.length > 0 &&
-                firstLoad.value
-              ) {
-                input.setSelectionRange(0, inputValue.value.length);
-              }
-              input.focus();
-            }
-          }}
-          value={inputValue.value as string}
-          placeholder={props.placeholder as string}
-          autofocus={true}
-          onChange={(e: any) => {
-            inputValue.value = e.target.value;
-            firstLoad.value = false;
-          }}
-        />
-        <div class="input-btns">
-          <Button onClick={() => modal.cancel()}>{props.cancelText}</Button>
-          <Button
-            onClick={() => {
-              if (!inputValue.value) return;
-              modal.submit(inputValue.value);
-            }}
-            type="primary"
-          >
-            {props.okText}
-          </Button>
-        </div>
-      </div>
-    );
-  },
-});

+ 0 - 118
src/modules/queenjs/adapter/vue/components/modal/index.less

@@ -1,118 +0,0 @@
-@import "@/styles/theme";
-
-.inf-modal {
-  top: 0;
-  padding-bottom: 0;
-  width: 100vw;
-  height: 100vh;
-  .ant-modal-header {
-    padding: 16px 24px;
-    font-size: 16px;
-    font-weight: 500;
-    background-color: @inf-modal-bg;
-    text-align: left;
-    border-bottom: 1px solid @inf-border-color;
-  }
-  .ant-modal-content {
-    width: 100%;
-    height: 100%;
-    padding: 0;
-    background-color: transparent;
-    box-shadow: none;
-    text-align: center;
-  }
-  .ant-modal-body {
-    position: relative;
-    padding: 0;
-    display: inline-block;
-    margin: 100px 0;
-    text-align: initial;
-    background-color: @inf-modal-bg;
-    border-radius: 4px;
-    .ant-modal-close {
-      position: absolute;
-      top: 0;
-      right: 0;
-      width: 56px;
-      height: 56px;
-      font-size: 16px;
-      line-height: 56px;
-    }
-    > :last-child {
-      padding: 24px;
-    }
-  }
-
-  &.ant-modal-fullscreen {
-    max-width: 100%;
-    margin: 0;
-    .ant-modal-body {
-      display: flex;
-      flex-direction: column;
-      height: 100%;
-      margin: 0;
-      border-radius: 0;
-      > :last-child {
-        flex-grow: 1;
-        padding: 0;
-        height: 0;
-      }
-    }
-  }
-}
-.ant-modal-header {
-  padding: 16px 24px 0;
-  font-size: 16px;
-  font-weight: 500;
-  background-color: @inf-modal-bg;
-  text-align: left;
-  border-bottom: none;
-}
-.ant-modal-close-x {
-  font-size: 14px;
-}
-.ant-modal-input {
-  .input-btns {
-    margin-top: 20px;
-    text-align: right;
-    button + button {
-      margin-left: 12px;
-    }
-  }
-}
-
-.ant-modal-confirm {
-  .confirm-content {
-    padding: 6px 0 20px 0;
-    text-align: center;
-    font-size: 16px;
-  }
-  .confirm-btns {
-    display: flex;
-    justify-content: center;
-    margin-top: 14px;
-    .btns-space {
-      flex: 1;
-    }
-    button + button {
-      margin-left: 12px;
-    }
-  }
-}
-
-.ant-modal-form {
-  margin-top: -6px;
-  .modal-form-header {
-    margin-bottom: 20px;
-    font-size: 16px;
-    font-weight: bold;
-  }
-  .modal-form-content {
-    display: flex;
-    flex-direction: column;
-  }
-  .modal-form-footer {
-    display: flex;
-    justify-content: flex-end;
-  }
-}

+ 0 - 265
src/modules/queenjs/adapter/vue/components/modal/index.tsx

@@ -1,265 +0,0 @@
-import { Modal as AntdModal } from "ant-design-vue";
-import { CloseOutlined } from "@ant-design/icons-vue";
-import {
-  defineComponent,
-  inject,
-  onBeforeUnmount,
-  onMounted,
-  provide,
-  reactive,
-  ref,
-} from "vue";
-import { bool, number } from "vue-types";
-import { queenApi } from "../../../../api";
-import { Exception } from "../../../../core/exception";
-import "./index.less";
-import ModalConfirm from "./ModalConfirm";
-import ModalInput from "./ModalInput";
-
-const store = reactive({
-  modalKeys: [] as Array<{ key: number; visible: boolean }>,
-  modalMaps: new Map() as Map<number, any>,
-});
-
-const MyModal = defineComponent({
-  props: {
-    visible: bool().isRequired,
-    modalKey: number().isRequired,
-  },
-  setup(props) {
-    provide("modalContext", props.modalKey);
-    const closeRef = ref();
-    const {
-      context,
-      children,
-      closable,
-      title,
-      fullscreen,
-      width,
-      ...otherProps
-    } = store.modalMaps.get(props.modalKey);
-    const baseProps: any = {
-      width,
-      closable,
-    };
-    const isSelfWidth = !(width && !fullscreen);
-
-    if (context) {
-      Object.entries(context).forEach(([key, value]) => {
-        provide(key, value);
-      });
-    }
-
-    if (isSelfWidth) {
-      baseProps.closable = false;
-      baseProps.width = "auto";
-      baseProps.class =
-        "inf-modal" + (fullscreen ? " ant-modal-fullscreen" : "");
-      onMounted(() => {
-        const closeEl = closeRef.value;
-        if (closeEl) {
-          const maskEl = closeEl.parentElement.parentElement;
-          // maskEl.addEventListener("click", closeModal, { once: true }); 选择文件过后,会触发事件但被拦截
-          maskEl.addEventListener("click", closeModal);
-        }
-      });
-      onBeforeUnmount(() => {
-        const closeEl = closeRef.value;
-        if (closeEl) {
-          const maskEl = closeEl.parentElement.parentElement;
-          maskEl.removeEventListener("click", closeModal);
-        }
-      });
-    } else {
-      baseProps.title = title;
-    }
-
-    function closeModal(e: MouseEvent) {
-      if (e.target === e.currentTarget) {
-        otherProps.onCancel?.();
-      }
-    }
-
-    const RenderSelfHeader = () => (
-      <>
-        {closable ? (
-          <CloseOutlined
-            class="ant-modal-close"
-            onClick={() => otherProps.onCancel()}
-            ref={closeRef}
-          />
-        ) : null}
-        {title ? <div class="ant-modal-header">{title}</div> : null}
-      </>
-    );
-
-    return () => {
-      return (
-        <AntdModal
-          key={props.modalKey}
-          visible={props.visible}
-          footer={null}
-          {...baseProps}
-          {...otherProps}
-        >
-          {isSelfWidth ? RenderSelfHeader() : null}
-          {children}
-        </AntdModal>
-      );
-    };
-  },
-});
-
-function hidden(key: number) {
-  if (key) {
-    const modal = store.modalKeys.find((item) => item.key === key);
-    modal && (modal.visible = false);
-  }
-}
-
-const Modal = {
-  show(
-    children: JSX.Element,
-    config?: {
-      width?: string;
-      title?: string;
-      afterClose?: VoidFunction;
-      closable?: boolean;
-      fullscreen?: boolean;
-      onOk?: any;
-      onCancel?: any;
-      [name: string]: any;
-    },
-    context?: {
-      [name: string]: any;
-    }
-  ) {
-    return new Promise((resolve, reject) => {
-      const key = Date.now();
-      const { afterClose, ...otherConfig } = config || {};
-      store.modalMaps.set(key, {
-        context,
-        children,
-        closable: true,
-        afterClose: () => {
-          const itemIndex = store.modalKeys.findIndex(
-            (item) => item.key === key
-          );
-          if (itemIndex != -1) {
-            store.modalKeys.splice(itemIndex, 1);
-            store.modalMaps.delete(key);
-          }
-          afterClose?.();
-        },
-        ...otherConfig,
-        onOk: async (value?: any) => {
-          if (otherConfig.onOk) {
-            await otherConfig.onOk(value);
-          }
-          resolve(value);
-          hidden(key);
-        },
-        onCancel: (msg?: string) => {
-          reject(Exception.cancel(msg));
-          hidden(key);
-        },
-      });
-      store.modalKeys.push({ key, visible: true });
-    });
-  },
-  use() {
-    const key = inject("modalContext") as number;
-    const ctx = store.modalMaps.get(key);
-    return {
-      submit: ctx.onOk as (value?: any) => void,
-      cancel: ctx.onCancel as (msg?: any) => void,
-    };
-  },
-  input(params: {
-    title?: string;
-    defaultValue?: string;
-    placeholder?: string;
-    okText?: string;
-    cancelText?: string;
-    selection?: boolean;
-    onValid?: (value: string) => Promise<boolean>;
-    [name: string]: any;
-  }) {
-    const {
-      title,
-      defaultValue,
-      placeholder,
-      maxLength,
-      okText,
-      cancelText,
-      selection,
-      onValid,
-      ...otherParams
-    } = params;
-    return Modal.show(
-      <ModalInput
-        defaultValue={defaultValue}
-        placeholder={placeholder}
-        maxLength={maxLength}
-        selection={selection}
-        okText={okText}
-        cancelText={cancelText}
-      />,
-      {
-        width: "400px",
-        title: title,
-        closable: true,
-        ...otherParams,
-        onOk: async (v: any) => {
-          const isValid = await (onValid ? onValid(v) : true);
-          if (isValid) return v;
-          throw Exception.warn({ msg: "invalid input value", silence: true });
-        },
-      }
-    );
-  },
-
-  confirm(params: {
-    title?: string;
-    content?: any;
-    okText?: string;
-    refuseText?: string;
-    cancelText?: string;
-    type?: "danger";
-    [name: string]: any;
-  }) {
-    const { type, okText, refuseText, cancelText, content, ...otherParams } =
-      params;
-    return Modal.show(
-      <ModalConfirm
-        type={type}
-        content={content}
-        okText={okText}
-        refuseText={refuseText}
-        cancelText={cancelText}
-      />,
-      {
-        width: "400px",
-        ...otherParams,
-      }
-    );
-  },
-  clear() {
-    store.modalKeys = [];
-    store.modalMaps.clear();
-  },
-};
-
-export const ModalProvider = defineComponent(() => {
-  // 路由跳转前销毁当前页面的弹层
-  queenApi.router.beforeEach(() => {
-    Modal.clear();
-  });
-
-  return () =>
-    store.modalKeys.map(({ key, visible }) => (
-      <MyModal key={key} visible={visible} modalKey={key} />
-    ));
-});
-
-export default Modal;

+ 0 - 14
src/modules/queenjs/adapter/vue/components/provider/index.tsx

@@ -1,14 +0,0 @@
-import { ConfigProvider } from "ant-design-vue";
-import { defineComponent } from "vue";
-import { LoadingProvider } from "../loading";
-import { ModalProvider } from "../modal";
-
-export const Provider = defineComponent((props, { slots }) => {
-  return () => (
-    <ConfigProvider>
-      {slots.default?.()}
-      <ModalProvider />
-      <LoadingProvider />
-    </ConfigProvider>
-  );
-});

+ 0 - 3
src/modules/queenjs/adapter/vue/index.ts

@@ -1,3 +0,0 @@
-import "./register/feedback";
-
-export { Provider } from "./components/provider";

+ 0 - 38
src/modules/queenjs/adapter/vue/register/feedback.ts

@@ -1,38 +0,0 @@
-import { message } from "ant-design-vue";
-import { queenBus } from "../../../api/bus";
-import Loading from "../components/loading";
-import Modal from "../components/modal";
-
-queenBus.method("ui:showLoading", function (tip: string) {
-  Loading.show(tip);
-});
-queenBus.method("ui:hideLoading", function () {
-  Loading.hidden();
-});
-queenBus.method("ui:dialog:input", function (params: any) {
-  return Modal.input(params);
-});
-queenBus.method("ui:dialog:confirm", function (params: any) {
-  return Modal.confirm(params);
-});
-queenBus.method("ui:message:warn", function (msg: string) {
-  message.warn(msg);
-});
-queenBus.method("ui:message:error", function (msg: string) {
-  message.error(msg);
-});
-queenBus.method("ui:message:info", function (msg: string) {
-  message.info(msg);
-});
-queenBus.method("ui:message:success", function (msg: string) {
-  message.success(msg);
-});
-queenBus.method(
-  "ui:dialog:custom",
-  function (component: any, params?: any, context?: any) {
-    return Modal.show(component, params, context);
-  }
-);
-queenBus.method("ui:dialog:use", function () {
-  return Modal.use();
-});

+ 0 - 3
src/modules/queenjs/api/bus.ts

@@ -1,3 +0,0 @@
-import { Bus } from "../core/comm/bus";
-
-export const queenBus = new Bus();

+ 0 - 84
src/modules/queenjs/api/feedback.ts

@@ -1,84 +0,0 @@
-import { queenBus } from "./bus";
-import Modal from "../adapter/vue/components/modal";
-
-export function showLoading(tip: string) {
-  queenBus.call("ui:showLoading", tip);
-}
-
-export function hideLoading() {
-  queenBus.call("ui:hideLoading");
-}
-
-export function messageSuccess(msg: string) {
-  queenBus.call("ui:message:success", msg);
-}
-
-export function messageInfo(msg: string) {
-  queenBus.call("ui:message:info", msg);
-}
-
-export function messageWarn(msg: string) {
-  queenBus.call("ui:message:warn", msg);
-  return msg;
-}
-
-export function messageError(msg: string) {
-  queenBus.call("ui:message:error", msg);
-  return msg;
-}
-
-export function showInput(params: {
-  width?: string;
-  centered?: boolean;
-  defaultValue?: string;
-  placeholder?: string;
-  title?: string;
-  selection?: boolean;
-  onValid?: (value: string) => Promise<boolean>;
-  maxLength?: number;
-  okText?: string;
-  cancelText?: string;
-}) {
-  return queenBus.call("ui:dialog:input", params) as Promise<string>;
-}
-
-export function showConfirm(params: {
-  width?: string;
-  centered?: boolean;
-  type?: "default" | "danger";
-  title?: string;
-  content: string;
-  okText?: string;
-  refuseText?: string;
-  cancelText?: string;
-}) {
-  return queenBus.call("ui:dialog:confirm", params) as Promise<boolean>;
-}
-
-export function dialog<T>(
-  component: any,
-  params?: {
-    width?: string;
-    title?: string;
-    afterClose?: VoidFunction;
-    closable?: boolean;
-    fullscreen?: boolean;
-    onOk?: any;
-    onCancel?: any;
-    [name: string]: any;
-  },
-  context?: {
-    [name: string]: any;
-  }
-) {
-  return queenBus.call(
-    "ui:dialog:custom",
-    component,
-    params,
-    context
-  ) as Promise<T>;
-}
-
-export function useDialog() {
-  return queenBus.call("ui:dialog:use") as ReturnType<typeof Modal.use>;
-}

+ 0 - 29
src/modules/queenjs/api/file.ts

@@ -1,29 +0,0 @@
-import { Exception } from "../core/exception";
-
-export function selectFile(opts?: {
-  accept?: string;
-  multiple?: boolean;
-}): Promise<File[]> {
-  return new Promise((resolve, reject) => {
-    const fileInput = document.createElement("input");
-    fileInput.type = "file";
-    fileInput.accept = opts?.accept || "images/*";
-    fileInput.multiple = opts?.multiple || false;
-
-    fileInput.onchange = function (this: any) {
-      resolve([...this.files]);
-    };
-
-    window.addEventListener(
-      "focus",
-      () => {
-        setTimeout(() => {
-          reject(Exception.cancel("select file cancel"));
-        }, 300);
-      },
-      { once: true }
-    );
-
-    fileInput.click();
-  });
-}

+ 0 - 13
src/modules/queenjs/api/index.ts

@@ -1,13 +0,0 @@
-import { Router } from "vue-router";
-import * as feedbackApis from "./feedback";
-import * as urlApis from "./url";
-import * as fileApis from "./file";
-
-export const queenApi = {
-  router: {} as Router,
-  ...feedbackApis,
-  ...urlApis,
-  ...fileApis,
-};
-
-export const useModal = feedbackApis.useDialog;

+ 0 - 38
src/modules/queenjs/api/url.ts

@@ -1,38 +0,0 @@
-const createObjectURL = URL.createObjectURL;
-const revokeObjectURL = URL.revokeObjectURL;
-
-URL.createObjectURL = function (obj: Blob | MediaSource): string {
-  const url = createObjectURL(obj);
-  blobURLMaps.set(url, obj);
-  return url;
-};
-URL.revokeObjectURL = function (url: string) {
-  revokeObjectURL(url);
-  blobURLMaps.delete(url);
-};
-
-export const blobURLMaps = new Map<string, any>();
-
-export function getBlobURLName(url: string) {
-  return blobURLMaps.get(url)?.name;
-}
-
-export function getBlobURLExt(url: string) {
-  const blob = blobURLMaps.get(url);
-  let ext = "unkown";
-  if (blob) {
-    const exp = /^.+\.(.+)$/;
-    if (blob.name && exp.test(blob.name)) {
-      ext = (exp.exec(blob.name) as any)[1];
-    } else if (blob.type) {
-      ext = blob.type.split("/").pop();
-    }
-    return ext.toLowerCase();
-  } else {
-    return ext;
-  }
-}
-
-export function isBlobURL(url: string) {
-  return /^blob:/.test(url);
-}

+ 0 - 35
src/modules/queenjs/core/comm/bus.ts

@@ -1,35 +0,0 @@
-import { AnyFun } from "../../typing";
-
-export class Bus {
-  _hooks: any = {};
-  method(name: string, fn: AnyFun) {
-    if (this._hooks[name] !== undefined) {
-      throw new Error("can't override hook: " + name);
-    }
-    this._hooks[name] = fn;
-  }
-
-  methodRemove(name: string) {
-    delete this._hooks[name];
-  }
-
-  call(name: string, ...args: any[]) {
-    if (this._hooks[name]) {
-      // var args = Array.prototype.slice.call(arguments, 1);
-      try {
-        return this._hooks[name].apply(null, args);
-      } catch (ex) {
-        console.info(
-          "%c%s %c(editor.method error)",
-          "color: #06f",
-          name,
-          "color: #f00"
-        );
-        console.error(ex);
-      }
-    } else {
-      // console.info('%c%s %c - editor.method does not exist yet', 'color: #06f', name, 'color: #f00');
-    }
-    return null;
-  }
-}

+ 0 - 141
src/modules/queenjs/core/comm/event.ts

@@ -1,141 +0,0 @@
-/* eslint-disable */
-
-class EventHandle {
-  owner: any;
-  name: string | null;
-  fn: Function | null;
-
-  constructor(owner: any, name: string, fn: Function) {
-    this.owner = owner;
-    this.name = name;
-    this.fn = fn;
-  }
-
-  unbind() {
-    if (!this.owner) return;
-    this.owner.unbind(this.name, this.fn);
-
-    this.owner = null;
-    this.name = null;
-    this.fn = null;
-  }
-
-  call() {
-    if (!this.fn) return;
-
-    this.fn.call(
-      this.owner,
-      arguments[0],
-      arguments[1],
-      arguments[2],
-      arguments[3],
-      arguments[4],
-      arguments[5],
-      arguments[6],
-      arguments[7]
-    );
-  }
-
-  on(name: string, fn: Function) {
-    return this.owner.on(name, fn);
-  }
-}
-
-class Events {
-  _events: { [name: string]: any };
-  _suspendEvents: boolean;
-
-  constructor() {
-    this._events = {};
-    this._suspendEvents = false;
-  }
-
-  get suspendEvents() {
-    return this._suspendEvents;
-  }
-  set suspendEvents(value) {
-    this._suspendEvents = !!value;
-  }
-
-  nextTick(name: string, fn: Function) {
-    this.on(
-      name,
-      (function () {
-        let timer: any = null;
-        return function (...args: any[]) {
-          if (timer) clearTimeout(timer);
-          timer = setTimeout(fn.bind(null, ...args));
-        };
-      })()
-    );
-  }
-
-  on(name: any, fn: Function): EventHandle {
-    const events = this._events[name];
-    if (events === undefined) {
-      this._events[name] = [fn];
-    } else {
-      if (events.indexOf(fn) == -1) events.push(fn);
-    }
-    return new EventHandle(this, name, fn);
-  }
-
-  once(name: any, fn: Function) {
-    const self = this;
-    const evt = this.on(name, function (...args: any[]) {
-      fn.call(self, ...args);
-      evt.unbind();
-    });
-    return evt;
-  }
-
-  emit(name: any, ...args: any[]): void {
-    if (this._suspendEvents) return;
-
-    let events = this._events[name];
-    if (!events) return;
-
-    events = events.slice(0);
-
-    for (let i = 0; i < events.length; i++) {
-      if (!events[i]) continue;
-
-      try {
-        events[i].call(this, ...args);
-      } catch (ex) {
-        console.info(
-          '%c%s %c(event error)',
-          'color: #06f',
-          name,
-          'color: #f00'
-        );
-        console.error(ex);
-      }
-    }
-  }
-
-  unbind(name?: string, fn?: Function) {
-    if (name) {
-      const events = this._events[name];
-      if (!events) return this;
-
-      if (fn) {
-        const i = events.indexOf(fn);
-        if (i !== -1) {
-          if (events.length === 1) {
-            delete this._events[name];
-          } else {
-            events.splice(i, 1);
-          }
-        }
-      } else {
-        delete this._events[name];
-      }
-    } else {
-      this._events = {};
-    }
-    return this;
-  }
-}
-
-export { EventHandle, Events };

+ 0 - 13
src/modules/queenjs/core/defineUI/DefaultUI.tsx

@@ -1,13 +0,0 @@
-import { defineUI } from "queenjs/core/defineUI";
-
-const NullDefineUI = defineUI({
-  setup() {
-    return () => null;
-  },
-});
-
-const Null: typeof NullDefineUI = (() => null) as any;
-
-export const DefaultUI = {
-  Null
-}

+ 0 - 51
src/modules/queenjs/core/defineUI/index.tsx

@@ -1,51 +0,0 @@
-import { defineComponent } from "vue";
-import { DefineUI } from "./typings";
-
-export const defineUI: DefineUI = function (options: any) {
-  delete options.slotOptions;
-  const { slots = {}, ...componentOptions } = options;
-  const UI = defineComponent(componentOptions);
-  const originComp = function (this: any, props: any) {
-    const { slots, ...uiProps } = props;
-    return <UI {...uiProps}>{buildSlots(this, slots)}</UI>;
-  };
-  const Component: any = originComp.bind(() => Component);
-  Object.setPrototypeOf(Component, originComp);
-
-  Object.keys(slots).forEach((key) => {
-    Component[key] = slots[key];
-  });
-
-  Component.slots = function (config: any) {
-    return config;
-  };
-
-  return Component;
-};
-
-function buildSlots(getComp: any, customSlots: any = {}) {
-  const Component = getComp();
-  const slotKeys = Object.keys(Component);
-  slotKeys.forEach((key: string) => {
-    customSlots[key] = buildSlot(customSlots, key, Component[key]);
-  });
-  return customSlots;
-}
-
-function buildSlot(conf: any, slotName: string, SlotUI: any) {
-  const originSlot = conf[slotName];
-  if (!originSlot) {
-    return (props: any) => <SlotUI {...props} />;
-  } else {
-    return (props: any = {}, option: any = {}) => {
-      const slotImpl = originSlot(props, option);
-      if (!slotImpl) {
-        return;
-      }
-      if (slotImpl != props) {
-        return slotImpl;
-      }
-      return <SlotUI {...slotImpl} />;
-    };
-  }
-}

+ 0 - 433
src/modules/queenjs/core/defineUI/typings.ts

@@ -1,433 +0,0 @@
-import { LooseRequired, UnionToIntersection } from "@vue/shared";
-import {
-  Component,
-  ComponentCustomOptions,
-  ComponentInjectOptions,
-  ComponentObjectPropsOptions,
-  ComponentOptionsMixin,
-  ComponentPropsOptions,
-  ComputedOptions,
-  CreateComponentPublicInstance,
-  DefineComponent,
-  Directive,
-  EmitsOptions,
-  ExtractDefaultPropTypes,
-  ExtractPropTypes,
-  MethodOptions,
-  ObjectEmitsOptions,
-  Prop,
-  RenderFunction,
-  RuntimeCompilerOptions,
-} from "vue";
-
-type RequiredKeys<T> = {
-  [K in keyof T]: T[K] extends
-    | {
-        required: true;
-      }
-    | BooleanConstructor
-    | {
-        type: BooleanConstructor;
-      }
-    ? K
-    : never;
-}[keyof T];
-
-type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N;
-
-type InferPropType<T> = [T] extends [null]
-  ? any
-  : [T] extends [
-      {
-        type: null | true;
-      }
-    ]
-  ? any
-  : [T] extends [
-      | ObjectConstructor
-      | {
-          type: ObjectConstructor;
-        }
-    ]
-  ? Record<string, any>
-  : [T] extends [
-      | BooleanConstructor
-      | {
-          type: BooleanConstructor;
-        }
-    ]
-  ? boolean
-  : [T] extends [
-      | DateConstructor
-      | {
-          type: DateConstructor;
-        }
-    ]
-  ? Date
-  : [T] extends [
-      | (infer U)[]
-      | {
-          type: (infer U)[];
-        }
-    ]
-  ? U extends DateConstructor
-    ? Date | InferPropType<U>
-    : InferPropType<U>
-  : [T] extends [Prop<infer V, infer D>]
-  ? unknown extends V
-    ? IfAny<V, V, D>
-    : V
-  : T;
-
-type SlotsRender<T extends { [name: string]: any }> = {
-  [name in keyof T]: (
-    props?: {
-      [k in keyof Omit<Parameters<T[name]["SlotFn"]>[0], "slots">]: Parameters<
-        T[name]["SlotFn"]
-      >[0][k];
-    },
-    options?: Parameters<T[name]["SlotFn"]>[1]
-  ) => any;
-} & {
-  default?: (...args: any[]) => any;
-};
-
-type ParseSlotEmits<T> = T extends (infer P extends string)[]
-  ? { [name in `on${Capitalize<P>}`]?: (...args: any[]) => any }
-  : {};
-
-type DefineProps<P> = {
-  [name in keyof Omit<P, RequiredKeys<P>>]?: InferPropType<P[name]>;
-} & {
-  [name in keyof Pick<P, RequiredKeys<P>>]: InferPropType<P[name]>;
-};
-
-type ComponentProps<P, S> = DefineProps<P> & {
-  slots?: Parameters<SlotsFn<S>>[0];
-};
-
-type SlotFn<P, E, SlotOptions, Slots> = (
-  props: DefineProps<P> &
-    ParseSlotEmits<E> & {
-      key?: string | number;
-      class?: string | string[] | { [name: string]: boolean };
-      style?: string | { [name: string]: string | number };
-      slots?: Parameters<SlotsFn<Slots>>[0];
-    },
-  options: DefineProps<SlotOptions>
-) => any;
-
-export type SlotsFn<S> = (
-  config: {
-    [name in keyof S]?: S[name] extends { [name: string]: any }
-      ? S[name]["SlotFn"]
-      : never;
-  } & {
-    default?: (...args: any[]) => any;
-  }
-) => any;
-
-export interface DefineUI {
-  <
-    Slots extends { [name: string]: any },
-    SlotOptions extends { [name: string]: any },
-    Props = {},
-    RawBindings = {},
-    D = {},
-    C extends ComputedOptions = {},
-    M extends MethodOptions = {},
-    Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
-    Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
-    E extends EmitsOptions = {},
-    EE extends string = string,
-    I extends ComponentInjectOptions = {},
-    II extends string = string
-  >(
-    options: ComponentOptionsWithoutProps<
-      Slots,
-      SlotOptions,
-      Props,
-      RawBindings,
-      D,
-      C,
-      M,
-      Mixin,
-      Extends,
-      E,
-      EE,
-      I,
-      II
-    >
-  ): DefineComponent<
-    ComponentProps<Props, Slots>,
-    RawBindings,
-    D,
-    C,
-    M,
-    Mixin,
-    Extends,
-    E,
-    EE
-  > & {
-    readonly [name in keyof Slots]: Slots[name];
-  } & {
-    readonly SlotFn: SlotFn<Props, E, SlotOptions, Slots>;
-    readonly slots: SlotsFn<Slots>;
-  };
-  <
-    Slots extends { [name: string]: any },
-    SlotOptions extends { [name: string]: any },
-    PropsOptions extends Readonly<ComponentPropsOptions>,
-    RawBindings,
-    D,
-    C extends ComputedOptions = {},
-    M extends MethodOptions = {},
-    Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
-    Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
-    E extends EmitsOptions = {},
-    EE extends string = string,
-    I extends ComponentInjectOptions = {},
-    II extends string = string
-  >(
-    options: ComponentOptionsWithObjectProps<
-      Slots,
-      SlotOptions,
-      PropsOptions,
-      RawBindings,
-      D,
-      C,
-      M,
-      Mixin,
-      Extends,
-      E,
-      EE,
-      I,
-      II
-    >
-  ): DefineComponent<
-    ComponentProps<PropsOptions, Slots>,
-    RawBindings,
-    D,
-    C,
-    M,
-    Mixin,
-    Extends,
-    E,
-    EE
-  > & {
-    readonly [name in keyof Slots]: Slots[name];
-  } & {
-    readonly SlotFn: SlotFn<PropsOptions, E, SlotOptions, Slots>;
-    readonly slots: SlotsFn<Slots>;
-  };
-}
-
-type ComponentOptionsWithoutProps<
-  Slots extends { [name: string]: any },
-  SlotOptions,
-  Props = {},
-  RawBindings = {},
-  D = {},
-  C extends ComputedOptions = {},
-  M extends MethodOptions = {},
-  Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
-  Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
-  E extends EmitsOptions = EmitsOptions,
-  EE extends string = string,
-  I extends ComponentInjectOptions = {},
-  II extends string = string,
-  PE = Props
-> = ComponentOptionsBase<
-  Slots,
-  SlotOptions,
-  PE,
-  RawBindings,
-  D,
-  C,
-  M,
-  Mixin,
-  Extends,
-  E,
-  EE,
-  {},
-  I,
-  II
-> & {
-  props?: undefined;
-} & ThisType<
-    CreateComponentPublicInstance<
-      PE,
-      RawBindings,
-      D,
-      C,
-      M,
-      Mixin,
-      Extends,
-      E,
-      PE,
-      {},
-      false,
-      I
-    >
-  >;
-
-type ComponentOptionsWithObjectProps<
-  Slots extends { [name: string]: any },
-  SlotOptions,
-  PropsOptions = ComponentObjectPropsOptions,
-  RawBindings = {},
-  D = {},
-  C extends ComputedOptions = {},
-  M extends MethodOptions = {},
-  Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
-  Extends extends ComponentOptionsMixin = ComponentOptionsMixin,
-  E extends EmitsOptions = EmitsOptions,
-  EE extends string = string,
-  I extends ComponentInjectOptions = {},
-  II extends string = string,
-  Props = Readonly<ExtractPropTypes<PropsOptions>>, // & EmitsToProps<E>,
-  Defaults = ExtractDefaultPropTypes<PropsOptions>
-> = ComponentOptionsBase<
-  Slots,
-  SlotOptions,
-  Props,
-  RawBindings,
-  D,
-  C,
-  M,
-  Mixin,
-  Extends,
-  E,
-  EE,
-  Defaults,
-  I,
-  II
-> & {
-  props: PropsOptions & ThisType<void>;
-} & ThisType<
-    CreateComponentPublicInstance<
-      Props,
-      RawBindings,
-      D,
-      C,
-      M,
-      Mixin,
-      Extends,
-      E,
-      Props,
-      Defaults,
-      false,
-      I
-    >
-  >;
-
-interface ComponentOptionsBase<
-  Slots extends { [name: string]: any },
-  SlotOptions,
-  Props,
-  RawBindings,
-  D,
-  C extends ComputedOptions,
-  M extends MethodOptions,
-  Mixin extends ComponentOptionsMixin,
-  Extends extends ComponentOptionsMixin,
-  E extends EmitsOptions,
-  EE extends string = string,
-  Defaults = {},
-  I extends ComponentInjectOptions = {},
-  II extends string = string
-> extends ComponentInternalOptions,
-    ComponentCustomOptions {
-  setup?: (
-    this: void,
-    props: Readonly<
-      LooseRequired<
-        Props &
-          UnionToIntersection<ExtractOptionProp<Mixin>> &
-          UnionToIntersection<ExtractOptionProp<Extends>>
-      >
-    >,
-    ctx: SetupContext<E, Slots>
-  ) => Promise<RawBindings> | RawBindings | RenderFunction | void;
-  name?: string;
-  template?: string | object;
-  slots?: Slots;
-  slotOptions?: SlotOptions;
-  render?: Function;
-  components?: Record<string, Component>;
-  directives?: Record<string, Directive>;
-  inheritAttrs?: boolean;
-  emits?: (E | EE[]) & ThisType<void>;
-  expose?: string[];
-  serverPrefetch?(): Promise<any>;
-  compilerOptions?: RuntimeCompilerOptions;
-  /* Excluded from this release type: ssrRender */
-  /* Excluded from this release type: __ssrInlineRender */
-  /* Excluded from this release type: __asyncLoader */
-  /* Excluded from this release type: __asyncResolved */
-  call?: (this: unknown, ...args: unknown[]) => never;
-  __isFragment?: never;
-  __isTeleport?: never;
-  __isSuspense?: never;
-  __defaults?: Defaults;
-}
-
-interface ComponentInternalOptions {
-  /* Excluded from this release type: __scopeId */
-  /* Excluded from this release type: __cssModules */
-  /* Excluded from this release type: __hmrId */
-  /**
-   * Compat build only, for bailing out of certain compatibility behavior
-   */
-  __isBuiltIn?: boolean;
-  /**
-   * This one should be exposed so that devtools can make use of it
-   */
-  __file?: string;
-  /**
-   * name inferred from filename
-   */
-  __name?: string;
-}
-
-type ExtractOptionProp<T> = T extends ComponentOptionsBase<
-  any,
-  any,
-  infer P, // Props
-  any, // RawBindings
-  any, // D
-  any, // C
-  any, // M
-  any, // Mixin
-  any, // Extends
-  any
->
-  ? unknown extends P
-    ? {}
-    : P
-  : {};
-
-interface SetupContext<
-  E = EmitsOptions,
-  S extends { [name: string]: (...args: any[]) => any } = {}
-> {
-  attrs: Record<string, unknown>;
-  slots: SlotsRender<S>;
-  emit: EmitFn<E>;
-  expose: (exposed?: Record<string, any>) => void;
-}
-
-type EmitFn<
-  Options = ObjectEmitsOptions,
-  Event extends keyof Options = keyof Options
-> = Options extends Array<infer V>
-  ? (event: V, ...args: any[]) => void
-  : {} extends Options
-  ? (event: string, ...args: any[]) => void
-  : UnionToIntersection<
-      {
-        [key in Event]: Options[key] extends (...args: infer Args) => any
-          ? (event: key, ...args: Args) => void
-          : (event: key, ...args: any[]) => void;
-      }[Event]
-    >;

+ 0 - 123
src/modules/queenjs/core/dict/index.ts

@@ -1,123 +0,0 @@
-import { AnyFun } from "../../typing";
-
-type MapItemRequire<T> = T extends {
-  [name in keyof T]: infer P;
-}
-  ? P
-  : never;
-
-type MapItemPartial<T> = ((x: {
-  [name in keyof T]: T[name];
-}) => void) extends (x: { [name in keyof T]: infer P }) => void
-  ? Partial<P>
-  : never;
-
-type DictMapItem<T> = MapItemRequire<T> & MapItemPartial<T>;
-
-type DictArrItem<T> = T extends Array<infer P> ? P : never;
-
-export function createDictMap<
-  T extends { [name: string]: any },
-  Methods extends {
-    [name: string]: AnyFun;
-  }
->(data: T, methods?: Methods & ThisType<DictMapItem<T>>) {
-  const dictMap = new DictMap<keyof T, DictMapItem<T>, Methods>();
-
-  Object.entries(data).forEach(([key, item]) => {
-    methods && Object.setPrototypeOf(item, methods);
-    dictMap.set(key as any, item);
-  });
-
-  return dictMap;
-}
-
-export function createDictArr<
-  T extends any[],
-  Methods extends {
-    [name: string]: AnyFun;
-  }
->(data: T, methods?: Methods & ThisType<DictArrItem<T>>) {
-  let dictArr = new DictArr<DictArrItem<T>, Methods>();
-  if (methods) {
-    dictArr = new Proxy(dictArr, {
-      set: (target, key, value, receiver) => {
-        Object.setPrototypeOf(value, methods);
-        return Reflect.set(target, key, value, receiver);
-      },
-    });
-  }
-
-  data.forEach((item) => {
-    dictArr.push(item);
-  });
-  return dictArr;
-}
-
-export function createDictStorage<T extends { [name: string]: any }>(
-  data: T,
-  type: "localStorage" | "sessionStorage"
-) {
-  const storage = type === "localStorage" ? localStorage : sessionStorage;
-  Object.entries(data || {}).map(([key, value]) => {
-    if (!storage.getItem(key)) {
-      storage.setItem(key, JSON.stringify(value));
-    }
-  });
-  return {
-    get<K extends keyof T>(key: K): T[K] {
-      try {
-        return JSON.parse(storage.getItem(key as string) as any);
-      } catch (error) {
-        console.error(
-          `调用JSON.parse(${type}.getItem("${key as string}"))失败`
-        );
-        return data[key];
-      }
-    },
-    set<K extends keyof T>(key: K, value: T[K]) {
-      storage.setItem(key as string, JSON.stringify(value));
-    },
-  };
-}
-
-class DictMap<K extends string | number | symbol, V, M> extends Map<K, V & M> {
-  arrayWith(keys: Array<K>) {
-    const list = new DictArr<V, M>();
-    keys.forEach((key) => {
-      const item = this.get(key);
-      item && list.push(item);
-    });
-    return list;
-  }
-  find<T extends (value: V & M) => boolean>(cb: T) {
-    return [...this.values()].find(cb);
-  }
-}
-
-class DictArr<V, M> extends Array<V & M> {
-  filterWith<T extends keyof V>(
-    key: T,
-    values: V[T][],
-    sort: "sort:value" | "sort:dict" = "sort:value"
-  ) {
-    const filterList = this.filter((item) => {
-      return values.includes(item[key]);
-    }) as DictArr<V, M>;
-    if (sort === "sort:value") {
-      const sortBy = values.join(",") + ",";
-      return filterList.sort((a: any, b: any) => {
-        return sortBy.indexOf(a[key] + ",") - sortBy.indexOf(b[key] + ",");
-      });
-    } else {
-      return filterList;
-    }
-  }
-  delete<T extends (value: V) => boolean>(cb: T) {
-    for (let i = this.length - 1; i >= 0; i--) {
-      if (cb(this[i])) {
-        this.splice(i, 1);
-      }
-    }
-  }
-}

+ 0 - 164
src/modules/queenjs/core/effect/index.ts

@@ -1,164 +0,0 @@
-import { clone } from "lodash";
-import { watch, WatchStopHandle } from "vue";
-
-type EffectTypes = "array" | "object" | "value";
-type EffectItem<T> = T extends Array<infer R> ? R : T;
-
-export class Effect<
-  T,
-  Item extends EffectItem<T>,
-  ItemObserver extends (item: Item) => any,
-  ItemHandler extends (item: Item, oldVal: any) => void
-> {
-  static array<T>(ob: () => T) {
-    return new Effect("array", ob);
-  }
-  static object<T>(ob: () => T) {
-    return new Effect("object", ob);
-  }
-  static value<T>(ob: () => T) {
-    return new Effect("value", ob);
-  }
-
-  pauseStatus = false;
-  watchs: [
-    ItemObserver,
-    ItemHandler,
-    Map<T, WatchStopHandle> | WatchStopHandle | null
-  ][] = [];
-
-  listHandlers: {
-    add?: ItemHandler;
-    remove?: ItemHandler;
-    stop?: VoidFunction;
-  } = {};
-  constructor(public type: EffectTypes, private observer: () => T) {}
-  list(handlers: Omit<this["listHandlers"], "stop">) {
-    if (!(this.observer() instanceof Array)) {
-      console.error("observer不是数组类型");
-    }
-    if (handlers) this.listHandlers = handlers;
-    return this;
-  }
-  item(itemObserver: ItemObserver, handler: ItemHandler) {
-    this.watchs.push([itemObserver, handler, null]);
-    return this;
-  }
-  run() {
-    this.stop();
-    this.pauseStatus = false;
-    if (this.type === "array") {
-      // @ts-ignore
-      if (!this.watchs.length) this.watchs.push([() => null, () => null, null]);
-      this.listHandlers.stop = watchList.call(
-        this,
-        this.observer,
-        this.listHandlers,
-        this.watchs
-      );
-    } else {
-      watchObject.call(this, this.observer, this.watchs);
-    }
-    return this;
-  }
-  stop() {
-    for (const [, , watchStop] of this.watchs) {
-      if (watchStop instanceof Function) {
-        watchStop();
-      } else if (watchStop instanceof Map) {
-        for (const stop of watchStop.values()) {
-          stop();
-        }
-      }
-    }
-    this.listHandlers.stop?.();
-    return this;
-  }
-  pause() {
-    this.pauseStatus = true;
-  }
-  async play() {
-    this.pauseStatus = await Promise.resolve(false);
-  }
-}
-
-// 通过比对新旧observerItem的属性值是否均相等,相等则返回oldItem, 否则返回currItem
-const getItemByCompare = function (currItem: any, oldItem: any) {
-  if (!(currItem instanceof Array))
-    return currItem === oldItem ? oldItem : currItem;
-  if (currItem.length !== oldItem?.length) return currItem;
-  for (let i = 0; i < currItem.length; i++) {
-    if (currItem[i] !== oldItem?.[i]) return currItem;
-  }
-  return oldItem;
-};
-
-function watchList(this: any, list: any, listHandlers: any, watchs: any[]) {
-  // list每一项item对象改变
-  const listObserver = [() => [...(list() || [])]];
-  // 初始化每个item的缓存Map
-  watchs.forEach((w) => (w[2] = new Map()));
-
-  watchItemHandler.call(this);
-  return watch(listObserver, () => {
-    if (this.pauseStatus) return;
-    const updateMap: Map<any, any> = clone(watchs[0][2]);
-    watchItemHandler.call(this, updateMap);
-    for (const [item, stop] of updateMap.entries()) {
-      if (stop) {
-        watchs.forEach(([, , itemMap]) => {
-          itemMap.get(item)?.();
-          itemMap.delete(item);
-        });
-      }
-      listHandlers[stop ? "remove" : "add"]?.(item);
-    }
-  });
-
-  function watchItemHandler(this: any, updateMap?: Map<any, any>) {
-    list().forEach((item: any) => {
-      watchs.forEach(([observer, handler, itemMap], i) => {
-        if (i === 0 && updateMap) {
-          if (!itemMap.has(item)) {
-            updateMap.set(item, null);
-          } else {
-            updateMap.delete(item);
-          }
-        }
-        if (!itemMap.has(item)) {
-          let oldItem: any;
-          itemMap.set(
-            item,
-            watch(
-              () => (oldItem = getItemByCompare(observer(item), oldItem)),
-              () => {
-                if (this.pauseStatus) return;
-                handler(item, oldItem);
-              }
-            )
-          );
-        }
-      });
-    });
-  }
-}
-
-function watchObject(this: any, observer: any, watchs: any[]) {
-  const handler = (item: any) => {
-    if (this.pauseStatus) return;
-    watchs.forEach((watchItem) => {
-      const [itemObserver, itemHandler] = watchItem;
-      let oldItem: any;
-      watchItem[2]?.();
-      watchItem[2] = watch(
-        () => (oldItem = getItemByCompare(itemObserver(item), oldItem)),
-        () => {
-          if (this.pauseStatus) return;
-          itemHandler(observer(), oldItem);
-        }
-      );
-    });
-  };
-  handler(observer());
-  watch(observer, handler);
-}

+ 0 - 59
src/modules/queenjs/core/exception/index.ts

@@ -1,59 +0,0 @@
-import { queenApi } from "../../api";
-
-// 异常流程类型
-const Exception_Types = {
-  Cancel: {
-    label: "取消",
-    silence: true,
-  },
-  Warn: {
-    label: "警告",
-    silence: false,
-  },
-  Error: {
-    label: "错误",
-    silence: false,
-  },
-};
-
-type ThrowOptions = ConstructorParameters<typeof Exception>[1];
-
-export class Exception {
-  static cancel(options?: ThrowOptions) {
-    return new Exception("Cancel", options);
-  }
-  static warn(options?: ThrowOptions) {
-    return new Exception("Warn", options);
-  }
-  static error(options?: ThrowOptions) {
-    return new Exception("Error", options);
-  }
-
-  msg: string;
-  silence: boolean;
-  result?: any;
-
-  constructor(
-    public type: keyof typeof Exception_Types,
-    options?: string | { msg?: string; silence?: boolean, result?: any }
-  ) {
-    this.msg = Exception_Types[type].label;
-    this.silence = Exception_Types[type].silence;
-    if (options) {
-      Object.assign(
-        this,
-        typeof options === "string" ? { msg: options } : options
-      );
-    }
-    if (this.silence) return;
-    switch (this.type) {
-      case "Cancel":
-      case "Warn":
-        queenApi.messageWarn(this.msg);
-        break;
-      case "Error":
-        queenApi.messageError(this.msg);
-        break;
-    }
-  }
-}

+ 0 - 82
src/modules/queenjs/core/http/index.ts

@@ -1,82 +0,0 @@
-import axios, { AxiosRequestConfig } from "axios";
-import { defaultsDeep } from "lodash";
-import { Exception } from "../exception";
-
-export type RequestConfig = AxiosRequestConfig & {
-  interceptors?: { [name: string]: ReturnType<typeof Http["interceptor"]> };
-  originBody?: boolean;
-  prefix?: string;
-  silence?: boolean;
-};
-
-function createRequest(defReqConfig: RequestConfig) {
-  const { interceptors, ...httpConfig } = defReqConfig;
-  const http = axios.create(httpConfig);
-
-  Object.values(interceptors || {})?.forEach((item) => {
-    item.request && http.interceptors.request.use(item.request);
-    item.response && http.interceptors.response.use(item.response);
-  });
-
-  return async function (
-    url: string,
-    config: AxiosRequestConfig & {
-      originBody?: boolean;
-      prefix?: string;
-      silence?: boolean;
-    }
-  ) {
-    const { originBody, prefix, silence, ...thisConfig } = Object.assign(
-      {},
-      config,
-      { url }
-    );
-    if (prefix) {
-      thisConfig.url = prefix + thisConfig.url;
-    }
-
-    try {
-      let response = (await http(thisConfig)).data;
-      if (originBody) {
-        response = {
-          errorNo: 200,
-          errorDesc: "",
-          result: response,
-        };
-      }
-      if (response.errorNo !== 200) {
-        const silence = config.silence ?? config.method === "GET";
-        throw Exception.error({
-          msg: response.errorDesc,
-          silence,
-          result: response,
-        });
-      }
-      return response;
-    } catch (error) {
-      if (error instanceof Exception) throw error;
-      throw Exception.error({ msg: `${error}`, silence, result: error });
-    }
-  };
-}
-export class Http {
-  static config: RequestConfig = {
-    timeout: 10000,
-    headers: { "Content-Type": "application/json; charset=utf-8" },
-  };
-  static setConfig(config: RequestConfig) {
-    Object.assign(this.config, config);
-  }
-  static defaultConfig(config: RequestConfig) {
-    defaultsDeep(this.config, config);
-  }
-  static create(config?: RequestConfig) {
-    return createRequest(Object.assign({}, this.config, config));
-  }
-  static interceptor(interceptor: {
-    request?: (config: RequestConfig) => RequestConfig;
-    response?: <T>(res: T) => T;
-  }) {
-    return interceptor;
-  }
-}

+ 0 - 11
src/modules/queenjs/core/index.ts

@@ -1,11 +0,0 @@
-export * from "./comm/bus";
-export * from "./comm/event";
-export * from "./defineUI";
-export * from "./defineUI/DefaultUI";
-export * from "./dict";
-export * from "./effect";
-export * from "./exception";
-export * from "./http";
-export { QueenModuleRoot as ModuleRoot } from "./module";
-export { ModuleControl } from "./module/control";
-export * from "./state";

+ 0 - 126
src/modules/queenjs/core/module/actions.ts

@@ -1,126 +0,0 @@
-import { createUse, ModuleRoot } from "moduse";
-import { onUnmounted } from "vue";
-import { QueenModuleRoot } from ".";
-import {
-  ActionsListener,
-  FuncType,
-  UnionToIntersectionType,
-} from "../../typing";
-import { Exception } from "../exception";
-
-export type IActionOptions = {
-  keepActive?: boolean;
-  once?: boolean;
-  result?: Promise<any> | null;
-};
-
-export type IAction = FuncType<Promise<any> | void> & IActionOptions;
-
-export type IActions = {
-  [name: string]: IAction;
-};
-
-type OptionKeys = "once" | "keepActive";
-interface IDefineAction {
-  <K extends typeof ModuleRoot, Define extends IActions>(
-    this: K,
-    options: OptionKeys | OptionKeys[] | { [name in OptionKeys]?: boolean },
-    define: Define & ThisType<InstanceType<K>>
-  ): Define;
-  <K extends typeof ModuleRoot, Define extends IActions>(
-    this: K,
-    define: Define & ThisType<InstanceType<K>>
-  ): Define;
-}
-
-export const defineAction: IDefineAction = function (...args: any[]) {
-  let [options, actions] = args;
-  if (!actions) {
-    actions = options;
-    options = undefined;
-  }
-
-  if (options) {
-    let funcOpts: any = {};
-    if (typeof options === "string") {
-      funcOpts[options] = true;
-    } else if (options instanceof Array) {
-      options.forEach((key) => (funcOpts[key] = true));
-    } else {
-      funcOpts = options;
-    }
-    Object.values(actions).forEach((func: any) => {
-      Object.assign(func, funcOpts);
-    });
-  }
-
-  return actions;
-};
-
-export const createUseActions = function (this: QueenModuleRoot) {
-  return createUse<IActions>("actions", {
-    transform: (actions) => {
-      Object.entries(actions).forEach(([key, func]) => {
-        this._actions[key] = {};
-        Object.keys(func).forEach((optionKey) => {
-          (this._actions[key] as any)[optionKey] = (func as any)[optionKey];
-        });
-        actions[key] = async (...args: any[]) => {
-          const _action = this._actions[key];
-          if (_action.once && _action.result !== undefined) {
-            throw Exception.error(`${key}方法在模块生命周期内只能调用一次!`);
-          }
-
-          let funcResult;
-          try {
-            console.log(key, "start");
-            this._bus.emit(key, ...args);
-            funcResult = (func as any).call(this, ...args) || Promise.resolve();
-          } catch (error) {
-            funcResult = Promise.reject(error);
-          }
-
-          _action.result = _action.keepActive ? funcResult : null;
-
-          funcResult
-            .then((res: any) => {
-              console.log(`${key}:success`, res);
-              this._bus.emit(`${key}:success`, res);
-            })
-            .catch((err: any) => {
-              console.log(`${key}:fail`, err);
-              this._bus.emit(`${key}:fail`, err);
-            });
-
-          return funcResult;
-        };
-      });
-
-      actions.on = (name: string, fn: any) => {
-        const [key, status] = name.split(":");
-        const _action = this._actions[key];
-        if (status && _action.keepActive && _action.result) {
-          _action.result
-            .then(fn)
-            .catch(fn)
-            .finally(() => {
-              this._bus.on(name, fn);
-            });
-        } else {
-          this._bus.on(name, fn);
-        }
-
-        onUnmounted(() => {
-          this._bus.removeListener(name, fn);
-        });
-      };
-
-      return actions;
-    },
-  }) as <InstanceThis extends ModuleRoot, T>(
-    this: InstanceThis,
-    defines: (T & ThisType<InstanceThis>) | T[]
-  ) => UnionToIntersectionType<T, never> & {
-    on: ActionsListener<UnionToIntersectionType<T, never>>;
-  };
-};

+ 0 - 23
src/modules/queenjs/core/module/control.ts

@@ -1,23 +0,0 @@
-import { QueenModuleRoot } from ".";
-
-export class ModuleControl<T extends QueenModuleRoot> {
-  constructor(protected module: T) {}
-  protected get store(): T["store"] {
-    return this.module.store;
-  }
-  protected get https(): T["https"] {
-    return this.module.https;
-  }
-  protected get actions(): T["actions"] {
-    return this.module.actions;
-  }
-  protected get helper(): T["helper"] {
-    return this.module.helper;
-  }
-  protected get controls(): T["controls"] {
-    return this.module.controls;
-  }
-  destroy() {
-    // todo 销毁
-  }
-}

+ 0 - 62
src/modules/queenjs/core/module/hook.ts

@@ -1,62 +0,0 @@
-import { ModuleRoot } from "moduse";
-import { markRaw, onUnmounted } from "vue";
-import { createHook } from "vue-moduse";
-
-export function defineHook<
-  T extends typeof ModuleRoot,
-  N extends Capitalize<string>
->(this: T, name: N) {
-  const initName = `init${name}`;
-  const hooks = createHook(this, name);
-  const initModule = (hooks as any)[initName];
-
-  (hooks as any)[initName] = function (options: any) {
-    const instance = initModule(options);
-    instance.moduleName = name;
-    instance.onReady();
-    onUnmounted(() => {
-      instance.destroy();
-    });
-
-    if (instance.components) {
-      Object.entries(instance.components).forEach(([key, value]) => {
-        instance.components[key] = value ? markRaw(value as any) : value;
-      });
-    }
-    return instance;
-  };
-
-  // const compsHooks = customHook(`${name}Comps` as const, options?.components);
-  // const useHooks = customHook(`${name}Hooks` as const, options?.components);
-
-  return hooks;
-}
-
-// function customHook<N extends string, T extends ObjType<any>>(
-//   name: N,
-//   fields?: T
-// ) {
-//   let isSetted = false;
-
-//   function setFields(fields: Partial<T>) {
-//     isSetted = true;
-//     provide(name, fields);
-//   }
-
-//   // 获取模块实例
-//   function useFields() {
-//     return { ...fields, ...(isSetted ? inject(name) : undefined) } as T;
-//   }
-
-//   type UseFields = `use${N}`;
-//   type SetFields = `set${N}`;
-
-//   return {
-//     [`use${name}`]: useFields,
-//     [`set${name}`]: setFields,
-//   } as {
-//     [name in UseFields]: typeof useFields;
-//   } & {
-//     [name in SetFields]: typeof setFields;
-//   };
-// }

+ 0 - 31
src/modules/queenjs/core/module/https.ts

@@ -1,31 +0,0 @@
-import { AxiosResponse } from "axios";
-import { createDefine, createUse } from "moduse";
-import { QueenModuleRoot } from ".";
-import { FuncType } from "../../typing";
-import { Http, RequestConfig } from "../http";
-
-export type IHttps = {
-  [name: string]: FuncType<Promise<AxiosResponse<any, any>>>;
-};
-
-export const defineHttp = createDefine<
-  IHttps,
-  { request: ReturnType<typeof Http.create> }
->();
-
-export function createUseHttps(this: QueenModuleRoot) {
-  return createUse<IHttps, { httpConfig: RequestConfig }>("https", {
-    transform: (https, options) => {
-      Object.entries(https).forEach(([key, func]) => {
-        https[key] = func.bind(https);
-      });
-      https.request = Http.create(
-        options.httpConfig ||
-          this.config?.httpConfig ||
-          this.options?.config?.httpConfig
-      );
-      Object.setPrototypeOf(https, this);
-      return https;
-    },
-  });
-}

+ 0 - 142
src/modules/queenjs/core/module/index.ts

@@ -1,142 +0,0 @@
-import Emitter from "eventemitter3";
-import {
-  createDefine,
-  createInstance,
-  createUse,
-  DefineType,
-  ModuleRoot,
-} from "moduse";
-import { queenApi } from "../../api";
-import { DeepCompSlots, FuncType, ObjType } from "../../typing";
-import { RequestConfig } from "../http";
-import {
-  createUseActions,
-  defineAction,
-  IActionOptions,
-  IActions,
-} from "./actions";
-import { defineHook } from "./hook";
-import { createUseHttps, defineHttp, IHttps } from "./https";
-import { defineStore, useStore } from "./store";
-import { useSubModules } from "./subModule";
-
-type IConfig = {
-  httpConfig?: RequestConfig;
-  [name: string]: any;
-};
-
-type IHelper = {
-  [name: string]: FuncType<any>;
-};
-
-export class QueenModuleRoot extends ModuleRoot {
-  // createInstance中可声明的泛型字段在模块中也需要声明
-  static create = createInstance<
-    "config" | "actions" | "https" | "helper" | "components" | "modules"
-  >();
-  config?: IConfig;
-  https?: IHttps;
-  helper?: IHelper;
-  actions?: IActions;
-  components: DefineType<any> = {};
-  modules: DefineType<ModuleRoot> = {};
-
-  static hook = defineHook;
-  static helper = createDefine<IHelper>();
-  static action = defineAction;
-  static http = defineHttp;
-  static store = defineStore;
-
-  moduleName = "";
-  store?: any;
-  controls?: { [name: string]: any };
-
-  protected _bus = new Emitter();
-  protected _actions: ObjType<IActionOptions> = {};
-
-  protected setConfig = createUse<
-    IConfig,
-    unknown,
-    { httpConfig: RequestConfig }
-  >("config");
-  protected useComponents = createUse<DefineType<any>>("components", {
-    transform(comps) {
-      return comps;
-    },
-  });
-
-  protected useModules = useSubModules;
-
-  protected createHelper = createUse<IHelper>("helper");
-  protected createStore = useStore;
-  protected createActions = createUseActions.call(this);
-  protected createHttps = createUseHttps.call(this);
-
-  showModal: typeof queenApi.dialog = (
-    ...args: Parameters<typeof queenApi.dialog>
-  ) => {
-    const [component, params, context = {}] = args;
-    const modules: any = {};
-    Object.values(context).forEach((value) => {
-      if (value.moduleName) {
-        modules[value.moduleName] = value;
-      }
-    });
-    modules[this.moduleName] = this;
-    return queenApi.dialog(component, params, modules);
-  };
-
-  onReady() {
-    // todo overwrite
-  }
-
-  // 在上下文销毁时调用
-  destroy() {
-    if (this.controls) {
-      Object.values(this.controls).forEach((control) => {
-        control.destroy?.();
-      });
-    }
-  }
-
-  initComponents<T extends QueenModuleRoot, C extends T["components"]>(
-    this: T,
-    config: {
-      [name in keyof C]?: DeepCompSlots<C[name]>;
-    }
-  ) {
-    Object.entries(config).forEach(([key, compConf]) => {
-      this.components[key] = initCompsDeep(this.components[key], compConf);
-    });
-
-    function initCompsDeep(comp: any, compConf: any) {
-      if (comp.compType === "overwrite") return comp;
-      if (!compConf) return () => null;
-      if (compConf instanceof Function) {
-        Object.keys(comp).forEach((key) => {
-          if (key === "name" || key === "compType") return;
-          compConf[key] = compConf[key] || comp[key];
-        });
-        return compConf;
-      } else {
-        const customComp: any =
-          compConf.default ||
-          Object.getPrototypeOf(comp).bind(() => customComp);
-        if (compConf.default) {
-          customComp.compType = "overwrite";
-        } else {
-          Object.setPrototypeOf(customComp, Object.getPrototypeOf(comp));
-        }
-        Object.keys(comp).forEach((key) => {
-          if (key === "name" || key === "compType") return;
-          customComp[key] =
-            customComp[key] ||
-            (compConf[key]
-              ? initCompsDeep(comp[key], compConf[key])
-              : comp[key]);
-        });
-        return customComp;
-      }
-    }
-  }
-}

+ 0 - 108
src/modules/queenjs/core/module/store.ts

@@ -1,108 +0,0 @@
-import { ModuleRoot } from "moduse";
-import { computed, reactive } from "vue";
-import {
-  AnyFun,
-  ClassType,
-  EmptyObj,
-  ObjType,
-  UnionToIntersectionReturnType,
-  UnionToIntersectionType
-} from "../../typing";
-
-type IStore = {
-  state: () => any;
-  getters?: any;
-  actions?: any;
-};
-
-interface IDefineStore {
-  <
-    K extends ClassType<any>,
-    State extends () => ObjType<any>,
-    Getters extends ObjType<(state: ReturnType<State>) => any>,
-    Actions extends ObjType<AnyFun>
-  >(
-    this: K,
-    store: {
-      state: State;
-      getters: Getters & ThisType<InstanceType<K>>;
-      actions: Actions & ThisType<InstanceType<K>>;
-    }
-  ): {
-    state: State;
-    getters: Getters;
-    actions: Actions;
-  };
-  <
-    K extends ClassType<any>,
-    State extends () => ObjType<any>,
-    Actions extends ObjType<AnyFun>
-  >(
-    this: K,
-    store: {
-      state: State;
-      actions: Actions & ThisType<InstanceType<K>>;
-    }
-  ): {
-    state: State;
-    getters: EmptyObj;
-    actions: Actions;
-  };
-  <
-    K extends ClassType<any>,
-    State extends () => ObjType<any>,
-    Getters extends ObjType<(state: ReturnType<State>) => any>
-  >(
-    this: K,
-    store: {
-      state: State;
-      getters: Getters & ThisType<InstanceType<K>>;
-    }
-  ): {
-    state: State;
-    getters: Getters;
-    actions: EmptyObj;
-  };
-
-  <K extends ClassType<any>, State extends () => ObjType<any>>(
-    this: K,
-    store: {
-      state: State;
-    }
-  ): {
-    state: State;
-    getters: EmptyObj;
-    actions: EmptyObj;
-  };
-}
-
-export const defineStore: IDefineStore = function (store: any) {
-  return store;
-};
-
-export function useStore<T extends IStore>(
-  this: ModuleRoot,
-  store: T | T[]
-): UnionToIntersectionType<ReturnType<T["state"]>, never> &
-  UnionToIntersectionReturnType<T["getters"], never> &
-  UnionToIntersectionType<T["actions"], never> {
-  const data: any = {},
-    actions: any = {};
-  const stores = store instanceof Array ? store : [store];
-  stores.forEach((store) => {
-    Object.assign(data, store.state());
-    if (store.getters) {
-      Object.entries(store.getters).forEach(([key, value]) => {
-        data[key] = computed(() => (value as any).call(this, state));
-      });
-    }
-    if (store.actions) {
-      Object.entries(store.actions).forEach(([key, value]) => {
-        actions[key] = (value as any).bind(this);
-      });
-    }
-  });
-  const state = reactive(data);
-  Object.setPrototypeOf(state, actions);
-  return state;
-}

+ 0 - 12
src/modules/queenjs/core/module/subModule.ts

@@ -1,12 +0,0 @@
-import { ModuleRoot } from "moduse";
-
-export function useSubModules<T extends { [name: string]: () => ModuleRoot }>(
-  this: any,
-  mods: T
-): { [name in keyof T]: ReturnType<T[name]> } {
-  const modules: any = {};
-  for (const key in mods) {
-    modules[key] = this.options.modules?.[key] || mods[key]();
-  }
-  return modules;
-}

+ 0 - 147
src/modules/queenjs/core/state/index.ts

@@ -1,147 +0,0 @@
-import { computed, isProxy, reactive } from "vue";
-
-const stateWatchers = new WeakMap();
-
-export class StateRoot {
-  protected isProxy = false;
-  protected computed<F extends (state: Omit<this, "reactive">) => any>(fn: F) {
-    return fn as ReturnType<F>;
-  }
-  reactive = () => {
-    return createReactive(this) as Omit<this, "reactive">;
-  };
-}
-
-function createReactive(obj: any) {
-  const data: any = {};
-  for (const name in obj) {
-    if (name === "reactive" || name === "computed" || name === "proxy")
-      continue;
-    const objItem: any = obj[name];
-    if (objItem instanceof Function) {
-      data[name] = computed(() => objItem(state));
-    } else {
-      data[name] = objItem;
-    }
-  }
-  const state: any = reactive(
-    obj.isProxy ? createProxy(data, [], () => state) : data
-  );
-  return state;
-}
-
-function createProxy<T>(target: T, paths: string[], getRoot: () => any): T {
-  if (
-    typeof target === "object" &&
-    !isProxy(target) &&
-    !(target instanceof Function) &&
-    target !== null
-  ) {
-    for (const key in target) {
-      const proxy = createProxy(target[key], [...paths, key], getRoot);
-      target[key] = proxy;
-    }
-    return new Proxy(target as any, {
-      get: (target, key, receiver) => {
-        if (key == "isProxy") {
-          return true;
-        }
-        return Reflect.get(target, key, receiver);
-      },
-      ...(target instanceof Array
-        ? arrayHandler(paths, getRoot)
-        : objectHandler(paths, getRoot)),
-    });
-  } else {
-    return target;
-  }
-}
-
-function arrayHandler(paths: string[], getRoot: () => any) {
-  let removeIndex: any = null;
-  let removeOld: any = null;
-  return {
-    set: (target: Array<any>, key: string, value: any, receiver: any) => {
-      if (key === "length") {
-        removeIndex = null;
-        removeOld = null;
-      } else if (!removeIndex) {
-        if (!value.isProxy) {
-          const pathArr = [...paths, key];
-          if (+key == target.length) {
-            emit("add", pathArr, value, null, getRoot);
-          } else {
-            emit("set", pathArr, value, target[+key], getRoot);
-          }
-          value = createProxy(value, pathArr, getRoot);
-        } else {
-          removeIndex = key;
-          removeOld = target[+key];
-        }
-      }
-
-      return Reflect.set(target, key, value, receiver);
-    },
-    deleteProperty: (target: Array<any>, key: string) => {
-      if (!removeIndex) {
-        removeIndex = key;
-        removeOld = target[+key];
-      }
-      emit("remove", [...paths, removeIndex], null, removeOld, getRoot);
-      return Reflect.deleteProperty(target, key);
-    },
-  };
-}
-
-function objectHandler(paths: string[], getRoot: () => any) {
-  return {
-    set: (
-      target: { [name: string]: any },
-      key: string,
-      value: any,
-      receiver: any
-    ) => {
-      // eslint-disable-next-line
-      const actionType = target.hasOwnProperty(key) ? "set" : "add";
-      emit(actionType, [...paths, key], value, target[key], getRoot);
-      return Reflect.set(
-        target,
-        key,
-        createProxy(value, [...paths, key], getRoot),
-        receiver
-      );
-    },
-    deleteProperty: (target: { [name: string]: any }, key: string) => {
-      emit("remove", [...paths, key], null, target[key], getRoot);
-      return Reflect.deleteProperty(target, key);
-    },
-  };
-}
-
-function emit(
-  type: string,
-  paths: string[],
-  val: any,
-  old: any,
-  getRoot: () => any
-) {
-  const handler = stateWatchers.get(getRoot());
-  handler?.(type, paths, val, old);
-}
-
-export function createProxyEffect(
-  target: ReturnType<StateRoot["reactive"]>,
-  handler: (
-    type: "set" | "add" | "remove",
-    paths: string[],
-    val: any,
-    old: any
-  ) => void
-) {
-  stateWatchers.set(target, handler);
-  return {
-    stop() {
-      stateWatchers.delete(target);
-    },
-  };
-}

+ 0 - 15
src/modules/queenjs/core/use/useCapturedFunc.ts

@@ -1,15 +0,0 @@
-import { AnyFun } from "../../typing";
-
-export function useCapturedFunc<T extends AnyFun>(
-  fn: T,
-  control?: (promise: ReturnType<T>) => void
-) {
-  return async (...args: any) => {
-    try {
-      const result = await fn(...args);
-      control?.(Promise.resolve(result) as any);
-    } catch (error) {
-      control?.(Promise.reject(error) as any);
-    }
-  };
-}

+ 0 - 2
src/modules/queenjs/index.ts

@@ -1,2 +0,0 @@
-export * from "./core";
-export * from "./api";

+ 0 - 91
src/modules/queenjs/typing.ts

@@ -1,91 +0,0 @@
-import { DefineComponent } from "vue";
-import { SlotsFn } from "./core/defineUI/typings";
-
-const emptyObj = {};
-
-export type EmptyObj = typeof emptyObj;
-
-export type ObjType<T> = { [name: string]: T };
-
-export type Filter<T, C> = T extends C ? T : never;
-
-type IActionReturn<
-  T,
-  Actions extends ObjType<AnyFun>
-> = T extends `${infer P extends Filter<keyof Actions, string>}:success`
-  ? Awaited<ReturnType<Actions[P]>>
-  : never;
-
-export type FuncType<T> = <T1 = unknown, T2 = unknown>(...args: any) => T;
-
-export interface AnyFun {
-  (...args: any[]): any;
-}
-
-export interface ClassType<T> {
-  new (...args: any): T;
-}
-
-export interface ModuleType<T> {
-  defineConfig: { [name: string]: any };
-  new (...args: any): T;
-}
-
-export interface ActionsListener<Actions extends ObjType<AnyFun>> {
-  <
-    ActionHandles extends {
-      [name in keyof Actions]: (...args: Parameters<Actions[name]>) => void;
-    } & {
-      [name in `${Filter<keyof Actions, string>}:success`]: (
-        args: IActionReturn<name, Actions>
-      ) => void;
-    } & {
-      [name in `${Filter<keyof Actions, string>}:fail`]: (err: string) => void;
-    },
-    Key extends keyof ActionHandles
-  >(
-    key: Key,
-    handle: ActionHandles[Key]
-  ): void;
-}
-
-export type UnionToIntersectionType<T, K extends string> = (
-  T extends any
-    ? (x: {
-        [name in keyof Omit<T, K>]: T[name];
-      }) => any
-    : never
-) extends (x: infer P) => any
-  ? { [name in keyof P]: P[name] }
-  : never;
-
-export type UnionToIntersectionReturnType<
-  T extends ObjType<AnyFun>,
-  K extends string
-> = (
-  T extends any
-    ? (x: {
-        [name in keyof Omit<T, K>]: ReturnType<T[name]>;
-      }) => any
-    : never
-) extends (x: infer P) => any
-  ? { [name in keyof P]: P[name] }
-  : never;
-
-type FuncCompopnent = (...args: any[]) => JSX.Element;
-export type IComponent =
-  | DefineComponent<any, any, any, any, any, any, any, any, any, any>
-  | FuncCompopnent;
-
-type GetSlots<T> = T extends SlotsFn<infer P> ? P : never;
-
-export type DeepCompSlots<
-  T extends { slots: any },
-  S = GetSlots<T["slots"]>
-> = {
-  [name in keyof S]?: S[name] extends { slots: any }
-    ? DeepCompSlots<S[name]>
-    : IComponent;
-} & {
-  default?: IComponent;
-};

+ 13 - 0
src/typings/asset.d.ts

@@ -1,3 +1,5 @@
+import { number } from "vue-types";
+
 declare var getImageUrl: (url: IAssetURLs) => string;
 
 declare interface LayoutMenu {
@@ -5,4 +7,15 @@ declare interface LayoutMenu {
   url: string;
   children?: { title: string; url: string }[];
 }
+declare type CategoryItem = {
+  id: string;
+  pid: string; // 分类的上层id // 默认为top
+  name: string; //分类封面图
+  cover: string; //分类名称
+  sort: number;
+  type: string; // 分类类型 list,detail,download
+  isHome: bool; // 是否展示到首页
+  children?: CategoryItem[];
+};
+
 declare module "froala-editor";

+ 1 - 0
src/utils/index.ts

@@ -1 +1,2 @@
 export * from "./image";
+export * from "./request";

+ 29 - 0
src/utils/request.ts

@@ -0,0 +1,29 @@
+import axios, { AxiosRequestConfig } from "axios";
+const config: RequestConfig = {
+  timeout: 10000,
+  headers: { "Content-Type": "application/json; charset=utf-8" },
+};
+
+export type RequestConfig = AxiosRequestConfig & {
+  interceptors?: any;
+};
+
+export function createRequest(defReqConfig: RequestConfig) {
+  const { interceptors, ...httpConfig } = defReqConfig;
+  const http = axios.create({ ...config, ...httpConfig });
+
+  Object.values(interceptors || {})?.forEach((item: any) => {
+    item.request && http.interceptors.request.use(item.request);
+    item.response && http.interceptors.response.use(item.response);
+  });
+  return async function (url: string, config: AxiosRequestConfig) {
+    const thisConfig = Object.assign({}, config, { url });
+
+    try {
+      let response = (await http(thisConfig)).data;
+      return response;
+    } catch (error) {
+      throw console.error({ msg: `${error}`, result: error });
+    }
+  };
+}

+ 5 - 5
src/views/admin/App.tsx

@@ -1,10 +1,10 @@
-import { Provider } from "@/components/Provider/Provider";
+import { Provider } from "@/components/Provider";
+import { useAuth } from "@/modules/admin";
 import { defineComponent } from "vue";
-import { initAdmin } from "@/modules/admin";
+
 export default defineComponent(() => {
-  initAdmin({
-    config: {},
-  });
+  const storeAuth = useAuth();
+  storeAuth.initAuth();
   return () => (
     <Provider>
       <router-view></router-view>

+ 123 - 0
src/views/admin/category/CategoryTree.tsx

@@ -0,0 +1,123 @@
+import {
+  DeleteOutlined,
+  FormOutlined,
+  PlusSquareOutlined,
+} from "@ant-design/icons-vue";
+import { css } from "@linaria/core";
+import { Button, Tree } from "ant-design-vue";
+import { defineComponent } from "vue";
+import { any } from "vue-types";
+
+export default defineComponent({
+  props: {
+    data: any(),
+  },
+  emits: ["add", "update", "delete"],
+  setup(props, { emit }) {
+    const formatTreeData = (data: any, key = 0) => {
+      const res: any[] = [];
+      data?.map((item: any, index: number) => {
+        res[index] = {};
+        res[index].key = item.id;
+        res[index].title = (
+          <div class={"tree_item"} key={index}>
+            <div class="item_txt">
+              <span class="item_tit">{item.name || "undefined"}</span>
+            </div>
+            <div class="item_btn">
+              {key != 3 && (
+                <Button
+                  class="tree_btn"
+                  title="添加子分类"
+                  icon={<PlusSquareOutlined />}
+                  onClick={(e) => {
+                    e.stopPropagation();
+                    emit("add", key + 1, item.id);
+                  }}
+                ></Button>
+              )}
+
+              <Button
+                class="tree_btn"
+                title="编辑分类"
+                icon={<FormOutlined />}
+                onClick={(e) => {
+                  e.stopPropagation();
+                  emit("update", item);
+                }}
+              ></Button>
+              <Button
+                class="tree_btn"
+                title="删除分类"
+                icon={<DeleteOutlined />}
+                onClick={(e) => {
+                  e.stopPropagation();
+                  emit("delete", item);
+                }}
+              ></Button>
+            </div>
+          </div>
+        );
+        let arr: any[] = [];
+        if (Array.isArray(item.children) && item.children.length > 0) {
+          arr = formatTreeData(item.children, key + 1);
+          res[index].children = arr;
+        }
+      });
+      return res;
+    };
+
+    return () => (
+      <Tree.DirectoryTree
+        class={`${TreeRoot} whitespace-nowrap`}
+        treeData={formatTreeData(props.data)}
+        showIcon={false}
+        blockNode={true}
+      ></Tree.DirectoryTree>
+    );
+  },
+});
+const TreeRoot = css`
+  .ant-tree-node-selected {
+    .tree_item {
+      .item_btn {
+        .tree_btn {
+          color: #fff;
+          &:hover {
+            color: #fff;
+          }
+        }
+      }
+    }
+  }
+  .tree_item {
+    display: flex;
+    align-items: center;
+    .item_txt {
+      flex: 0;
+      display: flex;
+      align-items: center;
+      .item_tit {
+        font-size: 14px;
+      }
+    }
+    &:hover {
+      .item_btn {
+        display: block;
+      }
+    }
+    .item_btn {
+      flex: 1;
+      display: none;
+      margin-left: 20px;
+      .tree_btn {
+        margin: 0 6px;
+        min-width: auto;
+
+        border: none;
+        background-color: transparent;
+        box-shadow: none;
+      }
+    }
+  }
+`;

+ 36 - 0
src/views/admin/category/index.tsx

@@ -0,0 +1,36 @@
+import { css } from "@linaria/core";
+import { Button, Card, PageHeader } from "ant-design-vue";
+import { defineComponent } from "vue";
+import CategoryTree from "./CategoryTree";
+import { useCategory } from "@/modules/admin";
+
+export default defineComponent(() => {
+  const categoryStore = useCategory();
+  return () => (
+    <Card class={Page}>
+      <PageHeader title={"分类管理"}>
+        {{
+          extra: () => {
+            return (
+              <Button
+                type="primary"
+                onClick={() => categoryStore.addCategoryItem()}
+              >
+                + 添加分类
+              </Button>
+            );
+          },
+        }}
+      </PageHeader>
+      <CategoryTree
+        data={categoryStore.categoryMap.get("_")?.children}
+        onAdd={categoryStore.addCategoryItem}
+        onUpdate={categoryStore.renameCategoryItem}
+        onDelete={categoryStore.deleteCategoryItem}
+      />
+    </Card>
+  );
+});
+const Page = css`
+  height: 100%;
+`;

+ 215 - 35
src/views/admin/components/Editor.tsx

@@ -1,48 +1,228 @@
 import { css } from "@linaria/core";
-import { defineComponent, onMounted } from "vue";
-import "froala-editor/css/froala_editor.min.css";
-import FroalaEditor from "froala-editor";
-import "froala-editor/js/languages/zh_cn.js";
+import { defineComponent, onMounted, ref } from "vue";
+
+import Quill from "quill";
+
 export default defineComponent({
   setup(props, ctx) {
+    let editor = ref();
     onMounted(() => {
       initEditor();
+      initTitle();
     });
     const initEditor = () => {
-      var editor = new FroalaEditor("#FroalaEditor", {
-        language: "zh_cn",
-        attribution: false,
-        toolbarButtons: [
-          "bold",
-          "italic",
-          "underline",
-          "strikeThrough",
-          "fontFamily",
-          "fontSize",
-          "paragraphFormat",
-          "align",
-          "textColor",
-          "backgroundColor",
-          "formatOL",
-          "formatUL",
-          "indent",
-          "outdent",
-          "emoticons",
-          "redo",
-          "undo",
-          "insertlmage",
-          "insertLink",
-          "subscript",
-          "superscript",
-          "insertHR",
-          "insertTable",
-        ],
+      editor.value = new Quill("#editor", {
+        theme: "snow",
+        placeholder: "请在这里输入",
+        modules: {
+          toolbar: {
+            container: [
+              ["bold", "italic", "underline", "strike"], //加粗,斜体,下划线,删除线
+              [{ header: [1, 2, 3, false] }], //几级标题
+              [{ indent: "-1" }, { indent: "+1" }], // 缩进
+              [{ list: "ordered" }, { list: "bullet" }], // 有序、无序列表
+              [{ align: [] }], //对齐方式
+              [{ size: ["small", false, "large", "huge"] }],
+              [{ color: [] }],
+              [{ background: [] }],
+              [{ font: [] }],
+              ["clean"], //清除字体样式
+              ["link", "image"], //上传图片
+            ],
+            // handlers: {
+            //   link: (value: any) => {
+            //     if (value) {
+            //       console.log(value);
+            //     } else {
+            //       // editor.value.format("link", false);
+            //     }
+            //   },
+            // },
+          },
+        },
       });
     };
-    return () => <div class={Editor} id="FroalaEditor"></div>;
+    const initTitle = () => {
+      const titleConfig: { [key: string]: any } = {
+        "ql-bold": "加粗",
+        "ql-color": "字体颜色",
+        "ql-font": "字体",
+        "ql-code": "插入代码",
+        "ql-italic": "斜体",
+        "ql-link": "添加链接",
+        "ql-background": "背景颜色",
+        "ql-size": "字体大小",
+        "ql-strike": "删除线",
+        "ql-underline": "下划线",
+        "ql-header": "标题",
+        "ql-indent": "缩进",
+        "ql-list": "列表",
+        "ql-align": "文本对齐",
+        "ql-formula": "公式",
+        "ql-image": "图片",
+        "ql-video": "视频",
+        "ql-clean": "清除字体样式",
+      };
+      const oToolBar = document.querySelector(".ql-toolbar");
+      const aButton = oToolBar?.querySelectorAll("button");
+      const aSelect = oToolBar?.querySelectorAll("select");
+      aButton &&
+        aButton.forEach(function (item: any) {
+          if (item.className === "ql-indent") {
+            item.value === "+1"
+              ? (item.title = "向右缩进")
+              : (item.title = "向左缩进");
+          } else {
+            item.title = titleConfig[item.classList[0]];
+          }
+        });
+      aSelect?.forEach(function (item: any) {
+        item.parentNode.title = titleConfig[item.classList[0]];
+      });
+    };
+    return () => (
+      <div class={EditorPage}>
+        <div id="editor" class={"editor_content"}></div>
+      </div>
+    );
   },
 });
-const Editor = css`
+const EditorPage = css`
   width: 100%;
-  height: 100vh;
+  .editor_content {
+    width: 100%;
+    min-height: 400px;
+  }
+  .ql-snow {
+    .ql-editor h1 {
+      h1,
+      .ql-size-huge {
+        font-size: 1.8rem;
+      }
+    }
+    .ql-tooltip {
+      &::before {
+        content: "访问链接:";
+      }
+      &[data-mode="link"]::before {
+        content: "输入链接:";
+      }
+      a.ql-action::after {
+        content: "编辑";
+      }
+      a.ql-remove::before {
+        content: "删除";
+      }
+      &.ql-editing {
+        a.ql-action::after {
+          content: "保存";
+        }
+      }
+    }
+
+    .ql-picker {
+      &.ql-header {
+        .ql-picker-label {
+          &::before {
+            content: "正文";
+          }
+          &[data-value="1"]::before {
+            content: "标题1";
+          }
+          &[data-value="2"]::before {
+            content: "标题2";
+          }
+          &[data-value="3"]::before {
+            content: "标题3";
+          }
+        }
+        .ql-picker-item {
+          &::before {
+            content: "正文";
+          }
+          &[data-value="1"] {
+            &::before {
+              content: "标题1";
+              font-size: 1.8em;
+            }
+          }
+          &[data-value="2"] {
+            &::before {
+              content: "标题2";
+            }
+          }
+          &[data-value="3"] {
+            &::before {
+              content: "标题3";
+            }
+          }
+        }
+      }
+      &.ql-size {
+        .ql-picker-label {
+          &::before {
+            content: "普通";
+          }
+          &[data-value="small"]::before {
+            content: "小号";
+          }
+          &[data-value="large"]::before {
+            content: "大号";
+          }
+          &[data-value="huge"]::before {
+            content: "超大";
+          }
+        }
+        .ql-picker-item {
+          &::before {
+            content: "普通";
+          }
+          &[data-value="small"] {
+            &::before {
+              content: "小号";
+            }
+          }
+          &[data-value="large"] {
+            &::before {
+              content: "大号";
+            }
+          }
+          &[data-value="huge"] {
+            &::before {
+              font-size: 1.8rem;
+              content: "超大";
+            }
+          }
+        }
+      }
+      &.ql-font {
+        .ql-picker-label {
+          &::before {
+            content: "标准字体";
+          }
+          &[data-value="serif"]::before {
+            content: "衬线字体";
+          }
+          &[data-value="monospace"]::before {
+            content: "等宽字体";
+          }
+        }
+        .ql-picker-item {
+          &::before {
+            content: "标准字体";
+          }
+          &[data-value="serif"] {
+            &::before {
+              content: "衬线字体";
+            }
+          }
+          &[data-value="monospace"] {
+            &::before {
+              content: "等宽字体";
+            }
+          }
+        }
+      }
+    }
+  }
 `;

+ 4 - 0
src/views/admin/config/menus.ts

@@ -3,6 +3,10 @@ export const MenusConfig = [
     name: "首页轮播",
     path: "/banner",
   },
+  {
+    name: "分类管理",
+    path: "/category",
+  },
   {
     name: "学院概述",
     children: [

+ 1 - 3
src/views/admin/intro/index.tsx

@@ -7,9 +7,7 @@ export default defineComponent(() => {
   return () => (
     <Card class={Page}>
       学院简介
-      <div class={"editor"}>
-        <Editor />
-      </div>
+      <Editor />
     </Card>
   );
 });

+ 3 - 1
src/views/admin/main.ts

@@ -1,7 +1,9 @@
 import { createApp } from "vue";
 import App from "./App.tsx";
 import router from "./router";
+import { createPinia } from "pinia";
+import "quill/dist/quill.snow.css";
 import "virtual:windi.css";
 import "ant-design-vue/dist/antd.less";
 import "@/styles/main.css";
-createApp(App).use(router).mount("#app");
+createApp(App).use(router).use(createPinia()).mount("#app");

+ 4 - 0
src/views/admin/router/index.ts

@@ -14,6 +14,10 @@ const router = createRouter({
           path: "/banner",
           component: () => import("../banner"),
         },
+        {
+          path: "/category",
+          component: () => import("../category"),
+        },
         {
           path: "/intro",
           component: () => import("../intro"),

File diff suppressed because it is too large
+ 330 - 330
yarn.lock


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