@@ -10,6 +10,7 @@
\ No newline at end of file
diff --git a/apps/frontend/src/views/home/spline.vue b/apps/frontend/src/views/home/spline.vue
new file mode 100644
index 0000000..e80f67e
--- /dev/null
+++ b/apps/frontend/src/views/home/spline.vue
@@ -0,0 +1,162 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/frontend/tailwind.config.js b/apps/frontend/tailwind.config.js
index 1145238..70e19e2 100644
--- a/apps/frontend/tailwind.config.js
+++ b/apps/frontend/tailwind.config.js
@@ -1,79 +1,56 @@
-/** @type {import('tailwindcss').Config} */
+import animate from "tailwindcss-animate";
+import { setupInspiraUI } from "@inspira-ui/plugins";
+
export default {
- content: [
- "./index.html",
- "./src/**/*.{vue,js,ts,jsx,tsx}",
- ],
+ darkMode: "selector",
+ safelist: ["dark"],
+ prefix: "",
+ content: ["./index.html","./public/**/*.html", "./src/**/*.{vue,js,ts,jsx,tsx}","./pages/**/*.{vue,js}" ],
theme: {
extend: {
- // 自定义颜色主题
colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
primary: {
- DEFAULT: '#6B46C1', // 深紫色
- light: '#A78BFA', // 浅紫色
- dark: '#553C9A', // 更深的紫色
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
},
secondary: {
- DEFAULT: '#1F2937', // 深灰色
- light: '#4B5563', // 中灰色
- lighter: '#9CA3AF', // 浅灰色
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
},
- background: {
- DEFAULT: '#F3F4F6', // 浅灰色背景
- dark: '#111827', // 深色背景
- card: '#FFFFFF', // 卡片背景
- }
},
- // 响应式断点配置
- screens: {
- 'xs': '475px', // 超小屏
- 'sm': '640px', // 小屏(手机横屏)
- 'md': '768px', // 中屏(平板)
- 'lg': '1024px', // 大屏(桌面)
- 'xl': '1280px', // 超大屏
- '2xl': '1536px', // 超超大屏
- },
- // 字体配置
- fontFamily: {
- 'sans': ['Inter', 'system-ui', 'sans-serif'],
- },
- // 间距配置(8px网格系统)
- spacing: {
- '18': '4.5rem',
- '88': '22rem',
- '128': '32rem',
- },
- // 圆角配置
borderRadius: {
- '4xl': '2rem',
- },
- // 阴影配置
- boxShadow: {
- 'card': '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
- 'card-hover': '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
- },
- // 动画配置
- animation: {
- 'fade-in': 'fadeIn 0.2s ease-in-out',
- 'slide-up': 'slideUp 0.3s ease-out',
- },
- keyframes: {
- fadeIn: {
- '0%': { opacity: '0' },
- '100%': { opacity: '1' },
- },
- slideUp: {
- '0%': { transform: 'translateY(10px)', opacity: '0' },
- '100%': { transform: 'translateY(0)', opacity: '1' },
- },
+ xl: "calc(var(--radius) + 4px)",
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
},
},
},
- plugins: [],
- // 暗黑模式支持
- darkMode: 'class',
- // 兼容性配置
- corePlugins: {
- preflight: true,
- },
-}
\ No newline at end of file
+
+ plugins: [animate, setupInspiraUI],
+};
diff --git a/package-lock.json b/package-lock.json
index 5960568..cceafe9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -30,6 +30,7 @@
"dependencies": {
"@element-plus/icons-vue": "^2.3.2",
"@google/genai": "^1.27.0",
+ "@splinetool/runtime": "^1.12.6",
"@stripe/stripe-js": "^4.8.0",
"@twind/core": "^1.1.3",
"@twind/preset-autoprefix": "^1.0.7",
@@ -37,11 +38,13 @@
"@types/three": "^0.180.0",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
+ "@vueuse/core": "^14.1.0",
"axios": "^1.13.2",
"country-state-city": "^3.2.1",
"dayjs": "^1.11.13",
"element-plus": "^2.11.7",
"jose": "^6.1.1",
+ "motion-v": "^1.7.4",
"normalize.css": "^8.0.1",
"nprogress": "^0.2.0",
"pinia": "^3.0.4",
@@ -57,11 +60,16 @@
},
"devDependencies": {
"@iconify-json/feather": "^1.2.1",
+ "@inspira-ui/plugins": "^0.0.1",
"@tailwindcss/postcss": "^4.1.17",
"@vitejs/plugin-vue": "^6.0.1",
"autoprefixer": "^10.4.22",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
"postcss": "^8.5.6",
+ "tailwind-merge": "^3.4.0",
"tailwindcss": "^4.1.17",
+ "tailwindcss-animate": "^1.0.7",
"terser": "^5.44.1",
"unplugin-auto-import": "^20.2.0",
"unplugin-icons": "^22.5.0",
@@ -69,6 +77,65 @@
"vite": "^7.2.2"
}
},
+ "apps/frontend/node_modules/@types/web-bluetooth": {
+ "version": "0.0.21",
+ "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz",
+ "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==",
+ "license": "MIT"
+ },
+ "apps/frontend/node_modules/@vueuse/core": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-14.1.0.tgz",
+ "integrity": "sha512-rgBinKs07hAYyPF834mDTigH7BtPqvZ3Pryuzt1SD/lg5wEcWqvwzXXYGEDb2/cP0Sj5zSvHl3WkmMELr5kfWw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/web-bluetooth": "^0.0.21",
+ "@vueuse/metadata": "14.1.0",
+ "@vueuse/shared": "14.1.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
+ }
+ },
+ "apps/frontend/node_modules/@vueuse/metadata": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-14.1.0.tgz",
+ "integrity": "sha512-7hK4g015rWn2PhKcZ99NyT+ZD9sbwm7SGvp7k+k+rKGWnLjS/oQozoIZzWfCewSUeBmnJkIb+CNr7Zc/EyRnnA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "apps/frontend/node_modules/@vueuse/shared": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-14.1.0.tgz",
+ "integrity": "sha512-EcKxtYvn6gx1F8z9J5/rsg3+lTQnvOruQd8fUecW99DCK04BkWD7z5KQ/wTAx+DazyoEE9dJt/zV8OIEQbM6kw==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
+ }
+ },
+ "apps/frontend/node_modules/motion-v": {
+ "version": "1.7.4",
+ "resolved": "https://registry.npmmirror.com/motion-v/-/motion-v-1.7.4.tgz",
+ "integrity": "sha512-YNDUAsany04wfI7YtHxQK3kxzNvh+OdFUk9GpA3+hMt7j6P+5WrVAAgr8kmPPoVza9EsJiAVhqoN3YYFN0Twrw==",
+ "license": "MIT",
+ "dependencies": {
+ "framer-motion": "12.23.12",
+ "hey-listen": "^1.0.8",
+ "motion-dom": "12.23.12"
+ },
+ "peerDependencies": {
+ "@vueuse/core": ">=10.0.0",
+ "vue": ">=3.0.0"
+ }
+ },
"apps/FrontendDesigner": {
"name": "frontenddesigner",
"version": "0.0.0",
@@ -1185,6 +1252,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@inspira-ui/plugins": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmmirror.com/@inspira-ui/plugins/-/plugins-0.0.1.tgz",
+ "integrity": "sha512-gM4iZptDoStA7QT1lltC6Jl4qRLhkZwVtcXomQy/PPxe0lAxhrZx40KXEUJakRZLOSmyfVJCExzZhRzOrE6DBQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mini-svg-data-uri": "^1.4.4"
+ }
+ },
"node_modules/@intlify/core-base": {
"version": "9.14.5",
"resolved": "https://registry.npmmirror.com/@intlify/core-base/-/core-base-9.14.5.tgz",
@@ -1707,6 +1784,15 @@
"win32"
]
},
+ "node_modules/@splinetool/runtime": {
+ "version": "1.12.6",
+ "resolved": "https://registry.npmmirror.com/@splinetool/runtime/-/runtime-1.12.6.tgz",
+ "integrity": "sha512-oBybkcit6Ythcyq9XzdQ1KSSJ8E6sqFBjt2SxociOE/A3hWv/k25ESy4LolahF2g48yl/XiLK8kS1EGbh5Bbhw==",
+ "dependencies": {
+ "on-change": "^4.0.0",
+ "semver-compare": "^1.0.0"
+ }
+ },
"node_modules/@stripe/stripe-js": {
"version": "4.10.0",
"resolved": "https://registry.npmmirror.com/@stripe/stripe-js/-/stripe-js-4.10.0.tgz",
@@ -2796,6 +2882,19 @@
"url": "https://paulmillr.com/funding/"
}
},
+ "node_modules/class-variance-authority": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmmirror.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+ "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "clsx": "^2.1.1"
+ },
+ "funding": {
+ "url": "https://polar.sh/cva"
+ }
+ },
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz",
@@ -2851,6 +2950,16 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/clsx": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz",
+ "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
@@ -3791,6 +3900,33 @@
"url": "https://github.com/sponsors/rawify"
}
},
+ "node_modules/framer-motion": {
+ "version": "12.23.12",
+ "resolved": "https://registry.npmmirror.com/framer-motion/-/framer-motion-12.23.12.tgz",
+ "integrity": "sha512-6e78rdVtnBvlEVgu6eFEAgG9v3wLnYEboM8I5O5EXvfKC8gxGQB8wXJdhkMy10iVcn05jl6CNw7/HTsTCfwcWg==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-dom": "^12.23.12",
+ "motion-utils": "^12.23.6",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/frontend": {
"resolved": "apps/frontend",
"link": true
@@ -4094,6 +4230,12 @@
"node": ">= 0.4"
}
},
+ "node_modules/hey-listen": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmmirror.com/hey-listen/-/hey-listen-1.0.8.tgz",
+ "integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==",
+ "license": "MIT"
+ },
"node_modules/hookable": {
"version": "5.5.3",
"resolved": "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz",
@@ -4786,6 +4928,16 @@
"node": ">= 0.6"
}
},
+ "node_modules/mini-svg-data-uri": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmmirror.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
+ "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mini-svg-data-uri": "cli.js"
+ }
+ },
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
@@ -4846,6 +4998,21 @@
"pathe": "^2.0.1"
}
},
+ "node_modules/motion-dom": {
+ "version": "12.23.12",
+ "resolved": "https://registry.npmmirror.com/motion-dom/-/motion-dom-12.23.12.tgz",
+ "integrity": "sha512-RcR4fvMCTESQBD/uKQe49D5RUeDOokkGRmz4ceaJKDBgHYtZtntC/s2vLvY38gqGaytinij/yi3hMcWVcEF5Kw==",
+ "license": "MIT",
+ "dependencies": {
+ "motion-utils": "^12.23.6"
+ }
+ },
+ "node_modules/motion-utils": {
+ "version": "12.23.6",
+ "resolved": "https://registry.npmmirror.com/motion-utils/-/motion-utils-12.23.6.tgz",
+ "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==",
+ "license": "MIT"
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz",
@@ -4963,6 +5130,18 @@
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
+ "node_modules/on-change": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmmirror.com/on-change/-/on-change-4.0.2.tgz",
+ "integrity": "sha512-cMtCyuJmTx/bg2HCpHo3ZLeF7FZnBOapLqZHr2AlLeJ5Ul0Zu2mUJJz051Fdwu/Et2YW04ZD+TtU+gVy0ACNCA==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/on-change?sponsor=1"
+ }
+ },
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
@@ -5504,6 +5683,12 @@
"node": ">=10"
}
},
+ "node_modules/semver-compare": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/semver-compare/-/semver-compare-1.0.0.tgz",
+ "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
+ "license": "MIT"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -5745,6 +5930,17 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
+ "node_modules/tailwind-merge": {
+ "version": "3.4.0",
+ "resolved": "https://registry.npmmirror.com/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
+ "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
"node_modules/tailwindcss": {
"version": "4.1.17",
"resolved": "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-4.1.17.tgz",
@@ -5752,6 +5948,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/tailwindcss-animate": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmmirror.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz",
+ "integrity": "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "tailwindcss": ">=3.0.0 || insiders"
+ }
+ },
"node_modules/tapable": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/tapable/-/tapable-2.3.0.tgz",
@@ -5839,7 +6045,6 @@
"version": "2.8.1",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "dev": true,
"license": "0BSD"
},
"node_modules/turbo": {
diff --git a/packages/utils/src/servers/fileserver.js b/packages/utils/src/servers/fileserver.js
index cea7575..887a168 100644
--- a/packages/utils/src/servers/fileserver.js
+++ b/packages/utils/src/servers/fileserver.js
@@ -10,6 +10,50 @@ export class FileServer {
concatUrl(url) {
return urlRule.replace('IMGURL',url)
}
+
+ //生成唯一的缓存键
+ generateUniqueCacheKey(input) {
+ let content = '';
+
+ if (typeof input === 'string') {
+ if (input.startsWith('data:')) {
+ // 对于base64字符串,使用文件类型、原始长度和内容哈希
+ const mimeMatch = input.match(/data:([^;]+)/);
+ const mimeType = mimeMatch ? mimeMatch[1] : 'unknown';
+ const contentLength = input.length;
+ // 取base64内容的前100个字符进行唯一标识
+ const contentPreview = input.substring(0, 100);
+ content = `base64_${mimeType}_${contentLength}_${contentPreview}`;
+ } else if (input.startsWith('http://') || input.startsWith('https://')) {
+ // 对于URL,使用完整URL
+ content = input;
+ } else {
+ // 对于本地路径
+ content = input;
+ }
+ } else if (input instanceof File) {
+ // 对于File对象,使用文件名、大小、类型和最后修改时间
+ content = `file_${input.name}_${input.size}_${input.type}_${input.lastModified}`;
+ }
+
+ // 使用同步哈希算法生成16位缓存键
+ return this.generateSimpleHash(content).substring(0, 16);
+ }
+
+ //简单的字符串哈希函数(同步)
+ generateSimpleHash(content) {
+ // 使用MurmurHash或简单的多项式哈希
+ let hash = 0;
+ const prime = 31;
+
+ for (let i = 0; i < content.length; i++) {
+ const char = content.charCodeAt(i);
+ hash = (prime * hash + char) | 0; // 使用位运算确保32位整数
+ }
+
+ // 转换为16进制字符串
+ return (hash >>> 0).toString(16).padStart(8, '0');
+ }
//文件压缩
/**
* 压缩文件 - 支持多种格式
@@ -228,7 +272,7 @@ export class FileServer {
throw error;
}
}
- const cacheKey = url.slice(-8);
+ const cacheKey = this.generateUniqueCacheKey(url);//生成唯一的缓存key
return new Promise(async (resolve, reject) => {
// 如果是网络路径直接返回
if (typeof url === 'string' && (url.startsWith('http://') || url.startsWith('https://'))) {