实现 setting

This commit is contained in:
huangzhelong.byte 2025-03-26 17:06:02 +08:00
parent 32a4fbd096
commit 868b7cda6b
46 changed files with 1483 additions and 77 deletions

419
app/package-lock.json generated
View File

@ -28,7 +28,9 @@
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.0.3", "eslint-plugin-vue": "^8.0.3",
"prettier": "^2.4.1", "prettier": "^2.4.1",
"typescript": "~4.5.5" "typescript": "~4.5.5",
"unplugin-auto-import": "^0.17.5",
"unplugin-vue-components": "^0.26.0"
} }
}, },
"node_modules/@achrinza/node-ipc": { "node_modules/@achrinza/node-ipc": {
@ -60,6 +62,16 @@
"node": ">=6.0.0" "node": ">=6.0.0"
} }
}, },
"node_modules/@antfu/utils": {
"version": "0.7.10",
"resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.7.10.tgz",
"integrity": "sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
"version": "7.26.2", "version": "7.26.2",
"resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.26.2.tgz", "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.26.2.tgz",
@ -2105,6 +2117,42 @@
"url": "https://opencollective.com/popperjs" "url": "https://opencollective.com/popperjs"
} }
}, },
"node_modules/@rollup/pluginutils": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz",
"integrity": "sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0",
"estree-walker": "^2.0.2",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
}
}
},
"node_modules/@rollup/pluginutils/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@sideway/address": { "node_modules/@sideway/address": {
"version": "4.1.5", "version": "4.1.5",
"resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz", "resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz",
@ -4802,6 +4850,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/confbox": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
"integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
"dev": true,
"license": "MIT"
},
"node_modules/connect-history-api-fallback": { "node_modules/connect-history-api-fallback": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
@ -6718,6 +6773,13 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/exsolve": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.4.tgz",
"integrity": "sha512-xsZH6PXaER4XoV+NiT7JHp1bJodJVT+cxeSH1G0f0tlT0lJqYuHUP3bUx2HtfTDvOagMINYp8rsqusxud3RXhw==",
"dev": true,
"license": "MIT"
},
"node_modules/fast-deep-equal": { "node_modules/fast-deep-equal": {
"version": "3.1.3", "version": "3.1.3",
"resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@ -8299,6 +8361,23 @@
"json5": "lib/cli.js" "json5": "lib/cli.js"
} }
}, },
"node_modules/local-pkg": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz",
"integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"mlly": "^1.7.3",
"pkg-types": "^1.2.1"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/locate-path": { "node_modules/locate-path": {
"version": "5.0.0", "version": "5.0.0",
"resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz", "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-5.0.0.tgz",
@ -8887,6 +8966,19 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/mlly": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz",
"integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.14.0",
"pathe": "^2.0.1",
"pkg-types": "^1.3.0",
"ufo": "^1.5.4"
}
},
"node_modules/module-alias": { "node_modules/module-alias": {
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmmirror.com/module-alias/-/module-alias-2.2.3.tgz", "resolved": "https://registry.npmmirror.com/module-alias/-/module-alias-2.2.3.tgz",
@ -9532,6 +9624,13 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/pathe": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
"integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
"dev": true,
"license": "MIT"
},
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
@ -9564,6 +9663,18 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/pkg-types": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz",
"integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"confbox": "^0.1.8",
"mlly": "^1.7.4",
"pathe": "^2.0.1"
}
},
"node_modules/portfinder": { "node_modules/portfinder": {
"version": "1.0.35", "version": "1.0.35",
"resolved": "https://registry.npmmirror.com/portfinder/-/portfinder-1.0.35.tgz", "resolved": "https://registry.npmmirror.com/portfinder/-/portfinder-1.0.35.tgz",
@ -10424,6 +10535,23 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/quansync": {
"version": "0.2.10",
"resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz",
"integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==",
"dev": true,
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/antfu"
},
{
"type": "individual",
"url": "https://github.com/sponsors/sxzz"
}
],
"license": "MIT"
},
"node_modules/queue-microtask": { "node_modules/queue-microtask": {
"version": "1.2.3", "version": "1.2.3",
"resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz", "resolved": "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz",
@ -10859,6 +10987,13 @@
"url": "https://opencollective.com/webpack" "url": "https://opencollective.com/webpack"
} }
}, },
"node_modules/scule": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
"integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
"dev": true,
"license": "MIT"
},
"node_modules/select-hose": { "node_modules/select-hose": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/select-hose/-/select-hose-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/select-hose/-/select-hose-2.0.0.tgz",
@ -11490,6 +11625,26 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/strip-literal": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz",
"integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"js-tokens": "^9.0.1"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/strip-literal/node_modules/js-tokens": {
"version": "9.0.1",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
"integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
"dev": true,
"license": "MIT"
},
"node_modules/stylehacks": { "node_modules/stylehacks": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz", "resolved": "https://registry.npmmirror.com/stylehacks/-/stylehacks-5.1.1.tgz",
@ -12017,6 +12172,13 @@
"node": ">=4.2.0" "node": ">=4.2.0"
} }
}, },
"node_modules/ufo": {
"version": "1.5.4",
"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz",
"integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==",
"dev": true,
"license": "MIT"
},
"node_modules/undici-types": { "node_modules/undici-types": {
"version": "6.20.0", "version": "6.20.0",
"resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.20.0.tgz", "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-6.20.0.tgz",
@ -12068,6 +12230,102 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/unimport": {
"version": "3.14.6",
"resolved": "https://registry.npmjs.org/unimport/-/unimport-3.14.6.tgz",
"integrity": "sha512-CYvbDaTT04Rh8bmD8jz3WPmHYZRG/NnvYVzwD6V1YAlvvKROlAeNDUBhkBGzNav2RKaeuXvlWYaa1V4Lfi/O0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rollup/pluginutils": "^5.1.4",
"acorn": "^8.14.0",
"escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3",
"fast-glob": "^3.3.3",
"local-pkg": "^1.0.0",
"magic-string": "^0.30.17",
"mlly": "^1.7.4",
"pathe": "^2.0.1",
"picomatch": "^4.0.2",
"pkg-types": "^1.3.0",
"scule": "^1.3.0",
"strip-literal": "^2.1.1",
"unplugin": "^1.16.1"
}
},
"node_modules/unimport/node_modules/confbox": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.1.tgz",
"integrity": "sha512-hkT3yDPFbs95mNCy1+7qNKC6Pro+/ibzYxtM2iqEigpf0sVw+bg4Zh9/snjsBcf990vfIsg5+1U7VyiyBb3etg==",
"dev": true,
"license": "MIT"
},
"node_modules/unimport/node_modules/escape-string-regexp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/unimport/node_modules/estree-walker": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/estree": "^1.0.0"
}
},
"node_modules/unimport/node_modules/local-pkg": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.1.tgz",
"integrity": "sha512-WunYko2W1NcdfAFpuLUoucsgULmgDBRkdxHxWQ7mK0cQqwPiy8E1enjuRBrhLtZkB5iScJ1XIPdhVEFK8aOLSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"mlly": "^1.7.4",
"pkg-types": "^2.0.1",
"quansync": "^0.2.8"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/unimport/node_modules/local-pkg/node_modules/pkg-types": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz",
"integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==",
"dev": true,
"license": "MIT",
"dependencies": {
"confbox": "^0.2.1",
"exsolve": "^1.0.1",
"pathe": "^2.0.3"
}
},
"node_modules/unimport/node_modules/picomatch": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/universalify": { "node_modules/universalify": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz",
@ -12088,6 +12346,165 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/unplugin": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz",
"integrity": "sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.14.0",
"webpack-virtual-modules": "^0.6.2"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/unplugin-auto-import": {
"version": "0.17.8",
"resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.17.8.tgz",
"integrity": "sha512-CHryj6HzJ+n4ASjzwHruD8arhbdl+UXvhuAIlHDs15Y/IMecG3wrf7FVg4pVH/DIysbq/n0phIjNHAjl7TG7Iw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@antfu/utils": "^0.7.10",
"@rollup/pluginutils": "^5.1.0",
"fast-glob": "^3.3.2",
"local-pkg": "^0.5.0",
"magic-string": "^0.30.10",
"minimatch": "^9.0.4",
"unimport": "^3.7.2",
"unplugin": "^1.11.0"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@nuxt/kit": "^3.2.2",
"@vueuse/core": "*"
},
"peerDependenciesMeta": {
"@nuxt/kit": {
"optional": true
},
"@vueuse/core": {
"optional": true
}
}
},
"node_modules/unplugin-auto-import/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/unplugin-auto-import/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/unplugin-vue-components": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.26.0.tgz",
"integrity": "sha512-s7IdPDlnOvPamjunVxw8kNgKNK8A5KM1YpK5j/p97jEKTjlPNrA0nZBiSfAKKlK1gWZuyWXlKL5dk3EDw874LQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@antfu/utils": "^0.7.6",
"@rollup/pluginutils": "^5.0.4",
"chokidar": "^3.5.3",
"debug": "^4.3.4",
"fast-glob": "^3.3.1",
"local-pkg": "^0.4.3",
"magic-string": "^0.30.3",
"minimatch": "^9.0.3",
"resolve": "^1.22.4",
"unplugin": "^1.4.0"
},
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@babel/parser": "^7.15.8",
"@nuxt/kit": "^3.2.2",
"vue": "2 || 3"
},
"peerDependenciesMeta": {
"@babel/parser": {
"optional": true
},
"@nuxt/kit": {
"optional": true
}
}
},
"node_modules/unplugin-vue-components/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/unplugin-vue-components/node_modules/local-pkg": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz",
"integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/unplugin-vue-components/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/unplugin/node_modules/webpack-virtual-modules": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
"dev": true,
"license": "MIT"
},
"node_modules/update-browserslist-db": { "node_modules/update-browserslist-db": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "resolved": "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",

View File

@ -28,6 +28,8 @@
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.0.3", "eslint-plugin-vue": "^8.0.3",
"prettier": "^2.4.1", "prettier": "^2.4.1",
"typescript": "~4.5.5" "typescript": "~4.5.5",
"unplugin-auto-import": "^0.17.5",
"unplugin-vue-components": "^0.26.0"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -1,8 +1,8 @@
@font-face { @font-face {
font-family: "iconfont"; /* Project id 4870215 */ font-family: "iconfont"; /* Project id 4870215 */
src: url('iconfont.woff2?t=1742911403305') format('woff2'), src: url('iconfont.woff2?t=1742978562991') format('woff2'),
url('iconfont.woff?t=1742911403305') format('woff'), url('iconfont.woff?t=1742978562991') format('woff'),
url('iconfont.ttf?t=1742911403305') format('truetype'); url('iconfont.ttf?t=1742978562991') format('truetype');
} }
.iconfont { .iconfont {
@ -13,6 +13,38 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.icon-company:before {
content: "\e6f5";
}
.icon-token:before {
content: "\e68f";
}
.icon-url-line:before {
content: "\ea38";
}
.icon-llm:before {
content: "\e8be";
}
.icon-bg-colors:before {
content: "\e800";
}
.icon-i18n:before {
content: "\e601";
}
.icon-weixin:before {
content: "\e600";
}
.icon-QQ:before {
content: "\e882";
}
.icon-debug:before { .icon-debug:before {
content: "\e76d"; content: "\e76d";
} }

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

View File

@ -0,0 +1,22 @@
<svg width="1080" height="1080" viewBox="0 0 1080 1080" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M515.09 725.824L472.006 824.503C455.444 862.434 402.954 862.434 386.393 824.503L343.308 725.824C304.966 638.006 235.953 568.104 149.868 529.892L31.2779 477.251C-6.42601 460.515 -6.42594 405.665 31.2779 388.929L146.164 337.932C234.463 298.737 304.714 226.244 342.401 135.431L386.044 30.2693C402.239 -8.75637 456.159 -8.75646 472.355 30.2692L515.998 135.432C553.685 226.244 623.935 298.737 712.234 337.932L827.121 388.929C864.825 405.665 864.825 460.515 827.121 477.251L708.53 529.892C622.446 568.104 553.433 638.006 515.09 725.824Z" fill="url(#paint0_radial_2525_777)"/>
<path d="M915.485 1036.98L903.367 1064.75C894.499 1085.08 866.349 1085.08 857.481 1064.75L845.364 1036.98C823.765 987.465 784.862 948.042 736.318 926.475L698.987 909.889C678.802 900.921 678.802 871.578 698.987 862.61L734.231 846.951C784.023 824.829 823.623 783.947 844.851 732.75L857.294 702.741C865.966 681.826 894.882 681.826 903.554 702.741L915.997 732.75C937.225 783.947 976.826 824.829 1026.62 846.951L1061.86 862.61C1082.05 871.578 1082.05 900.921 1061.86 909.889L1024.53 926.475C975.987 948.042 937.083 987.465 915.485 1036.98Z" fill="url(#paint1_radial_2525_777)"/>
<defs>
<radialGradient id="paint0_radial_2525_777" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(670.447 474.006) rotate(78.858) scale(665.5 665.824)">
<stop stop-color="#1BA1E3"/>
<stop offset="0.0001" stop-color="#1BA1E3"/>
<stop offset="0.300221" stop-color="#5489D6"/>
<stop offset="0.545524" stop-color="#9B72CB"/>
<stop offset="0.825372" stop-color="#D96570"/>
<stop offset="1" stop-color="#F49C46"/>
</radialGradient>
<radialGradient id="paint1_radial_2525_777" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(670.447 474.006) rotate(78.858) scale(665.5 665.824)">
<stop stop-color="#1BA1E3"/>
<stop offset="0.0001" stop-color="#1BA1E3"/>
<stop offset="0.300221" stop-color="#5489D6"/>
<stop offset="0.545524" stop-color="#9B72CB"/>
<stop offset="0.825372" stop-color="#D96570"/>
<stop offset="1" stop-color="#F49C46"/>
</radialGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<svg viewBox="0 0 824 834" fill="none" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="path_1" d="M300 0C465.708 0 600 134.292 600 300L600 300C600 465.708 465.708 600 300 600L300 600C134.292 600 0 465.708 0 300L0 300C0 134.292 134.292 0 300 0Z" />
<linearGradient id="gradient_2" gradientUnits="userSpaceOnUse" x1="300" y1="0" x2="300" y2="600">
<stop offset="0" stop-color="#A1A7F6" />
<stop offset="1" stop-color="#FFFFFF" stop-opacity="0.2" />
</linearGradient>
</defs>
<g>
<g transform="translate(186 116)">
<use p4:href="#path_1" fill="#5A00FF" xmlns:p4="http://www.w3.org/1999/xlink" />
<use p4:href="#path_1" fill="url(#gradient_2)" xmlns:p4="http://www.w3.org/1999/xlink" />
</g>
<path d="M0 110.5C0 49.4725 49.4725 0 110.5 0C171.527 0 221 49.4725 221 110.5C221 171.527 171.527 221 110.5 221C49.4725 221 0 171.527 0 110.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.431" transform="translate(445 458)" />
<path d="M0 55.5C0 24.8482 24.8482 0 55.5 0C86.1518 0 111 24.8482 111 55.5C111 86.1518 86.1518 111 55.5 111C24.8482 111 0 86.1518 0 55.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.431" transform="translate(199 386)" />
<path d="M0 182.5C0 81.708 81.708 0 182.5 0C283.292 0 365 81.708 365 182.5C365 283.292 283.292 365 182.5 365C81.708 365 0 283.292 0 182.5Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.424" transform="translate(339 156)" />
<path d="M0 57C0 25.5198 25.5198 0 57 0C88.4802 0 114 25.5198 114 57C114 88.4802 88.4802 114 57 114C25.5198 114 0 88.4802 0 57Z" fill="#FFFFFF" fill-rule="evenodd" fill-opacity="0.431" transform="translate(521 188)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -5,7 +5,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.svg">
<link rel="stylesheet" href="default-dark.css"> <link rel="stylesheet" href="default-dark.css">
<link rel="stylesheet" href="vscode.css"> <link rel="stylesheet" href="vscode.css">
<link rel="stylesheet" href="mcp.css"> <link rel="stylesheet" href="mcp.css">

View File

@ -11,12 +11,17 @@ import { Connection } from './components/sidebar/sidebar';
import Sidebar from '@/components/sidebar/index.vue'; import Sidebar from '@/components/sidebar/index.vue';
import MainPanel from '@/components/main-panel/index.vue'; import MainPanel from '@/components/main-panel/index.vue';
import { setDefaultCss } from './hook/css';
import { pinkLog } from './views/setting/util';
onMounted(() => { onMounted(() => {
setDefaultCss();
document.addEventListener('click', () => { document.addEventListener('click', () => {
Connection.showPanel = false; Connection.showPanel = false;
}); });
pinkLog('OpenMCP Client 启动');
}) })
</script> </script>

View File

@ -31,6 +31,7 @@ defineComponent({ name: 'main-panel' });
justify-content: center; justify-content: center;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
min-width: 800px;
height: 100%; height: 100%;
margin-left: 20px; margin-left: 20px;
} }

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="mcp-title"> <div class="mcp-title">
<img src="/protocol.svg" alt=""> <img src="/images/openmcp.svg" alt="">
<div>OpenMCP</div> <div>OpenMCP</div>
</div> </div>
</template> </template>

View File

@ -8,13 +8,14 @@
@click="gotoOption(item.ident)" @click="gotoOption(item.ident)"
> >
<span :class="`iconfont ${item.icon}`"></span> <span :class="`iconfont ${item.icon}`"></span>
<span>{{ item.name }}</span> <span>{{ t(item.ident) }}</span>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute, useRouter } from 'vue-router'; import { useRoute, useRouter } from 'vue-router';
import { sidebarItems } from './sidebar'; import { sidebarItems } from './sidebar';
@ -22,6 +23,7 @@ defineComponent({ name: 'sidebar-item-container' });
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const { t } = useI18n();
function isActive(name: string) { function isActive(name: string) {
return route.name === name; return route.name === name;

View File

@ -1,28 +1,20 @@
import { reactive } from 'vue'; import { reactive } from 'vue';
import I18n from '@/i18n';
const { t } = I18n.global;
export const sidebarItems = reactive([ export const sidebarItems = reactive([
{ {
icon: 'icon-debug', icon: 'icon-debug',
name: t('debug'),
ident: 'debug' ident: 'debug'
}, },
{ {
icon: 'icon-plugin', icon: 'icon-plugin',
name: t('connect'),
ident: 'connect' ident: 'connect'
}, },
{ {
icon: 'icon-setting', icon: 'icon-setting',
name: t('setting'),
ident: 'setting' ident: 'setting'
}, },
{ {
icon: 'icon-about', icon: 'icon-about',
name: t('about'),
ident: 'about' ident: 'about'
} }
]); ]);

227
app/src/hook/color.ts Normal file
View File

@ -0,0 +1,227 @@
interface RgbColor {
r: number;
g: number;
b: number;
a?: number; // 透明度,值介于 0 - 1 之间
}
/**
* @description rgb
* @param colorString #1e90ff rgba(0, 206, 209, 1)
* @returns RgbColor undefined
*/
export function parseColor(colorString: string): RgbColor | undefined {
// 检查是否是十六进制颜色
if (colorString.startsWith('#')) {
let hex = colorString.slice(1);
if (hex.length === 3) {
hex = hex.split('').map(c => c + c).join('');
}
const r = parseInt(hex.slice(0, 2), 16);
const g = parseInt(hex.slice(2, 4), 16);
const b = parseInt(hex.slice(4, 6), 16);
return { r, g, b };
}
// 检查是否是 RGBA 颜色
else if (colorString.startsWith('rgba')) {
const matches = colorString.match(/rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d+(\.\d+)?)\)/);
if (matches) {
const r = parseInt(matches[1], 10);
const g = parseInt(matches[2], 10);
const b = parseInt(matches[3], 10);
const a = parseFloat(matches[4]);
return { r, g, b, a };
}
}
// 检查是否是 RGB 颜色
else if (colorString.startsWith('rgb')) {
const matches = colorString.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
if (matches) {
const r = parseInt(matches[1], 10);
const g = parseInt(matches[2], 10);
const b = parseInt(matches[3], 10);
return { r, g, b };
}
}
return undefined;
}
/**
* @description
* @param rgb
* @param percent 0 - 100
* @returns RgbColor
*/
export function increaseBrightness(rgb: RgbColor, percent: number): RgbColor {
// 确保 percent 在 0 到 100 之间
percent = Math.max(0, Math.min(100, percent));
// 计算每个颜色分量的增量
const increment = (percent / 100) * 255;
// 提升每个颜色分量的亮度
const r = Math.min(255, Math.round(rgb.r + increment));
const g = Math.min(255, Math.round(rgb.g + increment));
const b = Math.min(255, Math.round(rgb.b + increment));
return { r, g, b };
}
/**
* @description
* @param rgb
* @param percent 0 - 100
* @returns RgbColor
*/
export function lowerBrightness(rgb: RgbColor, percent: number): RgbColor {
// 确保 percent 在 0 到 100 之间
percent = Math.max(0, Math.min(100, percent));
// 计算每个颜色分量的增量
const increment = (percent / 100) * 255;
// 降低每个颜色分量的亮度
const r = Math.max(0, Math.round(rgb.r - increment));
const g = Math.max(0, Math.round(rgb.g - increment));
const b = Math.max(0, Math.round(rgb.b - increment));
return { r, g, b };
}
/**
* @description gamma
* @param c 0 - 255
* @returns
*/
function gammaCorrected(c: number): number {
c /= 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
}
/**
* @description
* @param r
* @param g 绿
* @param b
* @returns true false
*/
export function isLightColorTheme(r: number, g: number, b: number): boolean {
r = gammaCorrected(r);
g = gammaCorrected(g);
b = gammaCorrected(b);
const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
return luminance > 0.5;
}
/**
* @description rgb css
* @param rgb
* @returns RGB CSS
*/
export function toRgbCssString(rgb: RgbColor): string {
const { r, g, b } = rgb;
return `rgb(${r}, ${g}, ${b})`;
}
/**
* @description rgba css
* @param rgb
* @returns RGBA CSS
*/
export function toRgbaCssString(rgb: RgbColor): string {
const { r, g, b, a } = rgb;
return `rgba(${r}, ${g}, ${b}, ${a ?? 1})`;
}
interface ComputedColorOption {
BaseForegroundColorMacroName?: string;
BaseBackgroundColorMacroName?: string;
}
interface GetColorOption {
mode?: 'pdf' | 'svg';
}
export class MacroColor {
private option: ComputedColorOption;
private rootStyles: CSSStyleDeclaration;
private theme: 'light' | 'dark';
public foregroundColor: RgbColor | undefined;
public backgroundColor: RgbColor | undefined;
public foregroundColorString: string;
public backgroundColorString: string;
constructor(option: ComputedColorOption = {}) {
this.option = option;
this.rootStyles = getComputedStyle(document.documentElement);
const foregroundColorString = this.rootStyles.getPropertyValue(option.BaseForegroundColorMacroName || '--foreground');
const backgroundColorString = this.rootStyles.getPropertyValue(option.BaseBackgroundColorMacroName || '--background');
this.foregroundColor = parseColor(foregroundColorString);
this.backgroundColor = parseColor(backgroundColorString);
this.foregroundColorString = foregroundColorString;
this.backgroundColorString = backgroundColorString;
if (this.backgroundColor) {
const isLight = isLightColorTheme(this.backgroundColor.r, this.backgroundColor.g, this.backgroundColor.b);
this.theme = isLight ? 'light' : 'dark';
} else {
this.theme = 'light'; // 默认主题
}
}
/**
* @description
* @param macroName CSS
* @param option
* @returns
*/
getColor(macroName: string, option: GetColorOption = {}): string {
const theme = this.theme;
const rootStyles = this.rootStyles;
const mode = option.mode || 'svg';
if (mode === 'svg') {
// svg 模式下,导出的效果和 webview 渲染效果基本一致,直接导出即可
return rootStyles.getPropertyValue(macroName);
}
// pdf 模式需要对黑色主题的几个特殊颜色进行处理,并对所有透明颜色进行混合处理
switch (macroName) {
case '--foreground':
case '--wire-color':
case '--cross-dot-color':
if (theme === 'dark') {
return '#2D323B';
}
}
const colorString = rootStyles.getPropertyValue(macroName);
if (!colorString) {
// 如果 macroName 不存在,返回空字符串
return colorString;
}
const color = parseColor(colorString);
if (!color) {
return colorString;
}
if (!color.a) {
// 不具有透明通道,在 pdf 中渲染效果和 svg 中一致,直接返回即可
return toRgbCssString(color);
}
// 透明度插值公式为 c = c_f * alpha + c_b * (1 - alpha)
const mixedBg = parseColor('#ffffff')!; // 假设背景为白色
const mixedColor = {
r: Math.round(color.r * color.a + mixedBg.r * (1 - color.a)),
g: Math.round(color.g * color.a + mixedBg.g * (1 - color.a)),
b: Math.round(color.b * color.a + mixedBg.b * (1 - color.a)),
};
return toRgbCssString(mixedColor);
}
}

55
app/src/hook/css.ts Normal file
View File

@ -0,0 +1,55 @@
import { isLightColorTheme, parseColor } from "./color";
export function setDefaultCss() {
// 改变默认颜色
document.body.style.setProperty('--el-color-primary', 'var(--main-color)');
document.body.style.setProperty('--el-color-primary-light-9', 'var(--main-color)');
document.body.style.setProperty('--el-color-primary-light-3', 'var(--main-color)');
document.body.style.setProperty('--el-text-color-secondary', 'var(--foreground)');
document.body.style.setProperty('--el-text-color-regular', 'var(--foreground)');
document.body.style.setProperty('--el-border-color', 'var(--main-color)');
document.body.style.setProperty('--el-fill-color-blank', 'var(--sidebar)');
document.body.style.setProperty('--el-fill-color-light', 'var(--vscode-button-hoverBackground)');
document.body.style.setProperty('--el-switch-on-color', 'var(--main-color)');
document.body.style.setProperty('--el-border', 'var(--sidebar)');
document.body.style.setProperty('--el-border-color-light', 'var(--sidebar)');
document.body.style.setProperty('--el-border-color-lighter', 'var(--sidebar)');
document.body.style.setProperty('--el-bg-color-overlay', 'var(--sidebar)');
document.body.style.setProperty('--el-color-info-light-9', 'var(--main-color)');
document.body.style.setProperty('--el-color-info', 'var(--foreground)');
document.body.style.setProperty('--el-color-info-light-8', 'var(--main-color)');
document.body.style.setProperty('--el-fill-color-light', 'var(--sidebar-item-selected)');
document.body.style.setProperty('--el-color-primary-dark-2', 'var(--main-light-color)');
// document.body.style.setProperty('--el-color-white', 'var(--background)');
// 设置全局宏
document.body.style.setProperty('--time-scale-height', '30px');
document.body.style.setProperty('--vcd-render-padding', '30px');
document.body.style.setProperty('--sidebar-width', '330px');
document.body.style.setProperty('--toolbar-height', '60px');
// 下面是 get style
const style = getComputedStyle(document.documentElement);
// 根据颜色亮度来设置额外的宏
const bgColorString = style.getPropertyValue('--background');
const color = parseColor(bgColorString);
if (!color) {
return;
}
const { r, g, b } = color;
if (isLightColorTheme(r, g, b)) {
setExtraLightColorCss();
} else {
setExtraDarkColorCss();
}
}
function setExtraLightColorCss() {
document.body.style.setProperty('--vline-stroke-color', '#ddd');
}
function setExtraDarkColorCss() {
document.body.style.setProperty('--vline-stroke-color', '#333');
}

31
app/src/hook/global.ts Normal file
View File

@ -0,0 +1,31 @@
import { reactive } from 'vue';
import * as Color from './color';
type SupportLanguage = 'zh' | 'en' | 'zhTw' | 'ja' | 'de' | 'ko' | 'ru' | 'fr' | 'ar';
interface IGlobalSetting {
language: SupportLanguage
}
export const globalSetting = reactive<IGlobalSetting>({
language: 'zh'
});
let themeColor: 'light' | 'dark' | undefined = undefined;
export function getThemeColor(): 'light' | 'dark' {
if (themeColor) {
return themeColor;
}
const rootStyles = getComputedStyle(document.documentElement);
const backgroundColorString = rootStyles.getPropertyValue('--background');
const backgroundColor = Color.parseColor(backgroundColorString);
if (backgroundColor) {
const isLight = Color.isLightColorTheme(backgroundColor.r, backgroundColor.g, backgroundColor.b);
themeColor = isLight ? 'light' : 'dark';
return themeColor;
}
return 'dark';
}

View File

@ -106,5 +106,11 @@
"connected": "متصل", "connected": "متصل",
"disconnected": "غير متصل", "disconnected": "غير متصل",
"debug": "تصحيح", "debug": "تصحيح",
"connect": "اتصال" "connect": "اتصال",
"setting.general-color-setting": "إعدادات الألوان العامة",
"choose-a-project-debug": "اختر مشروعًا لتصحيحه",
"model": "النموذج",
"server-provider": "مزود الخدمة",
"api-root-url": "مسار جذر API",
"api-token": "مفتاح API"
} }

