feat: 新增静态、api数据源

This commit is contained in:
2026-08-16 20:42:15 +08:00
parent 0fe7d69dba
commit 7215b59c5a
18 changed files with 501 additions and 23 deletions
+2 -2
View File
@@ -46,8 +46,8 @@ pnpm format # prettier --write src/
- ~~网页代码编辑器接入~~
- ~~页面 Schema 导入导出与实时编辑~~
- 静态数据源
- API 数据源
- ~~静态数据源~~
- ~~API 数据源~~
- 数据源管理界面
- API 数据源调试
- 加载、刷新与请求复用
+6
View File
@@ -22,6 +22,12 @@ declare module 'vue' {
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
ElOption: typeof import('element-plus/es')['ElOption']
ElSelect: typeof import('element-plus/es')['ElSelect']
ElTable: typeof import('element-plus/es')['ElTable']
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
ElTabPane: typeof import('element-plus/es')['ElTabPane']
ElTabs: typeof import('element-plus/es')['ElTabs']
MonacoEditor: typeof import('./src/components/MonacoEditor/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
+3
View File
@@ -16,8 +16,10 @@
},
"dependencies": {
"@tailwindcss/postcss": "^4.3.3",
"axios": "^1.19.0",
"echarts": "^6.1.0",
"element-plus": "^2.14.4",
"mockjs": "^1.1.0",
"monaco-editor": "0.55.1",
"pinia": "^4.0.2",
"postcss": "^8.5.26",
@@ -32,6 +34,7 @@
"devDependencies": {
"@iconify/vue": "^5.0.1",
"@tsconfig/node24": "^24.0.4",
"@types/mockjs": "^1.0.10",
"@types/node": "^24.13.3",
"@vitejs/plugin-vue": "^6.0.8",
"@vue/eslint-config-typescript": "^14.9.0",
+239
View File
@@ -11,12 +11,18 @@ importers:
'@tailwindcss/postcss':
specifier: ^4.3.3
version: 4.3.3
axios:
specifier: ^1.19.0
version: 1.19.0
echarts:
specifier: ^6.1.0
version: 6.1.0
element-plus:
specifier: ^2.14.4
version: 2.14.4(vue@3.5.41(typescript@6.0.3))
mockjs:
specifier: ^1.1.0
version: 1.1.0
monaco-editor:
specifier: 0.55.1
version: 0.55.1
@@ -54,6 +60,9 @@ importers:
'@tsconfig/node24':
specifier: ^24.0.4
version: 24.0.4
'@types/mockjs':
specifier: ^1.0.10
version: 1.0.10
'@types/node':
specifier: ^24.13.3
version: 24.13.3
@@ -747,6 +756,9 @@ packages:
'@types/lodash@4.17.25':
resolution: {integrity: sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==}
'@types/mockjs@1.0.10':
resolution: {integrity: sha512-SXgrhajHG7boLv6oU93CcmdDm0HYRiceuz6b+7z+/2lCJPTWDv0V5YiwFHT2ejE4bQqgSXQiVPQYPWv7LGsK1g==}
'@types/node@24.13.3':
resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==}
@@ -949,6 +961,10 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
agent-base@6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
ajv@6.15.0:
resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==}
@@ -974,6 +990,12 @@ packages:
async-validator@4.2.5:
resolution: {integrity: sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==}
asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
axios@1.19.0:
resolution: {integrity: sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==}
balanced-match@4.0.4:
resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==}
engines: {node: 18 || 20 || >=22}
@@ -1009,6 +1031,10 @@ packages:
resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==}
engines: {node: '>=18'}
call-bind-apply-helpers@1.0.2:
resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==}
engines: {node: '>= 0.4'}
caniuse-lite@1.0.30001809:
resolution: {integrity: sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ==}
@@ -1016,6 +1042,14 @@ packages:
resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==}
engines: {node: '>= 20.19.0'}
combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
commander@15.0.0:
resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==}
engines: {node: '>=22.12.0'}
confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
@@ -1081,6 +1115,10 @@ packages:
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
engines: {node: '>=12'}
delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'}
@@ -1088,6 +1126,10 @@ packages:
dompurify@3.2.7:
resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==}
dunder-proto@1.0.1:
resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==}
engines: {node: '>= 0.4'}
echarts@6.1.0:
resolution: {integrity: sha512-q0yaFPggC9FUdsWH4blavRWFmxdrIodbkoKNAjJudAI6CA9gNPxHtV2RcZNEepZVlk4yvBYkOkbk6HIVpIyHZA==}
@@ -1110,6 +1152,22 @@ packages:
error-stack-parser-es@1.0.5:
resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==}
es-define-property@1.0.1:
resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==}
engines: {node: '>= 0.4'}
es-errors@1.3.0:
resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==}
engines: {node: '>= 0.4'}
es-object-atoms@1.1.2:
resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==}
engines: {node: '>= 0.4'}
es-set-tostringtag@2.1.0:
resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==}
engines: {node: '>= 0.4'}
escalade@3.2.0:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
@@ -1242,6 +1300,19 @@ packages:
flatted@3.4.4:
resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==}
follow-redirects@1.16.0:
resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
form-data@4.0.6:
resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==}
engines: {node: '>= 6'}
framework-utils@1.1.0:
resolution: {integrity: sha512-KAfqli5PwpFJ8o3psRNs8svpMGyCSAe8nmGcjQ0zZBWN2H6dZDnq+ABp3N3hdUmFeMrLtjOCTXD4yplUJIWceg==}
@@ -1250,6 +1321,9 @@ packages:
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
@@ -1257,6 +1331,14 @@ packages:
gesto@1.19.4:
resolution: {integrity: sha512-hfr/0dWwh0Bnbb88s3QVJd1ZRJeOWcgHPPwmiH6NnafDYvhTsxg+SLYu+q/oPNh9JS3V+nlr6fNs8kvPAtcRDQ==}
get-intrinsic@1.3.0:
resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==}
engines: {node: '>= 0.4'}
get-proto@1.0.1:
resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==}
engines: {node: '>= 0.4'}
glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
@@ -1265,12 +1347,32 @@ packages:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
gopd@1.2.0:
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
engines: {node: '>= 0.4'}
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
has-symbols@1.1.0:
resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==}
engines: {node: '>= 0.4'}
has-tostringtag@1.0.2:
resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==}
engines: {node: '>= 0.4'}
hasown@2.0.4:
resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==}
engines: {node: '>= 0.4'}
hookable@5.5.3:
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
https-proxy-agent@5.0.1:
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
engines: {node: '>= 6'}
ignore@5.3.2:
resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==}
engines: {node: '>= 4'}
@@ -1559,6 +1661,10 @@ packages:
engines: {node: '>= 18'}
hasBin: true
math-intrinsics@1.1.0:
resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==}
engines: {node: '>= 0.4'}
memoize-one@6.0.0:
resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==}
@@ -1574,6 +1680,14 @@ packages:
resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==}
engines: {node: '>=8.6'}
mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
minimatch@10.2.6:
resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==}
engines: {node: 18 || 20 || >=22}
@@ -1581,6 +1695,10 @@ packages:
mlly@1.8.2:
resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==}
mockjs@1.1.0:
resolution: {integrity: sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==}
hasBin: true
monaco-editor@0.55.1:
resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==}
@@ -1740,6 +1858,10 @@ packages:
engines: {node: '>=14'}
hasBin: true
proxy-from-env@2.1.0:
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
engines: {node: '>=10'}
punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}
@@ -2669,6 +2791,8 @@ snapshots:
'@types/lodash@4.17.25': {}
'@types/mockjs@1.0.10': {}
'@types/node@24.13.3':
dependencies:
undici-types: 7.18.2
@@ -2948,6 +3072,12 @@ snapshots:
acorn@8.18.0: {}
agent-base@6.0.2:
dependencies:
debug: 4.4.3
transitivePeerDependencies:
- supports-color
ajv@6.15.0:
dependencies:
fast-deep-equal: 3.1.3
@@ -2974,6 +3104,18 @@ snapshots:
async-validator@4.2.5: {}
asynckit@0.4.0: {}
axios@1.19.0:
dependencies:
follow-redirects: 1.16.0
form-data: 4.0.6
https-proxy-agent: 5.0.1
proxy-from-env: 2.1.0
transitivePeerDependencies:
- debug
- supports-color
balanced-match@4.0.4: {}
baseline-browser-mapping@2.11.14: {}
@@ -3004,12 +3146,23 @@ snapshots:
dependencies:
run-applescript: 7.1.0
call-bind-apply-helpers@1.0.2:
dependencies:
es-errors: 1.3.0
function-bind: 1.1.2
caniuse-lite@1.0.30001809: {}
chokidar@5.0.0:
dependencies:
readdirp: 5.1.1
combined-stream@1.0.8:
dependencies:
delayed-stream: 1.0.0
commander@15.0.0: {}
confbox@0.1.8: {}
confbox@0.2.4: {}
@@ -3081,12 +3234,20 @@ snapshots:
define-lazy-prop@3.0.0: {}
delayed-stream@1.0.0: {}
detect-libc@2.1.2: {}
dompurify@3.2.7:
optionalDependencies:
'@types/trusted-types': 2.0.7
dunder-proto@1.0.1:
dependencies:
call-bind-apply-helpers: 1.0.2
es-errors: 1.3.0
gopd: 1.2.0
echarts@6.1.0:
dependencies:
tslib: 2.3.0
@@ -3122,6 +3283,21 @@ snapshots:
error-stack-parser-es@1.0.5: {}
es-define-property@1.0.1: {}
es-errors@1.3.0: {}
es-object-atoms@1.1.2:
dependencies:
es-errors: 1.3.0
es-set-tostringtag@2.1.0:
dependencies:
es-errors: 1.3.0
get-intrinsic: 1.3.0
has-tostringtag: 1.0.2
hasown: 2.0.4
escalade@3.2.0: {}
escape-string-regexp@4.0.0: {}
@@ -3266,11 +3442,23 @@ snapshots:
flatted@3.4.4: {}
follow-redirects@1.16.0: {}
form-data@4.0.6:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
es-set-tostringtag: 2.1.0
hasown: 2.0.4
mime-types: 2.1.35
framework-utils@1.1.0: {}
fsevents@2.3.3:
optional: true
function-bind@1.1.2: {}
gensync@1.0.0-beta.2: {}
gesto@1.19.4:
@@ -3278,6 +3466,24 @@ snapshots:
'@daybrush/utils': 1.13.0
'@scena/event-emitter': 1.0.5
get-intrinsic@1.3.0:
dependencies:
call-bind-apply-helpers: 1.0.2
es-define-property: 1.0.1
es-errors: 1.3.0
es-object-atoms: 1.1.2
function-bind: 1.1.2
get-proto: 1.0.1
gopd: 1.2.0
has-symbols: 1.1.0
hasown: 2.0.4
math-intrinsics: 1.1.0
get-proto@1.0.1:
dependencies:
dunder-proto: 1.0.1
es-object-atoms: 1.1.2
glob-parent@5.1.2:
dependencies:
is-glob: 4.0.3
@@ -3286,10 +3492,29 @@ snapshots:
dependencies:
is-glob: 4.0.3
gopd@1.2.0: {}
graceful-fs@4.2.11: {}
has-symbols@1.1.0: {}
has-tostringtag@1.0.2:
dependencies:
has-symbols: 1.1.0
hasown@2.0.4:
dependencies:
function-bind: 1.1.2
hookable@5.5.3: {}
https-proxy-agent@5.0.1:
dependencies:
agent-base: 6.0.2
debug: 4.4.3
transitivePeerDependencies:
- supports-color
ignore@5.3.2: {}
ignore@7.0.6: {}
@@ -3496,6 +3721,8 @@ snapshots:
marked@14.0.0: {}
math-intrinsics@1.1.0: {}
memoize-one@6.0.0: {}
memorystream@0.3.1: {}
@@ -3507,6 +3734,12 @@ snapshots:
braces: 3.0.3
picomatch: 2.3.2
mime-db@1.52.0: {}
mime-types@2.1.35:
dependencies:
mime-db: 1.52.0
minimatch@10.2.6:
dependencies:
brace-expansion: 5.0.9
@@ -3518,6 +3751,10 @@ snapshots:
pkg-types: 1.3.1
ufo: 1.6.4
mockjs@1.1.0:
dependencies:
commander: 15.0.0
monaco-editor@0.55.1:
dependencies:
dompurify: 3.2.7
@@ -3677,6 +3914,8 @@ snapshots:
prettier@3.9.5: {}
proxy-from-env@2.1.0: {}
punycode@2.3.1: {}
quansync@0.2.11: {}
+1 -1
View File
@@ -9,7 +9,7 @@ const redoStack: any[] = shallowReactive([])
/** 所有 useUndoRedo() 共用,避免面板 batch 和工具栏 undo 各过各的 */
let activeBatch: { target: any; key: string; oldValue: any; newValue: any }[] | null = null
export function useUndoRedo() {
export const useUndoRedo = () => {
// 是否可以撤销
const canUndo = computed(() => undoStack.length > 0)
// 是否可以重做
+60
View File
@@ -0,0 +1,60 @@
import type { DataSourceSchema } from '@/schema/page'
import axios from 'axios'
export const useDataSource = (dataId: Ref<string>) => {
const dataSource = inject<Ref<DataSourceSchema[]>>('dataSource')
// 数据源轮询定时器
let timer: number | null = null
const data = ref<any>(null)
/** 已绑定且能查到的数据;没绑或找不到则 null,避免空数组盖掉默认 dataset */
const source = computed(() => {
return dataSource?.value.find((item) => item.id === dataId.value)
})
// 加载数据源数据,如果是 api 类型则发起请求
const loadData = async () => {
if (!source.value) return
// 如果是 api 类型且有 url,则发起请求获取数据
if (source.value.type === 'api' && source.value.url) {
const url = source.value.url
try {
const res = await axios.get(url, {
params: {
...source.value.params,
},
})
console.log('loadData res', res)
data.value = res.data
} finally {
if (source.value.interval) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
loadData()
}, source.value.interval)
}
}
} else {
data.value = source.value.data
}
}
onBeforeUnmount(() => {
if (timer) {
clearTimeout(timer)
}
})
// 监听数据源变化,立即加载数据
watch(source, loadData, { immediate: true })
return {
data,
loadData,
}
}
+2 -1
View File
@@ -13,7 +13,8 @@ defineOptions({
name: 'ScreenEditor',
})
const editorStore = useEditorStore()
const { panelVisible } = storeToRefs(editorStore)
const { panelVisible, dataSource } = storeToRefs(editorStore)
provide('dataSource', dataSource)
const materialWidth = computed(() => (panelVisible.value.material ? '260px' : '0'))
const propertyWidth = computed(() => (panelVisible.value.property ? '160px' : '0'))
+1 -1
View File
@@ -7,7 +7,7 @@ defineOptions({
name: 'MaterialPanel',
})
const activeGroup = ref('info')
const activeGroup = ref('charts')
const groups = getMaterialGroups()
@@ -0,0 +1,35 @@
<!-- 数据源 -->
<script setup lang="ts">
import { useEditorStore } from '@/stores/editor'
import { storeToRefs } from 'pinia'
import { useUndoRedo } from '@/composables/useUndoRedo'
defineOptions({
name: 'DataSource',
})
const editorStore = useEditorStore()
const { dataSource, selectedNode } = storeToRefs(editorStore)
const { applyChange } = useUndoRedo()
/** 当前节点绑定的数据源 id,写回节点而不是页面数据源列表 */
const selectedDataId = computed({
get: () => selectedNode.value?.dataId,
set: (id: string | undefined) => {
if (!selectedNode.value) return
applyChange(selectedNode.value, 'dataId', id)
},
})
</script>
<template>
<el-form>
<el-form-item label="数据源">
<el-select v-model="selectedDataId" class="w-full" clearable placeholder="请选择数据源">
<el-option v-for="item in dataSource" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-form>
</template>
<style scoped></style>
@@ -4,6 +4,7 @@ import { useEditorStore } from '@/stores/editor'
import { storeToRefs } from 'pinia'
import FormCreate from './FormCreate.vue'
import MonacoEditor from '@/components/MonacoEditor/index.vue'
import DataSource from '@/editor/panels/property/components/DataSource.vue'
defineOptions({
name: 'NodeProperty',
@@ -15,6 +16,7 @@ const { selectedNode } = storeToRefs(editorStore)
const setters = computed(() => {
return getMaterialSetters(selectedNode.value?.type || '') ?? []
})
const activeTab = ref('property')
// 属性分组默认全部展开
const activeNames = ref(['layout', 'component'])
@@ -72,6 +74,9 @@ const onConfirm = () => {
<span>{{ selectedNode?.name }}</span>
<span class="cursor-pointer" @click="showJson"><Icon icon="si:json-duotone" /></span>
</div>
<el-tabs v-model="activeTab" type="border-card" stretch>
<el-tab-pane label="属性" name="property">
<el-collapse v-model="activeNames">
<el-collapse-item title="布局属性" name="layout">
<FormCreate :setters="layoutSetters" :form-data="selectedNode" />
@@ -80,6 +85,12 @@ const onConfirm = () => {
<FormCreate :setters="setters" :form-data="selectedNode" />
</el-collapse-item>
</el-collapse>
</el-tab-pane>
<el-tab-pane label="数据源" name="data-source">
<DataSource />
</el-tab-pane>
</el-tabs>
<el-drawer v-model="visible" title="编辑 JSON" class="json-drawer" destroy-on-close>
<MonacoEditor v-model="jsonContent" lang="json" />
@@ -98,4 +109,12 @@ const onConfirm = () => {
min-height: 0;
padding: 0;
}
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item.is-active) {
color: #fff;
}
:deep(.el-tabs--border-card > .el-tabs__header .el-tabs__item:not(.is-disabled):hover) {
color: #fff;
}
</style>
+2 -2
View File
@@ -20,14 +20,14 @@ const { undo, redo, canUndo, canRedo } = useUndoRedo()
<Icon icon="mynaui:panel-left"></Icon>
</span>
<span
class="border p-1 rounded-lg"
class="border p-1 rounded-lg cursor-pointer"
:class="{ 'bg-white/20': panelVisible.property }"
@click="panelVisible.property = !panelVisible.property"
>
<Icon icon="mynaui:panel-right"></Icon>
</span>
<span
class="border p-1 rounded-lg"
class="border p-1 rounded-lg cursor-pointer"
:class="{ 'bg-white/20': panelVisible.layer }"
@click="panelVisible.layer = !panelVisible.layer"
>
+11 -5
View File
@@ -73,13 +73,19 @@ const onFileChange = (e: Event) => {
<template>
<div class="flex items-center justify-end gap-5">
<span class="border p-1 rounded-lg"><Icon icon="icon-park-outline:preview-open"></Icon></span>
<span class="border p-1 rounded-lg" @click="showJson"><Icon icon="si:json-line"></Icon></span>
<span class="border p-1 rounded-lg"><Icon icon="hugeicons:internet"></Icon></span>
<span class="border p-1 rounded-lg" @click="onImport" title="导入">
<span class="border p-1 rounded-lg cursor-pointer">
<Icon icon="icon-park-outline:preview-open"> </Icon>
</span>
<span class="border p-1 rounded-lg cursor-pointer" @click="showJson">
<Icon icon="si:json-line"> </Icon>
</span>
<span class="border p-1 rounded-lg cursor-pointer">
<Icon icon="hugeicons:internet"> </Icon>
</span>
<span class="border p-1 rounded-lg cursor-pointer" @click="onImport" title="导入">
<Icon icon="lets-icons:import"> </Icon>
</span>
<span class="border p-1 rounded-lg" @click="onExport" title="导出">
<span class="border p-1 rounded-lg cursor-pointer" @click="onExport" title="导出">
<Icon icon="lets-icons:export"> </Icon>
</span>
+1
View File
@@ -5,6 +5,7 @@ import App from './App.vue'
import router from './router'
import './styles/index.css'
import 'element-plus/theme-chalk/dark/css-vars.css'
import '@/mock/data.ts'
const app = createApp(App)
+20 -3
View File
@@ -1,18 +1,35 @@
<!-- echarts组件 -->
<script setup lang="ts">
import type { MaterialSchema } from '@/schema/materials'
import { init, type EChartsType } from 'echarts'
import { useDataSource } from '@/composables/usseDataSource'
defineOptions({
name: 'ChartMaterial',
})
let chart: EChartsType
const props = defineProps<{ schema: MaterialSchema }>()
const chartRef = useTemplateRef('chartRef')
let chart: EChartsType
const dataId = computed(() => props.schema.dataId!)
const { data } = useDataSource(dataId)
const option = computed(() => {
const _option = props.schema.props.option
return {
..._option,
dataset: {
..._option.dataset,
source: data.value ?? _option.dataset?.source,
},
}
})
watch(
() => props.schema.props.option,
option,
(newOption) => {
if (chartRef.value) {
chart.setOption(newOption)
@@ -24,7 +41,7 @@ watch(
onMounted(() => {
if (chartRef.value) {
chart = init(chartRef.value)
chart.setOption(props.schema.props.option)
chart.setOption(option.value)
// 监听窗口大小变化,自动调整图表大小
const resizeObserver = new ResizeObserver(() => {
+21
View File
@@ -0,0 +1,21 @@
import Mock from 'mockjs'
Mock.mock(/\/api\/data/, 'get', (options) => {
const url = new URL(options.url, location.origin)
const search = new URLSearchParams(url.search)
const date = search.get('date')
const data = Mock.mock({
'list|6': [
{
'label|+1': ['一月', '二月', '三月', '四月', '五月', '六月'],
'value|100-2000': 0,
date,
},
],
})
console.log('mock options', options)
return data.list
})
+1
View File
@@ -10,6 +10,7 @@ export interface MaterialSchema {
type: string
name: string
id: string
dataId?: string
locked?: boolean
layout: Layout
style?: Record<string, any>
+15
View File
@@ -7,8 +7,23 @@ interface CanvasSchema {
backgroundColor: string
}
// 数据源数据结构
export interface DataSourceSchema {
/** 数据源类型 api: 接口数据源, static: 静态数据源 */
type: 'api' | 'static'
id: string
name: string
data: any
url?: string
/** api 类型数据源的轮询间隔,单位毫秒,默认不轮询 */
interval?: number
/** 预设参数 */
params?: Record<string, any>
}
// 页面数据结构
export interface PageSchema {
canvas: CanvasSchema
nodes: MaterialSchema[]
dataSource: DataSourceSchema[]
}
+54
View File
@@ -21,6 +21,57 @@ export const useEditorStore = defineStore('editor', () => {
backgroundColor: '#ffffff10',
},
nodes: [],
dataSource: [
{
type: 'static',
id: '123123',
name: 'test1',
data: [
{
label: '一月',
value: 100,
},
{
label: '二月',
value: 200,
},
{
label: '三月',
value: 300,
},
],
},
{
type: 'static',
id: '123124',
name: 'test2',
data: [
{
label: '一月',
value: 1200,
},
{
label: '二月',
value: 2200,
},
{
label: '三月',
value: 3200,
},
],
},
{
type: 'api',
id: '123125',
name: 'test3',
url: '/api/data',
interval: 2000,
params: {
date: '2026-01-01',
},
data: [],
},
],
})
// 设置页面数据
@@ -32,6 +83,8 @@ export const useEditorStore = defineStore('editor', () => {
// 画布上的节点数据
const nodes = toRef(page.value, 'nodes')
// 数据源
const dataSource = toRef(page.value, 'dataSource')
// 当前选中的节点id
const selectedNodeIds = ref<string[]>([])
const selectedNodeId = computed(() => {
@@ -128,6 +181,7 @@ export const useEditorStore = defineStore('editor', () => {
selectedNodeId,
selectedNode,
selectedNodeIds,
dataSource,
addNode,
selectNode,
clearSelect,