ckean
This commit is contained in:
0
.cursor/mcp.json
Normal file
0
.cursor/mcp.json
Normal file
26
.cursor/rules/general.mdc
Normal file
26
.cursor/rules/general.mdc
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
description: 工程全局规则
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
你是一个游戏开发Agent,需要在本工程中,协助我开发一个 HTML 游戏。
|
||||
|
||||
## 本工程介绍
|
||||
|
||||
- 这是一个模版工程,开发者会基于这个工程进行拓展开发
|
||||
- 本工程采用 Vite + React 框架,是一个React SPA架构的游戏/应用
|
||||
- 本工程强烈建议使用如下前端NPM包:
|
||||
- react-router: 用于管理页面和路由
|
||||
- zustand: 用于React状态管理
|
||||
- TailwindCSS: 用于编写样式和管理主题
|
||||
- axios:用于发起http请求。包括上传和SSE场景。
|
||||
- dayjs: 用于处理日期
|
||||
- localforage: 用于管理Storage
|
||||
- react-icons: 用于使用图标
|
||||
- motion: 动效库
|
||||
- loadsh-es: 用于提供一些常用的utils函数
|
||||
|
||||
## 你需要遵循的规则
|
||||
|
||||
- Always respond in 中文
|
||||
- 只能新增、修改和删除 src 目录里的文件或者文件夹,严禁修改其他文件或者文件夹!
|
||||
6
.cursorignore
Normal file
6
.cursorignore
Normal file
@@ -0,0 +1,6 @@
|
||||
.npmrc
|
||||
biome.json
|
||||
index.html
|
||||
pnpm-lock.yaml
|
||||
.trae/
|
||||
.cursor/
|
||||
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
*.zip
|
||||
338
biome.json
Normal file
338
biome.json
Normal file
@@ -0,0 +1,338 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/2.1.3/schema.json",
|
||||
"vcs": {
|
||||
"enabled": false,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": false
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": false
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "space",
|
||||
"indentWidth": 2
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": false
|
||||
},
|
||||
"includes": [
|
||||
"**",
|
||||
"!dist"
|
||||
]
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "single"
|
||||
}
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"includes": [
|
||||
"**/*.{ts,tsx,js,jsx}"
|
||||
],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"complexity": {
|
||||
"noAdjacentSpacesInRegex": "error",
|
||||
"noExtraBooleanCast": "error",
|
||||
"noUselessCatch": "error",
|
||||
"noUselessEscapeInRegex": "error"
|
||||
},
|
||||
"correctness": {
|
||||
"noConstAssign": "error",
|
||||
"noConstantCondition": "error",
|
||||
"noEmptyCharacterClassInRegex": "error",
|
||||
"noEmptyPattern": "error",
|
||||
"noGlobalObjectCalls": "error",
|
||||
"noInvalidBuiltinInstantiation": "error",
|
||||
"noInvalidConstructorSuper": "error",
|
||||
"noNonoctalDecimalEscape": "error",
|
||||
"noPrecisionLoss": "error",
|
||||
"noSelfAssign": "error",
|
||||
"noSetterReturn": "error",
|
||||
"noSwitchDeclarations": "error",
|
||||
"noUndeclaredVariables": "error",
|
||||
"noUnreachable": "error",
|
||||
"noUnreachableSuper": "error",
|
||||
"noUnsafeFinally": "error",
|
||||
"noUnsafeOptionalChaining": "error",
|
||||
"noUnusedLabels": "error",
|
||||
"noUnusedPrivateClassMembers": "error",
|
||||
"noUnusedVariables": "warn",
|
||||
"useIsNan": "error",
|
||||
"useValidForDirection": "error",
|
||||
"useValidTypeof": "error",
|
||||
"useYield": "error"
|
||||
},
|
||||
"suspicious": {
|
||||
"noAsyncPromiseExecutor": "error",
|
||||
"noCatchAssign": "error",
|
||||
"noClassAssign": "error",
|
||||
"noCompareNegZero": "error",
|
||||
"noControlCharactersInRegex": "error",
|
||||
"noDebugger": "error",
|
||||
"noDuplicateCase": "error",
|
||||
"noDuplicateClassMembers": "error",
|
||||
"noDuplicateElseIf": "error",
|
||||
"noDuplicateObjectKeys": "error",
|
||||
"noDuplicateParameters": "error",
|
||||
"noEmptyBlockStatements": "error",
|
||||
"noFallthroughSwitchClause": "error",
|
||||
"noFunctionAssign": "error",
|
||||
"noGlobalAssign": "error",
|
||||
"noImportAssign": "error",
|
||||
"noIrregularWhitespace": "error",
|
||||
"noMisleadingCharacterClass": "error",
|
||||
"noPrototypeBuiltins": "error",
|
||||
"noRedeclare": "error",
|
||||
"noShadowRestrictedNames": "error",
|
||||
"noSparseArray": "error",
|
||||
"noUnsafeNegation": "error",
|
||||
"noWith": "error",
|
||||
"useGetterReturn": "error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"includes": [
|
||||
"**/*.{ts,tsx,js,jsx}"
|
||||
],
|
||||
"javascript": {
|
||||
"globals": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"includes": [
|
||||
"**/*.{ts,tsx,js,jsx}"
|
||||
],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"complexity": {
|
||||
"noArguments": "error"
|
||||
},
|
||||
"correctness": {
|
||||
"noConstAssign": "off",
|
||||
"noGlobalObjectCalls": "off",
|
||||
"noInvalidBuiltinInstantiation": "off",
|
||||
"noInvalidConstructorSuper": "off",
|
||||
"noSetterReturn": "off",
|
||||
"noUndeclaredVariables": "off",
|
||||
"noUnreachable": "off",
|
||||
"noUnreachableSuper": "off"
|
||||
},
|
||||
"style": {
|
||||
"useConst": "error"
|
||||
},
|
||||
"suspicious": {
|
||||
"noClassAssign": "off",
|
||||
"noDuplicateClassMembers": "off",
|
||||
"noDuplicateObjectKeys": "off",
|
||||
"noDuplicateParameters": "off",
|
||||
"noFunctionAssign": "off",
|
||||
"noImportAssign": "off",
|
||||
"noRedeclare": "off",
|
||||
"noUnsafeNegation": "off",
|
||||
"noVar": "error",
|
||||
"noWith": "off",
|
||||
"useGetterReturn": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"includes": [
|
||||
"**/*.{ts,tsx,js,jsx}"
|
||||
],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"complexity": {
|
||||
"noUselessTypeConstraint": "error"
|
||||
},
|
||||
"correctness": {
|
||||
"noUnusedVariables": "warn"
|
||||
},
|
||||
"style": {
|
||||
"noCommonJs": "error",
|
||||
"noNamespace": "error",
|
||||
"useArrayLiterals": "error",
|
||||
"useAsConstAssertion": "error"
|
||||
},
|
||||
"suspicious": {
|
||||
"noExplicitAny": "error",
|
||||
"noExtraNonNullAssertion": "error",
|
||||
"noMisleadingInstantiator": "error",
|
||||
"noUnsafeDeclarationMerging": "error",
|
||||
"useNamespaceKeyword": "error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"includes": [
|
||||
"**/*.{ts,tsx,js,jsx}"
|
||||
],
|
||||
"linter": {
|
||||
"rules": {
|
||||
"correctness": {
|
||||
"useExhaustiveDependencies": "warn",
|
||||
"useHookAtTopLevel": "error"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"includes": [
|
||||
"**/*.{ts,tsx,js,jsx}"
|
||||
],
|
||||
"linter": {
|
||||
"rules": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"includes": [
|
||||
"**/*.{ts,tsx,js,jsx}"
|
||||
],
|
||||
"javascript": {
|
||||
"globals": [
|
||||
"onanimationend",
|
||||
"ongamepadconnected",
|
||||
"onlostpointercapture",
|
||||
"onanimationiteration",
|
||||
"onkeyup",
|
||||
"onmousedown",
|
||||
"onanimationstart",
|
||||
"onslotchange",
|
||||
"onprogress",
|
||||
"ontransitionstart",
|
||||
"onpause",
|
||||
"onended",
|
||||
"onpointerover",
|
||||
"onscrollend",
|
||||
"onformdata",
|
||||
"ontransitionrun",
|
||||
"onanimationcancel",
|
||||
"ondrag",
|
||||
"onchange",
|
||||
"onbeforeinstallprompt",
|
||||
"onbeforexrselect",
|
||||
"onmessage",
|
||||
"ontransitioncancel",
|
||||
"onpointerdown",
|
||||
"onabort",
|
||||
"onpointerout",
|
||||
"oncuechange",
|
||||
"ongotpointercapture",
|
||||
"onscrollsnapchanging",
|
||||
"onsearch",
|
||||
"onsubmit",
|
||||
"onstalled",
|
||||
"onsuspend",
|
||||
"onreset",
|
||||
"onerror",
|
||||
"onresize",
|
||||
"onmouseenter",
|
||||
"ongamepaddisconnected",
|
||||
"ondragover",
|
||||
"onbeforetoggle",
|
||||
"onmouseover",
|
||||
"onpagehide",
|
||||
"onmousemove",
|
||||
"onratechange",
|
||||
"oncommand",
|
||||
"onmessageerror",
|
||||
"onwheel",
|
||||
"ondevicemotion",
|
||||
"onauxclick",
|
||||
"ontransitionend",
|
||||
"onpaste",
|
||||
"onpageswap",
|
||||
"ononline",
|
||||
"ondeviceorientationabsolute",
|
||||
"onkeydown",
|
||||
"onclose",
|
||||
"onselect",
|
||||
"onpageshow",
|
||||
"onpointercancel",
|
||||
"onbeforematch",
|
||||
"onpointerrawupdate",
|
||||
"ondragleave",
|
||||
"onscrollsnapchange",
|
||||
"onseeked",
|
||||
"onwaiting",
|
||||
"onbeforeunload",
|
||||
"onplaying",
|
||||
"onvolumechange",
|
||||
"ondragend",
|
||||
"onstorage",
|
||||
"onloadeddata",
|
||||
"onfocus",
|
||||
"onoffline",
|
||||
"onplay",
|
||||
"onafterprint",
|
||||
"onclick",
|
||||
"oncut",
|
||||
"onmouseout",
|
||||
"ondblclick",
|
||||
"oncanplay",
|
||||
"onloadstart",
|
||||
"onappinstalled",
|
||||
"onpointermove",
|
||||
"ontoggle",
|
||||
"oncontextmenu",
|
||||
"onblur",
|
||||
"oncancel",
|
||||
"onbeforeprint",
|
||||
"oncontextrestored",
|
||||
"onloadedmetadata",
|
||||
"onpointerup",
|
||||
"onlanguagechange",
|
||||
"oncopy",
|
||||
"onselectstart",
|
||||
"onscroll",
|
||||
"onload",
|
||||
"ondragstart",
|
||||
"onbeforeinput",
|
||||
"oncanplaythrough",
|
||||
"oninput",
|
||||
"oninvalid",
|
||||
"ontimeupdate",
|
||||
"ondurationchange",
|
||||
"onselectionchange",
|
||||
"onmouseup",
|
||||
"location",
|
||||
"onkeypress",
|
||||
"onpointerleave",
|
||||
"oncontextlost",
|
||||
"ondrop",
|
||||
"onsecuritypolicyviolation",
|
||||
"oncontentvisibilityautostatechange",
|
||||
"ondeviceorientation",
|
||||
"onseeking",
|
||||
"onrejectionhandled",
|
||||
"onunload",
|
||||
"onmouseleave",
|
||||
"onhashchange",
|
||||
"onpointerenter",
|
||||
"onmousewheel",
|
||||
"onunhandledrejection",
|
||||
"ondragenter",
|
||||
"onpopstate",
|
||||
"onpagereveal",
|
||||
"onemptied"
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"assist": {
|
||||
"enabled": true,
|
||||
"actions": {
|
||||
"source": {
|
||||
"organizeImports": "on"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/logo.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>幕间自定义界面模版 React 纯净版</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
44
package.json
Normal file
44
package.json
Normal file
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "@mujian/game-boilerplate",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=22.0.0",
|
||||
"pnpm": ">=10.0.0"
|
||||
},
|
||||
"packageManager": "pnpm@10.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "biome check --write ./src",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mujian/js-sdk": "^0.0.6-beta.75",
|
||||
"@tailwindcss/vite": "^4.1.12",
|
||||
"axios": "^1.11.0",
|
||||
"dayjs": "^1.11.18",
|
||||
"localforage": "^1.10.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"motion": "^12.23.12",
|
||||
"react": "^19.1.1",
|
||||
"react-dom": "^19.1.1",
|
||||
"react-icons": "^5.5.0",
|
||||
"react-router": "^7.8.2",
|
||||
"tailwindcss": "^4.1.12",
|
||||
"zustand": "^5.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/react": "^19.1.10",
|
||||
"@types/react-dom": "^19.1.7",
|
||||
"@vitejs/plugin-react": "^5.0.0",
|
||||
"clsx": "^2.1.1",
|
||||
"globals": "^16.3.0",
|
||||
"tailwind-merge": "^3.4.0",
|
||||
"typescript": "~5.8.3",
|
||||
"vite": "^7.1.2"
|
||||
}
|
||||
}
|
||||
2051
pnpm-lock.yaml
generated
Normal file
2051
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
5
public/logo.svg
Normal file
5
public/logo.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="160" height="160" viewBox="0 0 160 160" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M52.7348 13.6389C58.5412 10.6133 64.8866 8.76088 71.4087 8.18728C85.5279 6.89611 99.1091 8.74917 110.754 17.5841C123.821 27.5189 131.173 41.4946 131.077 57.2395C131.304 82.0228 131.161 106.794 131.077 131.577C131.077 138.75 126.08 143.437 118.823 143.461C112.236 143.461 105.039 143.58 98.4398 143.461C97.9179 143.478 97.397 143.409 96.8973 143.258C96.6058 143.212 96.3382 143.069 96.1385 142.852C95.9385 142.635 95.8183 142.357 95.7975 142.062C95.8337 141.773 95.959 141.503 96.1563 141.288C96.3532 141.074 96.6126 140.926 96.8973 140.867C97.37 140.775 97.8506 140.73 98.3322 140.735C98.9777 140.735 99.5276 140.675 100.125 140.615C100.709 140.598 101.287 140.506 101.847 140.341C102.388 140.161 102.913 139.933 103.413 139.659C105.952 138.255 108.072 136.201 109.556 133.707C111.039 131.213 111.832 128.37 111.853 125.468C111.961 103.136 112.32 80.8033 111.758 58.5188C111.505 49.2421 108.463 40.2568 103.029 32.7335C97.596 25.2103 90.0225 19.4979 81.2957 16.3407C76.0252 14.5651 70.5138 13.6056 64.9531 13.4954C63.1 13.4954 60.5773 13.4954 58.7843 13.4954L52.7348 13.6389Z" fill="#EF200D"/>
|
||||
<path d="M73.7759 31.1294C63.2434 32.2174 55.4727 36.9875 51.061 45.9779C49.2567 49.5936 48.261 53.5589 48.1439 57.5982C47.9528 84.3302 47.9528 111.038 48.0125 137.758C48.0125 143.174 52.4358 147.43 58.1265 147.777C59.1427 147.849 60.1468 147.849 61.1514 147.872C62.1556 147.896 63.3987 148.219 63.4107 149.295C63.4107 150.598 61.7013 150.849 61.3186 150.885H55.1259C49.4591 150.885 43.7923 150.885 38.1374 150.885C32.4826 150.885 28.8123 147.299 28.8004 141.512C28.8004 113.609 28.8004 85.7051 28.8004 57.8255C28.8243 40.7414 41.3416 28.3917 58.0787 28.1406C63.4707 27.9232 68.8409 28.9457 73.7759 31.1294Z" fill="#EF200D"/>
|
||||
<path d="M108.147 81.6522C106.175 81.8078 105.852 81.8795 104.92 81.9392C102.69 82.0699 100.477 82.4021 98.308 82.9315C89.9396 85.2389 85.1575 91.0609 83.6031 100.625C82.1446 109.484 82.3122 131.099 82.2043 134.1C82.1763 134.438 82.0473 134.76 81.834 135.024C81.621 135.289 81.3336 135.483 81.009 135.582C80.6718 135.494 80.3697 135.305 80.143 135.039C79.9167 134.775 79.7764 134.447 79.7416 134.1C79.6461 131.087 79.8133 109.472 78.3429 100.625C76.7649 91.0609 72.0306 85.2389 63.638 82.9315C61.449 82.399 59.216 82.0669 56.967 81.9392C56.0225 81.9392 55.6996 81.8078 53.7271 81.6522C53.4766 81.6426 53.24 81.5341 53.0697 81.3501C52.8994 81.1664 52.8089 80.9224 52.8185 80.6719C52.828 80.4213 52.9366 80.1851 53.1205 80.0145C53.3042 79.8441 53.5482 79.7537 53.7988 79.7632C56.8977 79.6393 59.9871 79.34 63.0523 78.8666C72.6163 76.6312 77.9124 70.3903 79.0364 59.4394C79.4669 55.243 79.5146 50.9989 79.8491 46.8026C79.8491 46.6234 79.8491 46.4681 79.8491 46.3005C79.873 46.0769 79.9208 45.8564 79.9929 45.6431C80.0717 45.4291 80.1939 45.2338 80.3512 45.0693C80.4605 44.9874 80.5813 44.9226 80.71 44.8778C80.7844 44.8577 80.8629 44.8577 80.9373 44.8778C81.0117 44.8601 81.0896 44.8601 81.1643 44.8778C81.2674 44.9348 81.3636 45.0028 81.4514 45.0813C81.6128 45.2427 81.7353 45.439 81.8101 45.655C81.8855 45.868 81.9378 46.0885 81.9654 46.3124C81.9654 46.48 81.9654 46.6353 81.9654 46.8145C82.3003 51.0109 82.348 55.255 82.7785 59.4513C83.9738 70.4022 89.2699 76.6431 98.7742 78.8785C101.839 79.353 104.929 79.6526 108.028 79.7752C108.157 79.7547 108.29 79.7615 108.417 79.7953C108.544 79.8291 108.663 79.8888 108.765 79.9711C108.868 80.053 108.952 80.1558 109.013 80.2725C109.074 80.3889 109.109 80.5169 109.118 80.6483C109.126 80.7794 109.107 80.9108 109.062 81.034C109.016 81.1576 108.946 81.2699 108.854 81.3644C108.763 81.459 108.653 81.5334 108.531 81.5829C108.409 81.6324 108.279 81.6563 108.147 81.6522Z" fill="#EF200D"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
5
src/assets/logo.svg
Normal file
5
src/assets/logo.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="160" height="160" viewBox="0 0 160 160" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M52.7348 13.6389C58.5412 10.6133 64.8866 8.76088 71.4087 8.18728C85.5279 6.89611 99.1091 8.74917 110.754 17.5841C123.821 27.5189 131.173 41.4946 131.077 57.2395C131.304 82.0228 131.161 106.794 131.077 131.577C131.077 138.75 126.08 143.437 118.823 143.461C112.236 143.461 105.039 143.58 98.4398 143.461C97.9179 143.478 97.397 143.409 96.8973 143.258C96.6058 143.212 96.3382 143.069 96.1385 142.852C95.9385 142.635 95.8183 142.357 95.7975 142.062C95.8337 141.773 95.959 141.503 96.1563 141.288C96.3532 141.074 96.6126 140.926 96.8973 140.867C97.37 140.775 97.8506 140.73 98.3322 140.735C98.9777 140.735 99.5276 140.675 100.125 140.615C100.709 140.598 101.287 140.506 101.847 140.341C102.388 140.161 102.913 139.933 103.413 139.659C105.952 138.255 108.072 136.201 109.556 133.707C111.039 131.213 111.832 128.37 111.853 125.468C111.961 103.136 112.32 80.8033 111.758 58.5188C111.505 49.2421 108.463 40.2568 103.029 32.7335C97.596 25.2103 90.0225 19.4979 81.2957 16.3407C76.0252 14.5651 70.5138 13.6056 64.9531 13.4954C63.1 13.4954 60.5773 13.4954 58.7843 13.4954L52.7348 13.6389Z" fill="#EF200D"/>
|
||||
<path d="M73.7759 31.1294C63.2434 32.2174 55.4727 36.9875 51.061 45.9779C49.2567 49.5936 48.261 53.5589 48.1439 57.5982C47.9528 84.3302 47.9528 111.038 48.0125 137.758C48.0125 143.174 52.4358 147.43 58.1265 147.777C59.1427 147.849 60.1468 147.849 61.1514 147.872C62.1556 147.896 63.3987 148.219 63.4107 149.295C63.4107 150.598 61.7013 150.849 61.3186 150.885H55.1259C49.4591 150.885 43.7923 150.885 38.1374 150.885C32.4826 150.885 28.8123 147.299 28.8004 141.512C28.8004 113.609 28.8004 85.7051 28.8004 57.8255C28.8243 40.7414 41.3416 28.3917 58.0787 28.1406C63.4707 27.9232 68.8409 28.9457 73.7759 31.1294Z" fill="#EF200D"/>
|
||||
<path d="M108.147 81.6522C106.175 81.8078 105.852 81.8795 104.92 81.9392C102.69 82.0699 100.477 82.4021 98.308 82.9315C89.9396 85.2389 85.1575 91.0609 83.6031 100.625C82.1446 109.484 82.3122 131.099 82.2043 134.1C82.1763 134.438 82.0473 134.76 81.834 135.024C81.621 135.289 81.3336 135.483 81.009 135.582C80.6718 135.494 80.3697 135.305 80.143 135.039C79.9167 134.775 79.7764 134.447 79.7416 134.1C79.6461 131.087 79.8133 109.472 78.3429 100.625C76.7649 91.0609 72.0306 85.2389 63.638 82.9315C61.449 82.399 59.216 82.0669 56.967 81.9392C56.0225 81.9392 55.6996 81.8078 53.7271 81.6522C53.4766 81.6426 53.24 81.5341 53.0697 81.3501C52.8994 81.1664 52.8089 80.9224 52.8185 80.6719C52.828 80.4213 52.9366 80.1851 53.1205 80.0145C53.3042 79.8441 53.5482 79.7537 53.7988 79.7632C56.8977 79.6393 59.9871 79.34 63.0523 78.8666C72.6163 76.6312 77.9124 70.3903 79.0364 59.4394C79.4669 55.243 79.5146 50.9989 79.8491 46.8026C79.8491 46.6234 79.8491 46.4681 79.8491 46.3005C79.873 46.0769 79.9208 45.8564 79.9929 45.6431C80.0717 45.4291 80.1939 45.2338 80.3512 45.0693C80.4605 44.9874 80.5813 44.9226 80.71 44.8778C80.7844 44.8577 80.8629 44.8577 80.9373 44.8778C81.0117 44.8601 81.0896 44.8601 81.1643 44.8778C81.2674 44.9348 81.3636 45.0028 81.4514 45.0813C81.6128 45.2427 81.7353 45.439 81.8101 45.655C81.8855 45.868 81.9378 46.0885 81.9654 46.3124C81.9654 46.48 81.9654 46.6353 81.9654 46.8145C82.3003 51.0109 82.348 55.255 82.7785 59.4513C83.9738 70.4022 89.2699 76.6431 98.7742 78.8785C101.839 79.353 104.929 79.6526 108.028 79.7752C108.157 79.7547 108.29 79.7615 108.417 79.7953C108.544 79.8291 108.663 79.8888 108.765 79.9711C108.868 80.053 108.952 80.1558 109.013 80.2725C109.074 80.3889 109.109 80.5169 109.118 80.6483C109.126 80.7794 109.107 80.9108 109.062 81.034C109.016 81.1576 108.946 81.2699 108.854 81.3644C108.763 81.459 108.653 81.5334 108.531 81.5829C108.409 81.6324 108.279 81.6563 108.147 81.6522Z" fill="#EF200D"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
8
src/main.tsx
Normal file
8
src/main.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import '@/styles/global.css';
|
||||
import '@mujian/js-sdk/lite';
|
||||
import { ReactRouterProvider } from './providers/RouterProvider.tsx';
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<ReactRouterProvider />
|
||||
);
|
||||
0
src/pages/home/components/.gitkeep
Normal file
0
src/pages/home/components/.gitkeep
Normal file
27
src/pages/home/index.tsx
Normal file
27
src/pages/home/index.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { useGlobalStore } from "@/store/global";
|
||||
import logo from "@/assets/logo.svg";
|
||||
import { useMujianOpenAPI } from "@/utils/llm";
|
||||
import { useState } from "react";
|
||||
|
||||
function Home() {
|
||||
const { baseURL, apiKey, modelId } = useGlobalStore();
|
||||
const { query } = useMujianOpenAPI();
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
return (
|
||||
<div className="flex flex-col justify-center items-center h-screen gap-4">
|
||||
<img src={logo} alt="幕间" className="w-20 h-20" />
|
||||
<h1 className="text-2xl font-bold">初始化成功</h1>
|
||||
<div className="flex flex-col justify-start items-start gap-2">
|
||||
<p className="break-all">Base URL: <span className="text-gray-500">{baseURL}</span></p>
|
||||
<p className="break-all">API Key: <span className="text-gray-500">{apiKey}</span></p>
|
||||
<p className="break-all">Model ID: <span className="text-gray-500">{modelId}</span></p>
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" placeholder="请输入问题" value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
|
||||
<button type="button" disabled={!inputValue} onClick={() => query(inputValue)}>发送</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Home;
|
||||
21
src/providers/RouterProvider.tsx
Normal file
21
src/providers/RouterProvider.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import { createBrowserRouter } from "react-router";
|
||||
import { RouterProvider } from "react-router/dom";
|
||||
import Home from "@/pages/home";
|
||||
import { useGlobalStore } from "@/store/global";
|
||||
import { useEffect } from "react";
|
||||
import type MujianSdkLite from "@mujian/js-sdk/lite";
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <Home />,
|
||||
},
|
||||
]);
|
||||
|
||||
export const ReactRouterProvider = () => {
|
||||
const { init } = useGlobalStore();
|
||||
useEffect(() => {
|
||||
init(window.$mujian_lite as MujianSdkLite);
|
||||
}, [init]);
|
||||
return <RouterProvider router={router} />;
|
||||
};
|
||||
25
src/store/global.tsx
Normal file
25
src/store/global.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import type MujianSdkLite from "@mujian/js-sdk/lite";
|
||||
import { create } from "zustand";
|
||||
|
||||
type GlobalState = {
|
||||
apiKey: string;
|
||||
baseURL: string;
|
||||
modelId: string;
|
||||
init: (mujian_lite: MujianSdkLite) => Promise<void>;
|
||||
};
|
||||
|
||||
console.log(import.meta.env);
|
||||
|
||||
export const useGlobalStore = create<GlobalState>((set) => ({
|
||||
baseURL: "https://openapi.mujian.ai/v1",
|
||||
apiKey: import.meta.env.VITE_MUJIAN_API_KEY,
|
||||
modelId: "deepseek-v3.2",
|
||||
init: async (mujian_lite: MujianSdkLite) => {
|
||||
mujian_lite.init().then(() => {
|
||||
set({
|
||||
apiKey: mujian_lite.openapi?.apiKey ?? "",
|
||||
baseURL: mujian_lite.openapi?.baseURL ?? "",
|
||||
});
|
||||
});
|
||||
},
|
||||
}));
|
||||
16
src/styles/global.css
Normal file
16
src/styles/global.css
Normal file
@@ -0,0 +1,16 @@
|
||||
/* 全局样式 */
|
||||
|
||||
@import "tailwindcss";
|
||||
|
||||
:root {
|
||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
6
src/utils/cn.ts
Normal file
6
src/utils/cn.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { type ClassValue, clsx } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export const cn = (...inputs: ClassValue[]) => {
|
||||
return twMerge(clsx(inputs));
|
||||
};
|
||||
75
src/utils/llm.ts
Normal file
75
src/utils/llm.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import { useGlobalStore } from "@/store/global";
|
||||
|
||||
const useMujianOpenAPI = () => {
|
||||
const { baseURL, apiKey, modelId } = useGlobalStore();
|
||||
return {
|
||||
query: (query: string) => queryMujianOpenAPI(baseURL, apiKey, query, modelId),
|
||||
};
|
||||
};
|
||||
|
||||
async function queryMujianOpenAPI(baseURL: string, apiKey: string, query: string, modelId: string) {
|
||||
try {
|
||||
const response = await fetch(`${baseURL}/chat/completions`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiKey}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: modelId,
|
||||
stream: true,
|
||||
messages: [
|
||||
{ role: 'system', content: '这里是系统提示词' },
|
||||
{ role: 'user', content: query }
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.body) {
|
||||
throw new Error('No response body');
|
||||
}
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = '';
|
||||
|
||||
const parseDataLine = (line: string) => {
|
||||
if (!line.startsWith("data: ")) return;
|
||||
const payload = line.slice(6).trimStart();
|
||||
if (payload === "[DONE]") return;
|
||||
try {
|
||||
const data = JSON.parse(payload);
|
||||
if (data?.choices?.[0]?.delta?.content) {
|
||||
console.log("content", data.choices?.[0]?.delta?.content);
|
||||
} else {
|
||||
console.log("data", data);
|
||||
}
|
||||
} catch {
|
||||
// incomplete JSON until next chunk; caller should only pass full lines
|
||||
}
|
||||
};
|
||||
|
||||
const flushLines = (flushAll: boolean) => {
|
||||
// SSE: one logical line per \n; last segment may be incomplete until next read
|
||||
const lines = buffer.split(/\r?\n/);
|
||||
buffer = flushAll ? "" : (lines.pop() ?? "");
|
||||
for (const raw of lines) {
|
||||
parseDataLine(raw.trimEnd());
|
||||
}
|
||||
};
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
flushLines(true);
|
||||
break;
|
||||
}
|
||||
buffer += decoder.decode(value, { stream: true });
|
||||
flushLines(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Streaming error:", error);
|
||||
}
|
||||
}
|
||||
|
||||
export { useMujianOpenAPI };
|
||||
1
src/vite-env.d.ts
vendored
Normal file
1
src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
31
tsconfig.app.json
Normal file
31
tsconfig.app.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"erasableSyntaxOnly": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
7
tsconfig.json
Normal file
7
tsconfig.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
25
tsconfig.node.json
Normal file
25
tsconfig.node.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2023",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"erasableSyntaxOnly": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
17
vite.config.ts
Normal file
17
vite.config.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import tailwindcss from '@tailwindcss/vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import path from 'path';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react(), tailwindcss()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
cors: true,
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user