View File

@ -106,5 +106,11 @@
"connected": "Verbunden", "connected": "Verbunden",
"disconnected": "Getrennt", "disconnected": "Getrennt",
"debug": "Debuggen", "debug": "Debuggen",
"connect": "Verbinden" "connect": "Verbinden",
"setting.general-color-setting": "Allgemeine Farbeinstellungen",
"choose-a-project-debug": "Wählen Sie ein Projekt zum Debuggen aus",
"model": "Modell",
"server-provider": "Dienstanbieter",
"api-root-url": "API-Stammpfad",
"api-token": "API-Schlüssel"
} }

File diff suppressed because one or more lines are too long

View File

@ -106,5 +106,11 @@
"connected": "Connecté", "connected": "Connecté",
"disconnected": "Déconnecté", "disconnected": "Déconnecté",
"debug": "Déboguer", "debug": "Déboguer",
"connect": "Connexion" "connect": "Connexion",
"setting.general-color-setting": "Paramètres de couleur généraux",
"choose-a-project-debug": "Sélectionnez un projet à déboguer",
"model": "Modèle",
"server-provider": "Fournisseur de services",
"api-root-url": "Chemin racine de l'API",
"api-token": "Clé API"
} }

View File

@ -106,5 +106,11 @@
"connected": "接続済み", "connected": "接続済み",
"disconnected": "切断されました", "disconnected": "切断されました",
"debug": "デバッグ", "debug": "デバッグ",
"connect": "接続" "connect": "接続",
"setting.general-color-setting": "一般的な色設定",
"choose-a-project-debug": "デバッグするプロジェクトを選択",
"model": "モデル",
"server-provider": "サービスプロバイダー",
"api-root-url": "APIルートパス",
"api-token": "APIキー"
} }

