├── .env.development ├── .env.production ├── .env.staging ├── .eslintrc.cjs ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── biome.json ├── bunfig.toml ├── index.html ├── package.json ├── public ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── browserconfig.xml ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── mstile-150x150.png ├── safari-pinned-tab.svg └── site.webmanifest ├── src ├── advance │ └── suspense.tsx ├── assets │ ├── alipay.webp │ ├── weapp-code.webp │ └── wechat.webp ├── components │ ├── alert.tsx │ ├── footer.tsx │ ├── loading.tsx │ └── nav │ │ ├── index.scss │ │ └── index.tsx ├── index.css ├── index.scss ├── main.tsx ├── pages.ts ├── pages │ ├── list │ │ ├── index.scss │ │ └── index.tsx │ ├── result │ │ ├── 16pf │ │ │ ├── index.tsx │ │ │ ├── tab.scss │ │ │ └── tab.tsx │ │ ├── common │ │ │ └── index.tsx │ │ ├── components │ │ │ ├── GradientLine.scss │ │ │ ├── badge.tsx │ │ │ ├── circle.tsx │ │ │ ├── gradient-line.tsx │ │ │ └── radar.tsx │ │ ├── epq-rsc │ │ │ ├── coordinate-system.tsx │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── ept │ │ │ ├── index.tsx │ │ │ └── type.tsx │ │ ├── h-sds │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── index.scss │ │ ├── index.tsx │ │ ├── neo-pi-r │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ ├── scl90 │ │ │ ├── index.scss │ │ │ └── index.tsx │ │ └── y-bocs │ │ │ └── index.tsx │ ├── scale │ │ ├── components │ │ │ ├── checklist │ │ │ │ ├── index.scss │ │ │ │ └── index.tsx │ │ │ ├── idea.tsx │ │ │ ├── index.scss │ │ │ ├── question.tsx │ │ │ └── radio.tsx │ │ ├── index.scss │ │ ├── index.tsx │ │ └── items │ │ │ ├── 16pf │ │ │ ├── index.ts │ │ │ ├── question.tsx │ │ │ └── scale.tsx │ │ │ ├── common │ │ │ ├── question.tsx │ │ │ └── scale.tsx │ │ │ ├── epq-rsc │ │ │ ├── index.ts │ │ │ ├── question.tsx │ │ │ └── scale.tsx │ │ │ ├── ept │ │ │ ├── index.ts │ │ │ ├── question.tsx │ │ │ └── scale.tsx │ │ │ ├── h-sds │ │ │ ├── question.tsx │ │ │ └── scale.tsx │ │ │ ├── neo-pi-r │ │ │ ├── index.ts │ │ │ ├── question.tsx │ │ │ └── scale.tsx │ │ │ ├── scl90 │ │ │ ├── index.ts │ │ │ ├── question.tsx │ │ │ └── scale.tsx │ │ │ └── y-bocs │ │ │ ├── question.tsx │ │ │ └── scale.tsx │ └── utils.tsx ├── utils │ ├── color.ts │ ├── date.ts │ ├── http.ts │ ├── index.ts │ ├── math.ts │ └── random.ts └── vite-env.d.ts ├── tsconfig.json ├── tsconfig.node.json ├── types ├── index.d.ts ├── list.d.ts └── scale │ ├── 16pf.d.ts │ ├── epq-rsc.d.ts │ ├── ept.d.ts │ ├── h-sds.d.ts │ ├── index.d.ts │ ├── neo-pi-r.d.ts │ ├── scl-90.d.ts │ └── y-bocs.d.ts └── vite.config.ts /.env.development: -------------------------------------------------------------------------------- 1 | VITE_API=http://127.0.0.1:9999 2 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | VITE_API=https://your.domain/api 2 | -------------------------------------------------------------------------------- /.env.staging: -------------------------------------------------------------------------------- 1 | VITE_API=http://127.0.0.1:9999 2 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { browser: true, es2020: true }, 4 | extends: [ 5 | "eslint:recommended", 6 | "plugin:@typescript-eslint/recommended", 7 | "plugin:react-hooks/recommended", 8 | ], 9 | ignorePatterns: ["dist", ".eslintrc.cjs"], 10 | parser: "@typescript-eslint/parser", 11 | plugins: ["react-refresh"], 12 | rules: { 13 | "react-refresh/only-export-components": [ 14 | "warn", 15 | { allowConstantExport: true }, 16 | ], 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | bun.lockb 26 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "tabWidth": 2, 4 | "printWidth": 80, 5 | "singleQuote": true, 6 | "arrowParens": "always", 7 | "trailingComma": "all" 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 心灵脉冲网站页面 2 | 3 | 使用 antd-mobile 写的心理测试网站。 4 | 5 | ## 1 部署 6 | 7 | 你可以将前端页面部署到自己的服务器上,**不建议修改捐款二维码和小程码,但如果你修改了也请提个 issue 让我知道**,这个要求不是强制性的。 8 | 9 | 我使用的包管理器是`pnpm`,如果你使用的不是此包管理器,使用自己的包管理器执行下面的命令。 10 | 11 | ### 1.1 安装依赖 12 | 13 | 前端那一套流程,不再多说,直接上命令: 14 | 15 | ```bash 16 | pnpm i 17 | bun install 18 | ``` 19 | 20 | ### 1.2 打包 21 | 22 | 打包前一定要修改 api 地址,只需修改`.env.production`中的`VITE_API`为你的域名对应的 api 接口即可。 23 | 24 | 比如你的域名为`foo.bar.com`,给 api 服务器分配的路径是`mind-pulse`,则需改为: 25 | 26 | ``` 27 | VITE_API=https://foo.bar.com/mind-pulse 28 | ``` 29 | 30 | 然后再打包: 31 | 32 | ```bash 33 | pnpm build 34 | bun run build 35 | ``` 36 | 37 | 打包产物在项目根目录的`dist`目录中,根据自己的实际需求将产物上传。 38 | 39 | ## 2 开发 40 | 41 | 本网站是开源公益网站,但我个人精力有限,没有足够的时间去搜集已有测试或量表外的其他量表相关资料,如果你想提供某个量表的**完整题目**、**有可信来源的常模**、**计分规则**、**参考论文或书籍**可通过 issue 提供,以上条件缺一不可。 42 | -------------------------------------------------------------------------------- /biome.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://biomejs.dev/schemas/1.7.0/schema.json", 3 | "formatter": { 4 | "indentStyle": "space", 5 | "indentWidth": 2 6 | }, 7 | "linter": { 8 | "enabled": true, 9 | "rules": { 10 | "recommended": true 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /bunfig.toml: -------------------------------------------------------------------------------- 1 | [install] 2 | registry = "https://registry.npmmirror.com" 3 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 心灵脉冲 14 | 15 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "confidant", 3 | "private": true, 4 | "version": "0.1.11", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "stage": "vite --mode staging", 9 | "build": "biome check --write src && tsc && vite build", 10 | "check": "biome check --write src", 11 | "preview": "vite preview --mode staging" 12 | }, 13 | "dependencies": { 14 | "@ant-design/icons": "^5.5.1", 15 | "@antv/f2": "^5.7.3", 16 | "@antv/f2-react": "^5.7.3", 17 | "ahooks": "^3.8.1", 18 | "antd-mobile": "^5.38.1", 19 | "antd-mobile-icons": "^0.3.0", 20 | "react": "^18.3.1", 21 | "react-dom": "^18.3.1", 22 | "react-router-dom": "^6.28.0" 23 | }, 24 | "devDependencies": { 25 | "@biomejs/biome": "^1.9.4", 26 | "@types/node": "^20.17.6", 27 | "@types/react": "^18.3.12", 28 | "@types/react-dom": "^18.3.1", 29 | "@vitejs/plugin-react": "^4.3.3", 30 | "sass": "^1.81.0", 31 | "typescript": "^5.6.3", 32 | "vite": "^5.4.11", 33 | "vite-plugin-imp": "^2.4.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mind-pulse/www/4f6659f54d9d2897ac685a44eec47048a1cbfcb1/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mind-pulse/www/4f6659f54d9d2897ac685a44eec47048a1cbfcb1/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mind-pulse/www/4f6659f54d9d2897ac685a44eec47048a1cbfcb1/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #da532c 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mind-pulse/www/4f6659f54d9d2897ac685a44eec47048a1cbfcb1/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mind-pulse/www/4f6659f54d9d2897ac685a44eec47048a1cbfcb1/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mind-pulse/www/4f6659f54d9d2897ac685a44eec47048a1cbfcb1/public/favicon.ico -------------------------------------------------------------------------------- /public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mind-pulse/www/4f6659f54d9d2897ac685a44eec47048a1cbfcb1/public/mstile-150x150.png -------------------------------------------------------------------------------- /public/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 31 | 55 | 57 | 59 | 61 | 83 | 95 | 97 | 99 | 102 | 106 | 127 | 129 | 160 | 165 | 168 | 176 | 179 | 182 | 184 | 186 | 188 | 190 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /src/advance/suspense.tsx: -------------------------------------------------------------------------------- 1 | import type React from "react"; 2 | import { Suspense } from "react"; 3 | import Loading from "~/components/loading"; 4 | 5 | const suspense = (component: React.ReactNode) => ( 6 | }>{component} 7 | ); 8 | 9 | export default suspense; 10 | -------------------------------------------------------------------------------- /src/assets/alipay.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mind-pulse/www/4f6659f54d9d2897ac685a44eec47048a1cbfcb1/src/assets/alipay.webp -------------------------------------------------------------------------------- /src/assets/weapp-code.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mind-pulse/www/4f6659f54d9d2897ac685a44eec47048a1cbfcb1/src/assets/weapp-code.webp -------------------------------------------------------------------------------- /src/assets/wechat.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mind-pulse/www/4f6659f54d9d2897ac685a44eec47048a1cbfcb1/src/assets/wechat.webp -------------------------------------------------------------------------------- /src/components/alert.tsx: -------------------------------------------------------------------------------- 1 | import { Dialog, NoticeBar } from "antd-mobile"; 2 | import { useEffect, useRef, useState } from "react"; 3 | import type { ReactNode } from "react"; 4 | 5 | interface AlertProps { 6 | wait?: number; 7 | title?: string; 8 | warning?: string; 9 | content: ReactNode[]; 10 | defaultShow?: boolean; 11 | onClose?: () => void; 12 | } 13 | 14 | const Alert = ({ 15 | wait, 16 | title, 17 | warning, 18 | content, 19 | defaultShow, 20 | onClose, 21 | }: AlertProps) => { 22 | const [second, setSecond] = useState(wait); 23 | 24 | const [show, setShow] = useState(defaultShow); 25 | 26 | const timerRef = useRef(null); 27 | 28 | // biome-ignore lint/correctness/useExhaustiveDependencies(second): only run once on mount 29 | useEffect(() => { 30 | if (!second || second < 0) return; 31 | 32 | let current = second; 33 | 34 | timerRef.current = setInterval(() => { 35 | current--; 36 | setSecond(current); 37 | }, 1000); 38 | 39 | return () => { 40 | timerRef.current && clearInterval(timerRef.current); 41 | }; 42 | }, []); 43 | 44 | useEffect(() => { 45 | if (second === 0) { 46 | timerRef.current && clearInterval(timerRef.current); 47 | } 48 | }, [second]); 49 | 50 | return ( 51 | 0 : false, 59 | }, 60 | ]} 61 | onAction={() => { 62 | if (second) return; 63 | setShow(false); 64 | onClose?.(); 65 | }} 66 | content={ 67 | <> 68 | {warning ? : null} 69 | 70 |
71 | {content.map( 72 | (s, i): React.ReactNode => 73 | typeof s === "string" ? ( 74 |
75 | {s} 76 |
77 | ) : ( 78 | s 79 | ), 80 | )} 81 |
82 | 83 | } 84 | /> 85 | ); 86 | }; 87 | 88 | export default Alert; 89 | -------------------------------------------------------------------------------- /src/components/footer.tsx: -------------------------------------------------------------------------------- 1 | import { Footer } from "antd-mobile"; 2 | 3 | const SiteFooter = () => ( 4 |