View File

@ -106,5 +106,11 @@
"connected": "연결됨", "connected": "연결됨",
"disconnected": "연결 해제됨", "disconnected": "연결 해제됨",
"debug": "디버그", "debug": "디버그",
"connect": "연결" "connect": "연결",
"setting.general-color-setting": "일반 색상 설정",
"choose-a-project-debug": "디버깅할 프로젝트 선택",
"model": "모델",
"server-provider": "서비스 제공자",
"api-root-url": "API 루트 경로",
"api-token": "API 키"
} }

View File

@ -106,5 +106,11 @@
"connected": "Подключено", "connected": "Подключено",
"disconnected": "Отключено", "disconnected": "Отключено",
"debug": "Отладка", "debug": "Отладка",
"connect": "Подключение" "connect": "Подключение",
"setting.general-color-setting": "Общие настройки цвета",
"choose-a-project-debug": "Выберите проект для отладки",
"model": "Модель",
"server-provider": "Поставщик услуг",
"api-root-url": "Корневой путь API",
"api-token": "API-ключ"
} }

View File

@ -106,5 +106,11 @@
"connected": "已连接", "connected": "已连接",
"disconnected": "未连接", "disconnected": "未连接",
"debug": "调试", "debug": "调试",
"connect": "连接" "connect": "连接",
"setting.general-color-setting": "通用颜色设置",
"choose-a-project-debug": "选择一个项目进行调试",
"model": "模型",
"server-provider": "服务提供者",
"api-root-url": "API 根路径",
"api-token": "API 密钥"
} }

View File

@ -106,5 +106,11 @@
"connected": "已連線", "connected": "已連線",
"disconnected": "已斷開連接", "disconnected": "已斷開連接",
"debug": "偵錯", "debug": "偵錯",
"connect": "連接" "connect": "連接",
"setting.general-color-setting": "通用顏色設定",
"choose-a-project-debug": "選擇一個項目進行調試",
"model": "模型",
"server-provider": "服務提供者",
"api-root-url": "API 根路徑",
"api-token": "API 密鑰"
} }

View File

@ -2,16 +2,32 @@
<div class="about-container"> <div class="about-container">
<span> <span>
<img src="/protocol.svg" alt=""> <img src="/images/openmcp.svg" alt="">
</span> </span>
OpenMCP Client 0.0.1 @锦恢 开发 <p>
OpenMCP Client 0.0.1 OpenMCP@<a href="https://www.zhihu.com/people/can-meng-zhong-de-che-xian">锦恢</a> 开发
</p>
<p>软件已开源 <a href="https://github.com/LSTM-Kirigaya/openmcp-client" target="_blank"> <p>
软件已开源 <a href="https://github.com/LSTM-Kirigaya/openmcp-client" target="_blank">
LSTM-Kirigaya/openmcp-client LSTM-Kirigaya/openmcp-client
</a></p> </a>
<br>
请遵循开源协议进行分发和二次开发
</p>
<p>请遵循开源协议进行分发和二次开发</p> <p>
如果感兴趣欢迎加入我们的QQ群和我们讨论
</p>
<el-button
class="join-qq"
type="primary"
@click="joinQQGroup('https://qm.qq.com/cgi-bin/qm/qr?k=C6ZUTZvfqWoI12lWe7L93cWa1hUsuVT0&jump_from=webapi&authKey=McW6B1ogTPjPDrCyGttS890tMZGQ1KB3QLuG4aqVNRaYp4vlTSgf2c6dMcNjMuBD')"
>
<span class="iconfont icon-QQ"></span>
加入 OpenMCP 技术群
</el-button>
</div> </div>
</template> </template>
@ -19,6 +35,11 @@
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
defineComponent({ name: 'about' }); defineComponent({ name: 'about' });
function joinQQGroup(url: string) {
window.open(url, '_blank');
}
</script> </script>
<style> <style>
@ -30,4 +51,23 @@ defineComponent({ name: 'about' });
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
} }
.about-container > span > img {
height: 150px;
width: 150px;
}
.about-container > .qr-code {
height: 180px;
border: 2px solid transparent; /* 设置边框宽度,但颜色透明 */
border-image: linear-gradient(to bottom right, #7DDCEB, #CB81DA);
border-image-slice: 1; /* 确保渐变覆盖整个边框 */
background: white; /* 可选:防止内容穿透 */
}
.join-qq .iconfont {
font-size: 20px;
margin-right: 6px;
}
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="debug-welcome"> <div class="debug-welcome">
<span>选择一个项目进行调试</span> <span>{{ t('choose-a-project-debug') }}</span>
<div class="welcome-container"> <div class="welcome-container">
<span <span
class="debug-option" class="debug-option"
@ -99,4 +99,8 @@ const debugOptions = [
font-size: 48px; font-size: 48px;
} }
.debug-welcome {
user-select: none;
}
</style> </style>

View File

@ -0,0 +1,94 @@
<template>
<div class="setting-section">
<h2>{{ "API" }}</h2>
<div class="setting-option">
<span>
<span class="iconfont icon-company"></span>
<span class="option-title">{{ t('server-provider') }}</span>
</span>
<div style="width: 160px;">
<el-select
name="language-setting"
class="language-setting"
v-model="llmManager.currentModelIndex"
@change="onmodelchange">
<el-option v-for="(option, index) in llms" :value="index" :label="option.name" :key="index">
<div class="llm-option">
<img :src="option.icon" alt="">
<span>{{ option.name }}</span>
</div>
</el-option>
</el-select>
</div>
</div>
<!-- 根据不同模型展示不同的接入点 -->
<div v-if="false">
</div>
<div v-else>
<div class="setting-option">
<span>
<span class="iconfont icon-llm"></span>
<span class="option-title">{{ t('model') }}</span>
</span>
<div style="width: 160px;">
<el-select name="language-setting" class="language-setting"
v-model="llms[llmManager.currentModelIndex].userModel"
@change="onmodelchange"
>
<el-option v-for="option in llms[llmManager.currentModelIndex].models"
:value="option"
:label="option"
:key="option"
></el-option>
</el-select>
</div>
</div>
<div class="setting-option">
<span>
<span class="iconfont icon-url-line"></span>
<span class="option-title">{{ t('api-root-url') }}</span>
</span>
<div style="width: 240px;">
<el-input
v-model="llms[llmManager.currentModelIndex].baseUrl"
placeholder="https://"
/>
</div>
</div>
<div class="setting-option">
<span>
<span class="iconfont icon-token"></span>
<span class="option-title">{{ t('api-token') }}</span>
</span>
<div style="width: 240px;">
<el-input
v-model="llms[llmManager.currentModelIndex].userToken"
show-password
/>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { defineComponent } from 'vue';
import { llmManager, llms, onmodelchange } from './llm';
import { useI18n } from 'vue-i18n';
defineComponent({ name: 'api' });
const { t } = useI18n();
</script>
<style>
</style>

View File

@ -0,0 +1,42 @@
<template>
<div class="setting-section">
<h2>{{ t('general-setting') }}</h2>
<div class="setting-option">
<span>
<span class="iconfont icon-i18n"></span>
<span class="option-title">{{ t('language-setting') }}</span>
</span>
<div style="width: 100px;">
<el-select name="language-setting" class="language-setting" v-model="locale" @change="onlanguagechange">
<el-option v-for="option in languageSetting.options" :value="option.value" :label="option.text"
:key="option.value">
</el-option>
</el-select>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { defineComponent, ref } from 'vue';
import { languageSetting } from './language';
import { useI18n } from 'vue-i18n';
import { globalSetting } from '@/hook/global';
defineComponent({ name: 'appearance' });
const { t, locale } = useI18n();
locale.value = globalSetting.language;
const currentLanguage = ref('简体中文');
function onlanguagechange(code: string) {
const option = languageSetting.options.find(item => item.value === code);
if (option) {
currentLanguage.value = option.text;
}
// languageDialogShow.value = true;
}
</script>
<style></style>

View File

@ -0,0 +1,45 @@
import { reactive } from 'vue';
import i18n from '@/i18n';
import { parseColor } from '@/hook/color';
import { globalSetting } from '@/hook/global';
const { t, locale } = i18n.global;
locale.value = globalSetting.language;
export const colorManager = reactive({
mainColor: 'white',
initColor() {
const rootStyles = getComputedStyle(document.documentElement);
this.mainColor = rootStyles.getPropertyValue('--main-color');
}
});
/**
* @description
* @param {string} colorString
*/
export function onGeneralColorChange(colorString: string) {
const color = parseColor(colorString);
if (!color) {
return;
}
const { r, g, b } = color;
document.documentElement.style.setProperty(
'--main-color', `rgb(${r}, ${g}, ${b})`);
document.documentElement.style.setProperty(
'--main-light-color', `rgba(${r}, ${g}, ${b}, 0.7)`);
}
export const predefinedColors = [
'#ff4500',
'#ff8c00',
'#ffd700',
'#90ee90',
'#00ced1',
'#1e90ff',
'#c71585'
];

View File

@ -0,0 +1,29 @@
<template>
<div class="setting-section">
<h2>{{ t('appearance-setting') }}</h2>
<div class="setting-option">
<span class="option-title">
<span class="iconfont icon-bg-colors"></span>
{{ t('setting.general-color-setting') }}
</span>
<div class="option-group">
<div style="height: 20px; width: 20px;"></div>
<el-color-picker v-model="colorManager.mainColor" @change="onGeneralColorChange"
:predefine="predefinedColors" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { defineComponent } from 'vue';
import { colorManager, onGeneralColorChange, predefinedColors } from './color';
import { useI18n } from 'vue-i18n';
defineComponent({ name: 'general' });
const { t } = useI18n();
</script>
<style></style>

View File

@ -1,12 +1,116 @@
<template> <template>
<div></div> <div class="setting-container">
<General></General>
<Api></Api>
<Appearance></Appearance>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { defineComponent } from 'vue'; import { defineComponent, ref, onMounted } from 'vue';
import { colorManager } from './color';
import General from './general.vue';
import Api from './api.vue';
import Appearance from './appearance.vue';
defineComponent({ name: 'setting' }); defineComponent({ name: 'setting' });
onMounted(() => {
colorManager.initColor();
});
</script> </script>
<style> <style>
.setting-container {
position: relative;
width: 60%;
padding: 5px 20px;
height: fit-content;
display: flex;
flex-direction: column;
justify-content: center;
border-radius: .5em;
}
.setting-drag {
height: 20px;
width: 100%;
background-color: var(--main-color);
position: relative;
border-radius: .5em .5em 0 0;
}
.setting-container .el-scrollbar {
width: 400px;
user-select: none;
}
.setting-section {
padding: 10px;
margin: 10px;
border-radius: .3em;
min-height: 50px;
}
.setting-option {
margin: 3px;
margin-bottom: 10px;
padding: 8px 12px;
height: 40px;
border-radius: .5em;
background-color: var(--background);
display: flex;
align-items: center;
justify-content: space-between;
font-size: 0.9rem;
}
.setting-option .iconfont {
margin-right: 8px;
font-size: 15px;
}
.option-group {
display: flex;
width: fit-content;
}
.option-title {
font-size: 0.8rem;
min-width: 80px;
margin-right: 12px;
user-select: none;
}
.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner,
.el-checkbox-button__inner {
font-size: 0.8rem !important;
}
.el-slider__button {
background-color: var(--background) !important;
}
.el-switch__core .el-switch__action {
background-color: var(--background) !important;
}
.el-slider__stop {
background-color: var(--vscode-foreground) !important;
}
.llm-option img {
height: 20px;
width: 20px;
margin-right: 7px;
}
.llm-option {
display: flex;
align-items: center;
margin: 2px;
}
</style> </style>

View File

@ -0,0 +1,42 @@
import { reactive } from 'vue';
export const languageSetting = reactive({
options: [
{
value: 'en',
text: 'English'
},
{
value: 'zh',
text: '简体中文'
},
{
value: 'zhTw',
text: '繁體中文'
},
{
value: 'ja',
text: '日本語'
},
{
value: 'ko',
text: '한국어'
},
{
value: 'de',
text: 'Deutsch'
},
{
value: 'fr',
text: 'Français'
},
{
value: 'ru',
text: 'Русский'
},
{
value: 'ar',
text: 'العربية'
}
]
});

View File

@ -0,0 +1,114 @@
import { reactive } from 'vue';
export const llms = reactive([
{
id: 'deepseek',
name: 'DeepSeek',
baseUrl: 'https://api.deepseek.com/v1',
models: ['deepseek-chat', 'deepseek-coder', 'deepseek-math'],
icon: '/images/deepseek.com.ico',
provider: 'DeepSeek',
isOpenAICompatible: true,
description: '深度求索推出的大模型,擅长中文和代码',
website: 'https://www.deepseek.com',
userToken: '',
userModel: 'deepseek-chat'
},
{
id: 'openai',
name: 'OpenAI',
baseUrl: 'https://api.openai.com/v1',
models: ['gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo'],
icon: '/images/openai.com.ico',
provider: 'OpenAI',
isOpenAICompatible: true,
description: 'OpenAI官方API',
website: 'https://openai.com',
userToken: '',
userModel: 'gpt-4-turbo'
},
{
id: 'mistral',
name: 'Mistral',
baseUrl: 'https://api.mistral.ai/v1',
models: ['mistral-tiny', 'mistral-small', 'mistral-medium'],
icon: '/images/mistral.ai.ico',
provider: 'Mistral AI',
isOpenAICompatible: true,
description: '欧洲开源大模型代表',
website: 'https://mistral.ai',
userToken: '',
userModel: 'mistral-tiny'
},
{
id: 'ollama',
name: 'Ollama (Local)',
baseUrl: 'http://localhost:11434/v1',
models: ['llama2', 'mistral', 'codellama'],
icon: '/images/ollama.png',
provider: 'Ollama',
isOpenAICompatible: true,
description: '本地运行的大模型',
website: 'https://ollama.com',
userToken: '',
userModel: 'llama2'
},
{
id: 'groq',
name: 'Groq',
baseUrl: 'https://api.groq.com/openai/v1',
models: ['mixtral-8x7b-32768', 'llama2-70b-4096'],
icon: '/images/grok.com.png',
provider: 'Groq',
isOpenAICompatible: true,
description: '超高速推理API',
website: 'https://groq.com',
userToken: '',
userModel: 'mixtral-8x7b-32768'
},
{
id: 'perplexity',
name: 'Perplexity',
baseUrl: 'https://api.perplexity.ai/v1',
models: ['pplx-7b-online', 'pplx-70b-online'],
icon: '/images/perplexity.ai.ico',
provider: 'Perplexity AI',
isOpenAICompatible: true,
description: '联网搜索增强的大模型',
website: 'https://www.perplexity.ai',
userToken: '',
userModel: 'pplx-7b-online'
},
{
id: 'kimi',
name: 'Kimi Chat',
baseUrl: 'https://api.moonshot.cn/v1',
models: ['moonshot-v1-8k', 'moonshot-v1-32k', 'moonshot-v1-128k'],
icon: '/images/kimichat.cn.png',
provider: '月之暗面 (Moonshot AI)',
isOpenAICompatible: true,
description: '支持超长上下文的中文大模型上下文窗口高达128K',
website: 'https://kimi.moonshot.cn',
userToken: '',
userModel: 'moonshot-v1-8k'
}
]);
export const llmManager = reactive({
currentModelIndex: 0,
});
export function onmodelchange() {
console.log();
}
export async function save() {
console.log();
}
export async function load() {
console.log();
}

View File

@ -0,0 +1,10 @@
const pinkLogStyle = 'background-color: #CB81DA; color: white; padding: 3px; border-radius: 3px;';
const redLogStyle = 'background-color:rgb(227, 91, 49); color: white; padding: 3px; border-radius: 3px;';
export function pinkLog(message: string) {
console.log('%c' + message, pinkLogStyle);
}
export function redLog(message: string) {
console.log('%c' + message, redLogStyle);
}

22
app/webpack.config.js Normal file
View File

@ -0,0 +1,22 @@
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
module.exports = {
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
new webpack.DefinePlugin({
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
})
],
resolve: {
fallback: {
"stream": false
}
},
};