diff --git a/.gitignore b/.gitignore index 4f04301..cf57b40 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ sandboxes/ # 系统文件 .DS_Store Thumbs.db +.env diff --git a/agents/planner/agent/models.json b/agents/planner/agent/models.json index 1c88b09..c5d0e43 100644 --- a/agents/planner/agent/models.json +++ b/agents/planner/agent/models.json @@ -1,81 +1,113 @@ { - "providers": { - "new-api": { - "baseUrl": "http://192.168.2.74:3000/v1", - "apiKey": "sk-vaYyq9RwzyLlvAvHHUXzOTWkbioP76YW58vKuplq2npSkfZr", - "api": "openai-completions", - "request": { - "allowPrivateNetwork": true - }, - "models": [ - { - "id": "deepseek-v4-flash", - "name": "DeepSeek V4 Flash", - "reasoning": false, - "input": [ - "text" - ], - "cost": { - "input": 0, - "output": 0, - "cacheRead": 0, - "cacheWrite": 0 - }, - "contextWindow": 131072, - "maxTokens": 8192 - }, - { - "id": "qwen3.7-max", - "name": "Qwen 3.7 Max", - "reasoning": false, - "input": [ - "text", - "image" - ], - "cost": { - "input": 0, - "output": 0, - "cacheRead": 0, - "cacheWrite": 0 - }, - "contextWindow": 131072, - "maxTokens": 32768 - }, - { - "id": "qwen3.5-plus", - "name": "Qwen 3.5 Plus", - "reasoning": false, - "input": [ - "text", - "image" - ], - "cost": { - "input": 0, - "output": 0, - "cacheRead": 0, - "cacheWrite": 0 - }, - "contextWindow": 131072, - "maxTokens": 32768 - }, - { - "id": "glm-5.1", - "name": "GLM 5.1", - "reasoning": false, - "input": [ - "text", - "image" - ], - "cost": { - "input": 0, - "output": 0, - "cacheRead": 0, - "cacheWrite": 0 - }, - "contextWindow": 131072, - "maxTokens": 32768 - } - ] + "providers": { + "new-api": { + "baseUrl": "http://192.168.2.74:3000/v1", + "apiKey": "sk-vaYyq9RwzyLlvAvHHUXzOTWkbioP76YW58vKuplq2npSkfZr", + "api": "openai-completions", + "request": { + "allowPrivateNetwork": true + }, + "models": [ + { + "id": "qwen3.7-max", + "name": "Qwen 3.7 Max", + "reasoning": false, + "input": [ + "text", + "image" + ], + "cost": { + "input": 0, + "output": 0, + "cacheRead": 0, + "cacheWrite": 0 + }, + "contextWindow": 131072, + "maxTokens": 32768 + }, + { + "id": "deepseek-v4-pro", + "name": "DeepSeek V4 Pro", + "reasoning": false, + "input": [ + "text" + ], + "cost": { + "input": 0, + "output": 0, + "cacheRead": 0, + "cacheWrite": 0 + }, + "contextWindow": 131072, + "maxTokens": 32768 + }, + { + "id": "deepseek-v4-flash", + "name": "DeepSeek V4 Flash", + "reasoning": false, + "input": [ + "text" + ], + "cost": { + "input": 0, + "output": 0, + "cacheRead": 0, + "cacheWrite": 0 + }, + "contextWindow": 131072, + "maxTokens": 8192 + }, + { + "id": "glm-5.1", + "name": "GLM 5.1", + "reasoning": false, + "input": [ + "text", + "image" + ], + "cost": { + "input": 0, + "output": 0, + "cacheRead": 0, + "cacheWrite": 0 + }, + "contextWindow": 131072, + "maxTokens": 32768 + }, + { + "id": "kim-k2.6", + "name": "Kimi K2.6", + "reasoning": false, + "input": [ + "text" + ], + "cost": { + "input": 0, + "output": 0, + "cacheRead": 0, + "cacheWrite": 0 + }, + "contextWindow": 131072, + "maxTokens": 32768 + }, + { + "id": "qwen3.5-plus", + "name": "Qwen 3.5 Plus", + "reasoning": false, + "input": [ + "text", + "image" + ], + "cost": { + "input": 0, + "output": 0, + "cacheRead": 0, + "cacheWrite": 0 + }, + "contextWindow": 131072, + "maxTokens": 32768 } + ] } -} \ No newline at end of file + } +} diff --git a/cache/shell-snapshots/8bdc13fe25b20cd09559b8350857f9917c373ff8fc3e34212c5b7ad54d7d1fc0.sh b/cache/shell-snapshots/8bdc13fe25b20cd09559b8350857f9917c373ff8fc3e34212c5b7ad54d7d1fc0.sh new file mode 100644 index 0000000..e76e47b --- /dev/null +++ b/cache/shell-snapshots/8bdc13fe25b20cd09559b8350857f9917c373ff8fc3e34212c5b7ad54d7d1fc0.sh @@ -0,0 +1,26 @@ +# OpenClaw exec shell snapshot. Generated; do not edit. +if [ -n "${BASH_VERSION:-}" ]; then shopt -s expand_aliases 2>/dev/null || true; fi +unalias -a 2>/dev/null || true +alias egrep='egrep --color=auto' +alias fgrep='fgrep --color=auto' +alias grep='grep --color=auto' +alias l='ls -CF' +alias la='ls -A' +alias ll='ls -alF' +alias ls='ls --color=auto' +command_not_found_handle () +{ + if [ -x /usr/lib/command-not-found ]; then + /usr/lib/command-not-found -- "$1"; + return $?; + else + if [ -x /usr/share/command-not-found/command-not-found ]; then + /usr/share/command-not-found/command-not-found -- "$1"; + return $?; + else + printf "%s: command not found\n" "$1" 1>&2; + return 127; + fi; + fi +} +export PATH='/root/.nvm/versions/node/v24.18.1/bin:/usr/bin:/bin:/usr/local/bin:/root/.nvm/current/bin:/root/.local/bin:/root/.npm-global/bin:/root/bin:/root/.nix-profile/bin:/root/.local/share/pnpm' \ No newline at end of file diff --git a/identity/device-auth.json b/identity/device-auth.json index dc17158..9808f0f 100644 --- a/identity/device-auth.json +++ b/identity/device-auth.json @@ -3,16 +3,12 @@ "deviceId": "e8510d8b751c9065aebddecb8951b0283fce5457af923f81b6d4a6bd72d421e7", "tokens": { "operator": { - "token": "2720025facf8497986551236793037ea", + "token": "qmmu-2Qk84qMJtYcJei6Jw2sQvmGwx0-vgihHe2AhSQ", "role": "operator", "scopes": [ - "operator.admin", - "operator.approvals", - "operator.pairing", - "operator.read", - "operator.write" + "operator.read" ], - "updatedAtMs": 1784020866140 + "updatedAtMs": 1785744116242 } } } diff --git a/openclaw.json b/openclaw.json index 7ff1da7..e20b53b 100644 --- a/openclaw.json +++ b/openclaw.json @@ -17,7 +17,7 @@ "providers": { "new-api": { "baseUrl": "http://192.168.2.74:3000/v1", - "apiKey": "sk-vaYyq9RwzyLlvAvHHUXzOTWkbioP76YW58vKuplq2npSkfZr", + "apiKey": "${NEW_API_KEY}", "api": "openai-completions", "request": { "allowPrivateNetwork": true @@ -161,6 +161,15 @@ }, "sandbox": { "mode": "off" + }, + "memorySearch": { + "enabled": true, + "provider": "openai-compatible", + "model": "BAAI/bge-m3", + "remote": { + "baseUrl": "https://api.siliconflow.cn/v1", + "apiKey": "$SILICONFLOW_API_KEY" + } } }, "list": [ @@ -213,7 +222,7 @@ }, "agentToAgent": { "enabled": true, - "allow": ["planner", "backend", "sql", "travel", "fitness", "finances", "juaner"] + "allow": ["planner", "backend", "frontend"] }, "deny": [ "group:web", @@ -449,15 +458,6 @@ }, "browser": { "enabled": false - }, - "ezviz": { - "enabled": false - }, - "openclaw-weixin": { - "enabled": false - }, - "dingtalk-connector": { - "enabled": false } }, "bundledDiscovery": "compat" diff --git a/workspace-attestations/0c7b240386c2ff0dc0802cc3e9ce7542eb8de19a15809148f907a6e836ef62d5.attested b/workspace-attestations/0c7b240386c2ff0dc0802cc3e9ce7542eb8de19a15809148f907a6e836ef62d5.attested index 0b9d1da..1e4d6d1 100644 --- a/workspace-attestations/0c7b240386c2ff0dc0802cc3e9ce7542eb8de19a15809148f907a6e836ef62d5.attested +++ b/workspace-attestations/0c7b240386c2ff0dc0802cc3e9ce7542eb8de19a15809148f907a6e836ef62d5.attested @@ -1,3 +1,2 @@ openclaw-workspace-attestation:v1 -2026-08-03T07:43:41.248Z -generated:USER.md:e418ca9a680553b3ad8f54aecb0d403330810bb77826ab5251cc1dc13368fe16 +2026-08-03T08:31:43.211Z diff --git a/workspace-attestations/291b60b61915ad7883255cc3e467f3d4c7328d3057ad9b3078735710540c8051.attested b/workspace-attestations/291b60b61915ad7883255cc3e467f3d4c7328d3057ad9b3078735710540c8051.attested index bdd664f..03281d7 100644 --- a/workspace-attestations/291b60b61915ad7883255cc3e467f3d4c7328d3057ad9b3078735710540c8051.attested +++ b/workspace-attestations/291b60b61915ad7883255cc3e467f3d4c7328d3057ad9b3078735710540c8051.attested @@ -1,2 +1,2 @@ openclaw-workspace-attestation:v1 -2026-08-03T06:59:43.692Z +2026-08-03T07:49:18.452Z diff --git a/workspace-attestations/7998712e71dadc13b041354cd823ffc4867a7504adb2222b73b483beacc96d18.attested b/workspace-attestations/7998712e71dadc13b041354cd823ffc4867a7504adb2222b73b483beacc96d18.attested index bf32f5b..eeb1e4c 100644 --- a/workspace-attestations/7998712e71dadc13b041354cd823ffc4867a7504adb2222b73b483beacc96d18.attested +++ b/workspace-attestations/7998712e71dadc13b041354cd823ffc4867a7504adb2222b73b483beacc96d18.attested @@ -1,2 +1,2 @@ openclaw-workspace-attestation:v1 -2026-08-03T07:23:35.859Z +2026-08-03T08:31:12.922Z diff --git a/workspace-backend/.clawhub/lock.json b/workspace-backend/.clawhub/lock.json new file mode 100644 index 0000000..d86b4b5 --- /dev/null +++ b/workspace-backend/.clawhub/lock.json @@ -0,0 +1,405 @@ +{ + "version": 1, + "skills": { + "sql-toolkit": { + "version": "1.0.0", + "installedAt": 1785744535727, + "registry": "https://clawhub.ai", + "ownerHandle": "gitgoodordietrying", + "artifact": { + "kind": "archive", + "sha256": "4f48da99f3b1beb878195590b3ed1c6a469ce554498831abdee42ca27468959f", + "integrity": "sha256-T0jamfOxvrh4GVWQs+0cakac5VRJiDGr3uQsonRolZ8=" + }, + "skillFile": { + "path": "SKILL.md", + "sha256": "515ecf904449a3cd5ebb92e85e54127e216d9483ee9111705e75e686a0694285" + }, + "verification": { + "schema": "clawhub.skill.verify.v1", + "ok": true, + "decision": "pass", + "reasons": [], + "card": { + "available": true, + "path": "skill-card.md", + "url": "https://wry-manatee-359.convex.site/api/v1/skills/sql-toolkit/card?ownerHandle=gitgoodordietrying&version=1.0.0", + "sha256": "ecf10f8b45e67a00ae6b5c6ef5438feb44cd33f505666b4362c506172d39848d", + "size": 1998, + "contentType": "text/markdown; charset=utf-8" + }, + "artifact": { + "sourceFingerprint": "d90603335b0cc1e00d6da8eac9e1345d52453b894578bd2e8590fa20b1475484", + "bundleFingerprints": [ + "b99edda9c4d7b4e0a78f172715644da5955da8bad18563789b4903f734c0baa2" + ], + "files": [ + { + "path": "SKILL.md", + "size": 12080, + "sha256": "515ecf904449a3cd5ebb92e85e54127e216d9483ee9111705e75e686a0694285", + "contentType": "text/markdown" + } + ] + }, + "provenance": { + "source": "unavailable", + "reason": "No server-resolved GitHub import provenance is stored for this version." + }, + "security": { + "status": "clean", + "passed": true, + "rawStatus": "clean", + "verdict": "benign", + "confidence": "high", + "summary": "This SQL helper skill is purpose-aligned documentation for database command-line workflows, with no evidence of hidden behavior or malicious activity, but users should be careful with restore examples that can overwrite data.", + "model": "gpt-5.5", + "checkedAt": 1783656186394, + "signals": { + "staticScan": { + "status": "clean", + "rawStatus": "clean", + "reasonCodes": [], + "summary": "No suspicious patterns detected.", + "engineVersion": "v2.4.5", + "checkedAt": 1777524980775 + }, + "virusTotal": { + "status": "clean", + "rawStatus": "clean", + "verdict": "benign", + "analysis": "Type: OpenClaw Skill\nName: sql-toolkit\nVersion: 1.0.0\n\nThe skill bundle is benign. It provides comprehensive documentation and examples for interacting with SQL databases (SQLite, PostgreSQL, MySQL) using standard command-line tools. While the skill inherently involves powerful commands with file system and network access (e.g., `psql`, `mysql`, `sqlite3`, `pg_dump`, `mysqldump`), all examples and instructions in `SKILL.md` are aligned with the stated purpose of a 'SQL Toolkit' and demonstrate legitimate, common database operations. There is no evidence of prompt injection, data exfiltration, malicious execution, persistence, or obfuscation.", + "source": "palm", + "scanner": "code_insight", + "engineStats": { + "harmless": 0, + "malicious": 0, + "suspicious": 0, + "undetected": 64 + }, + "checkedAt": 1779161171837 + }, + "skillSpector": { + "status": "clean", + "rawStatus": "clean", + "score": 8, + "severity": "LOW", + "recommendation": "SAFE", + "issueCount": 1, + "scannerVersion": "2.3.5", + "summary": null, + "error": null, + "checkedAt": 1783656142755 + }, + "dependencyRegistry": null + } + }, + "signature": { + "status": "unsigned" + } + } + }, + "qiushi-openclaw-skill": { + "version": "1.0.0", + "installedAt": 1785745381570, + "registry": "https://clawhub.ai", + "ownerHandle": "skytodmoon", + "artifact": { + "kind": "archive", + "sha256": "1e2d3712d2974143449c9e47b0379725a954794c498727799f782ac7b1db7a49", + "integrity": "sha256-Hi03EtKXQUNEnJ5HsDeXJalUeUxJhyd5n3gqx7Hbekk=" + }, + "skillFile": { + "path": "SKILL.md", + "sha256": "b21d933b7f61584d2254fba25fd531c16f19e33e10016ddfbdea1a5e2d5d6d25" + }, + "verification": { + "schema": "clawhub.skill.verify.v1", + "ok": true, + "decision": "pass", + "reasons": [], + "card": { + "available": true, + "path": "skill-card.md", + "url": "https://wry-manatee-359.convex.site/api/v1/skills/qiushi-openclaw-skill/card?ownerHandle=skytodmoon&version=1.0.0", + "sha256": "7ffcf0eaab78e22dc18592df90bce922535f9ce092c53c3a68f5d020f698e081", + "size": 2044, + "contentType": "text/markdown; charset=utf-8" + }, + "artifact": { + "sourceFingerprint": "1d39ab4575f3ffec359865c03bed700ee3426f57f61d9fa9dad153fc60e5a3ae", + "bundleFingerprints": [ + "8864f859b5a5b919d08ed0da8d37a79d4e5276ffd32a564ebe650f637423e296" + ], + "files": [ + { + "path": "README.md", + "size": 3652, + "sha256": "3454e7472626a033616d7d9f89c0ecf6b11aa5172774f0c07bca694c9d115f1f", + "contentType": "text/x-markdown" + }, + { + "path": "SKILL.md", + "size": 2385, + "sha256": "b21d933b7f61584d2254fba25fd531c16f19e33e10016ddfbdea1a5e2d5d6d25", + "contentType": "text/x-markdown" + }, + { + "path": "investigation-first/clawhub.json", + "size": 387, + "sha256": "48159dc63edec35d2ea36df30cb028bc89d5adf7e873e0bbd98c2b559b72d04b", + "contentType": "application/json" + }, + { + "path": "investigation-first/README.md", + "size": 2766, + "sha256": "edc308afbcffb36f40f9e925e13dcc24f7c8b361af3a7c7c45af80f76cc96c3e", + "contentType": "text/x-markdown" + }, + { + "path": "investigation-first/SKILL.md", + "size": 2309, + "sha256": "101212ce1723aaf92f7503b77fff35edbcccf22830dbe2f0f43cb995c166da2d", + "contentType": "text/x-markdown" + }, + { + "path": "practice-cognition/clawhub.json", + "size": 380, + "sha256": "68bf1d476a88950059cb7dc52e78dee5583f7114472237bb2824d190119e9add", + "contentType": "application/json" + }, + { + "path": "practice-cognition/README.md", + "size": 2659, + "sha256": "addd5a3c69d8559e659f507127877823727e03cdec2da0346c4a5dae4306b1bb", + "contentType": "text/x-markdown" + }, + { + "path": "practice-cognition/SKILL.md", + "size": 2457, + "sha256": "204872d8135301e2ed07b696ef63dbe4081cce1ed3235221843fd4f97a0f42e9", + "contentType": "text/x-markdown" + }, + { + "path": "concentrate-forces/clawhub.json", + "size": 380, + "sha256": "683dc297ed5d0f8a0b223f543fe54d445e8ebcaa39cd65d59cdca07e843f772c", + "contentType": "application/json" + }, + { + "path": "concentrate-forces/README.md", + "size": 2731, + "sha256": "1666b93bcfdf78520b492bc196a901d465ce637c7d3b08520163a5f0609ff962", + "contentType": "text/x-markdown" + }, + { + "path": "concentrate-forces/SKILL.md", + "size": 2253, + "sha256": "207b28f78ecb81d7c54f2ac8c6b3cdd58b4e10775a8e92f2f026bc3310d6f123", + "contentType": "text/x-markdown" + }, + { + "path": "contradiction-analysis/clawhub.json", + "size": 423, + "sha256": "ef00074e7841d1698c0f0ea74c9e9dfc9e0923452e3d1475216bf945f147fd80", + "contentType": "application/json" + }, + { + "path": "contradiction-analysis/README.md", + "size": 3012, + "sha256": "b4eeae7b315e024bf2c9f49d388d627cf2b0c3304d92d449f0c86abc3ee8d4b4", + "contentType": "text/x-markdown" + }, + { + "path": "contradiction-analysis/SKILL.md", + "size": 2919, + "sha256": "1fd24138f9ab3b4bab002a771978356c673c24c7a5dce6c7acb37dc271dcd385", + "contentType": "text/x-markdown" + }, + { + "path": "mass-line/clawhub.json", + "size": 356, + "sha256": "bac70025aedd0465607cbca72996bdf705a7d3a75c50bcc5da29c18147dee980", + "contentType": "application/json" + }, + { + "path": "mass-line/README.md", + "size": 2632, + "sha256": "1c3c76199aa50ec1eca70b0463c42e09227777265a74e9f4b487483a8c5b5307", + "contentType": "text/x-markdown" + }, + { + "path": "mass-line/SKILL.md", + "size": 2169, + "sha256": "f215fdf997b02cf314b6ba0e03e2425aae20904f55c4ce7734dcc8c32f64b78e", + "contentType": "text/x-markdown" + }, + { + "path": "protracted-strategy/clawhub.json", + "size": 372, + "sha256": "5f54232101b8b48a38452b9cf69f9824914bb834cb03f06f4c0afc59429947dc", + "contentType": "application/json" + }, + { + "path": "protracted-strategy/README.md", + "size": 2954, + "sha256": "d92f25b8ebfd8cd8999e56dbf79727e96f6c1502860dd2f37138795bea65e40e", + "contentType": "text/x-markdown" + }, + { + "path": "protracted-strategy/SKILL.md", + "size": 2418, + "sha256": "7a69b073927a7426a01dc8e2979297f9a9b90f7b450e853bf2b877fb174422d2", + "contentType": "text/x-markdown" + }, + { + "path": "workflows/clawhub.json", + "size": 392, + "sha256": "77497954f506f25351f35cf4e541a2e533501056ce7418b434ee24c6b9438ca4", + "contentType": "application/json" + }, + { + "path": "workflows/README.md", + "size": 2871, + "sha256": "5b16dd2a4d5093494ace5d201c85d7cfd5e3409a93cb50176e269a987e0a7bc9", + "contentType": "text/x-markdown" + }, + { + "path": "workflows/SKILL.md", + "size": 2448, + "sha256": "183fd3caa21f6ff5ebc9e725b59f4a0be3d83e5fdeb8587eb6d0b22859b768b1", + "contentType": "text/x-markdown" + }, + { + "path": "overall-planning/clawhub.json", + "size": 363, + "sha256": "1e4a7014f0745993be50e1dd2813af364592e6cfbd87b68456c46543b6fc9797", + "contentType": "application/json" + }, + { + "path": "overall-planning/README.md", + "size": 2912, + "sha256": "68c2f97a23befb87a11c612d862c0a77b5544a2cd8cd4e1f8bd2ba91c3eb9620", + "contentType": "text/x-markdown" + }, + { + "path": "overall-planning/SKILL.md", + "size": 2403, + "sha256": "b3fdc6991bc211c2e83981e7ce53facfa1014cb7325452826cfc22ce056e36af", + "contentType": "text/x-markdown" + }, + { + "path": "spark-prairie-fire/clawhub.json", + "size": 383, + "sha256": "17981f22cf824e28c2d770bcc21c9aa5087476326004eaae138b96a7b4fc4eae", + "contentType": "application/json" + }, + { + "path": "spark-prairie-fire/README.md", + "size": 2710, + "sha256": "06a95aeafad95d606a742e4b99cb8ad257aeb65321305d318bbbf9b324299e63", + "contentType": "text/x-markdown" + }, + { + "path": "spark-prairie-fire/SKILL.md", + "size": 2232, + "sha256": "e0eac250f3046cfcd8cdd95c3bd780ccefe7e9efbcb62de0a73f80986e78b2a8", + "contentType": "text/x-markdown" + }, + { + "path": "arming-thought/clawhub.json", + "size": 450, + "sha256": "0a7cc0fb2129be03444e2fec5e8fb505cfcadbe2ed58ebef1fc37aaed28a0211", + "contentType": "application/json" + }, + { + "path": "arming-thought/README.md", + "size": 1955, + "sha256": "6f1d3d9a0abcd5ad8fc90a1e0d18207d7e97ab53d947894aef049adf8807bdb2", + "contentType": "text/x-markdown" + }, + { + "path": "arming-thought/SKILL.md", + "size": 2271, + "sha256": "6fa2855bcb06d1a136d916c9a07124dbd50adaac75b8037c86882b4c6c430735", + "contentType": "text/x-markdown" + }, + { + "path": "criticism-self-criticism/clawhub.json", + "size": 407, + "sha256": "eda46316ce74edbf78c7210005d2785f1c2dbe7c0e8ae6809adb8f75a5e90e41", + "contentType": "application/json" + }, + { + "path": "criticism-self-criticism/README.md", + "size": 2811, + "sha256": "d90d58b4e5707bdf4635aa85e147422bf8d18d79b3c4d24864f4f3fa7d7ad3e3", + "contentType": "text/x-markdown" + }, + { + "path": "criticism-self-criticism/SKILL.md", + "size": 2369, + "sha256": "1f01760dbdffa7cd5acb95365e7866692d72c89061ed2240a05bbe1056794002", + "contentType": "text/x-markdown" + } + ] + }, + "provenance": { + "source": "unavailable", + "reason": "No server-resolved GitHub import provenance is stored for this version." + }, + "security": { + "status": "clean", + "passed": true, + "rawStatus": "clean", + "verdict": "benign", + "confidence": "high", + "summary": "This is a disclosed Chinese-language methodology skill pack that guides reasoning and planning without requesting tools, credentials, file access, network access, or persistence.", + "model": "gpt-5.5", + "checkedAt": 1779973863935, + "signals": { + "staticScan": { + "status": "clean", + "rawStatus": "clean", + "reasonCodes": [], + "summary": "No suspicious patterns detected.", + "engineVersion": "v2.4.5", + "checkedAt": 1777527313505 + }, + "virusTotal": { + "status": "clean", + "rawStatus": "clean", + "verdict": null, + "analysis": null, + "source": "engines", + "scanner": null, + "engineStats": { + "harmless": 0, + "malicious": 0, + "suspicious": 0, + "undetected": 65 + }, + "checkedAt": 1780086996288 + }, + "skillSpector": { + "status": "suspicious", + "rawStatus": "suspicious", + "score": 100, + "severity": "CRITICAL", + "recommendation": "DO_NOT_INSTALL", + "issueCount": 16, + "scannerVersion": "2.0.0", + "summary": null, + "error": null, + "checkedAt": 1779973821578 + }, + "dependencyRegistry": null + } + }, + "signature": { + "status": "unsigned" + } + } + } + } +} diff --git a/workspace-backend/TOOLS.md b/workspace-backend/TOOLS.md index a8ee284..6ef8539 100644 --- a/workspace-backend/TOOLS.md +++ b/workspace-backend/TOOLS.md @@ -23,3 +23,24 @@ ## 项目别名 - `wit` → `/root/projects/wit`(前端 mica-web / 后端 mica-server / 文档 mica-doc) + +## mica 项目数据库配置 + +**连接信息:** +- 主机:`47.99.209.185:50036` +- 用户:`witsoftd` +- 密码:见密码管理器 + +**数据库列表:** +| 数据库 | 用途 | +|--------|------| +| `dmp_serp` | ERP 相关 | +| `dmp_smdm` | 主数据管理 | +| `dmp_smes` | 制造执行系统 | +| `dmp_spom` | 订单管理 | +| `dmp_secm` | 安全管理 | +| `dmp_sportal` | 门户系统 | + +**相关系统:** `witdmp_edge/scheduler/workflow`、`witdn_lcdp/server`、`witprint`、`nacos_k8s`、`tenant` + +**技能:** sql-toolkit(`/root/.openclaw/workspace-backend/skills/sql-toolkit/SKILL.md`) diff --git a/workspace-backend/memory/2026-05-23.md b/workspace-backend/memory/2026-05-23.md deleted file mode 100644 index 342702b..0000000 --- a/workspace-backend/memory/2026-05-23.md +++ /dev/null @@ -1,88 +0,0 @@ -# 2026-05-23 会话记忆 - -## 项目:tiny-erp - -### 核心决策 - -1. **包路径确定**:`com.witsoft.erp`(不是 com.example 或 com.witsoft.tinyerp) - - tiny 是项目别名,包名使用正式名称 erp - -2. **技术栈确认**: - - JDK 11+(不是 1.8) - - Spring Boot 2.7.18 - - MyBatis Plus 3.5.3.1 - - PostgreSQL 14+ - - Spring Security + JWT (jjwt 0.11.5) - - SpringDoc OpenAPI 3(不是 Knife4j) - -3. **多租户方案**:ecid 字段隔离 + TenantLineHandler 自动拦截 - - 系统表(sys_*)不进行租户隔离(登录时需要查询) - - 业务表全部需要 ecid 隔离 - - **所有表的 ecid 字段为 NOT NULL** - -4. **API 设计规范**: - - 分页列表接口使用 POST(不是 GET) - - 请求体携带查询条件 + 分页参数 - - 统一返回格式:{code, message, data} - -5. **异常处理规范**: - - BusinessException 支持自定义错误码 - - GlobalExceptionHandler 统一处理各类异常 - - 参数校验失败返回 400 + 具体错误信息 - -6. **模块命名**:基础数据模块(bd)替代主数据模块(md) - -### 已完成模块 - -| 模块 | 功能 | 状态 | -|------|------|------| -| system | 租户、用户、字典、JWT 认证 | ✅ | -| bd | 物料分类、工厂、仓库、物料 | ✅ | -| om | 销售订单、发货单(含库存扣减) | ✅ | -| mc | 采购订单 | ✅ | -| im | 库存查询、库存流水 | ✅ | - -### 数据库脚本结构 - -``` -scripts/postgresql/ -├── 00-init.sql # 数据库初始化 -├── 10-system.sql # 系统模块 -├── 20-basic-data.sql # 基础数据模块 -├── 30-sales.sql # 销售模块 -├── 40-purchase.sql # 采购模块 -├── 50-inventory.sql # 库存模块 -└── 99-data.sql # 初始化数据 -``` - -### 默认账号 - -- admin / admin123 / default -- test / admin123 / default - -### 待开发功能 - -1. 采购收货单 + 库存增加(P0) -2. 销售退货单(P1) -3. 采购申请单(P1) -4. 库存调拨(P1) -5. 库存盘点(P1) -6. 操作日志、登录日志(P1/P2) -7. 报表统计(P2) - -### 关键代码位置 - -- JWT 工具:`framework/security/JwtUtil.java` -- 租户上下文:`framework/tenant/TenantContext.java` -- 租户拦截器:`framework/tenant/TenantLineHandlerImpl.java` -- 全局异常:`common/core/GlobalExceptionHandler.java` -- 业务异常:`common/core/BusinessException.java` - -### 文档位置 - -- README.md:项目根目录 -- 开发方案:`yangxuan/设计/01-开发方案.md` - ---- - -> ⚠️ 2026-05-26: 当前只关注 md(主数据)和 im(库存)模块。om/mc/fin/system/home 代码已存在但不再关注。 diff --git a/workspace-backend/memory/2026-05-25.md b/workspace-backend/memory/2026-05-25.md deleted file mode 100644 index 8ab7a81..0000000 --- a/workspace-backend/memory/2026-05-25.md +++ /dev/null @@ -1,517 +0,0 @@ -# 2026-05-25 会话记录 - -## 系统模块开发(2026-05-25 13:28) - -### 完成的工作 - -1. **操作日志功能** - - 实体类:`OperLog.java` - - Mapper:`OperLogMapper.java` - - Service:`OperLogService.java` + `OperLogServiceImpl.java` - - Controller:`OperLogController.java` - - 切面:`LogAspect.java`(自动记录带@Log 注解的方法) - - 注解:`@Log`(module、businessType、isSaveRequestData、isSaveResponseData) - -2. **数据字典增强** - - 新增方法:`listDataBatch()` - 批量获取字典数据 - - 新增方法:`listOptions()` - 前端下拉框格式 [{label, value}] - - 新增方法:`listOptionsBatch()` - 批量获取下拉框选项 - - 新增接口:`GET /system/dict/data/options/batch?dictTypes=xxx,yyy` - -3. **文档** - - `04-系统模块开发指南.md` - 包含使用示例、API 文档、前端集成示例 - -### 业务类型枚举 - -| 值 | 含义 | -|----|------| -| 0 | 其它 | -| 1 | 新增 | -| 2 | 修改 | -| 3 | 删除 | -| 4 | 导出 | -| 5 | 导入 | -| 6 | 审核 | - -### 已初始化字典 - -- `inbound_type` - 入库类型(采购入库、退货入库、其他入库) -- `outbound_type` - 出库类型(销售出库、领料出库、其他出库) -- `stocktake_diff_result` - 盘点结果(相符、盘盈、盘亏) -- `payment_method` - 收付款方式(现金、银行转账、承兑汇票) - -### 下一步 - -- 主数据模块开发(供应商、客户) ✓ -- 库存模块开发(入库单、出库单) ✓ -- 财务模块开发(应收、应付、收款、付款) -- 首页模块开发 ✓ - ---- - -## 首页模块开发(2026-05-25 15:15) - -### 完成的工作 - -1. **欢迎信息接口** - - `GET /home/welcome` - 返回欢迎语、用户名、企业名、日期、问候语 - - 根据时间段自动切换问候语(早上好/中午好/下午好/晚上好/夜深了) - - DTO:`HomeWelcomeResDTO.java` - -2. **最新动态接口** - - `GET /home/news` - 返回最近 20 条业务动态 - - 动态类型:入库完成、出库完成、盘点完成、新增供应商、新增客户 - - 按时间倒序排列 - - DTO:`HomeNewsItemDTO.java` - -3. **文件清单** - - `HomeController.java` - 首页控制器 - - `HomeService.java` / `HomeServiceImpl.java` - 首页服务 - - `HomeWelcomeResDTO.java` - 欢迎信息响应 - - `HomeNewsItemDTO.java` - 动态项 DTO - -### API 示例 - -```http -GET /home/welcome -→ { welcome: "欢迎", userName: "张三", companyName: "某某公司", greeting: "下午好" } - -GET /home/news -→ [ { type: "inbound", title: "入库完成", content: "RK202605250001 - 成品仓", operator: "张三", operateTime: "..." } ] -``` - -### TODO - -- 从用户会话/配置中获取真实用户名和企业名(当前为默认值) - ---- - -## 库存模块增强(2026-05-25 14:26) - -### 完成的工作 - -1. **入库单管理 CRUD** - - 实体:`Inbound.java` + `InboundItem.java` - - DTO:`InboundSaveReqDTO.java` + `InboundItemSaveReqDTO.java` - - Mapper:`InboundMapper.java` + `InboundItemMapper.java` - - Service:`InboundService.java` + `InboundServiceImpl.java` - - Controller:`InboundController.java` - - API:分页查询、详情、明细、新增、修改、审核、作废、删除 - - 审核逻辑:检查状态 → 更新状态 → 增加库存 - - 作废逻辑:检查状态 → 更新状态 → 扣减库存 - -2. **出库单管理 CRUD** - - 实体:`Outbound.java` + `OutboundItem.java` - - DTO:`OutboundSaveReqDTO.java` + `OutboundItemSaveReqDTO.java` - - Mapper:`OutboundMapper.java` + `OutboundItemMapper.java` - - Service:`OutboundService.java` + `OutboundServiceImpl.java` - - Controller:`OutboundController.java` - - API:分页查询、详情、明细、新增、修改、审核、作废、删除 - - 审核逻辑:检查状态 → **检查库存充足** → 更新状态 → 扣减库存 - - 作废逻辑:检查状态 → 更新状态 → 恢复库存 - -3. **盘点单管理 CRUD** - - 实体:`Stocktake.java` + `StocktakeItem.java` - - DTO:`StocktakeSaveReqDTO.java` + `StocktakeItemSaveReqDTO.java` - - Mapper:`StocktakeMapper.java` + `StocktakeItemMapper.java` - - Service:`StocktakeService.java` + `StocktakeServiceImpl.java` - - Controller:`StocktakeController.java` - - API:分页查询、详情、明细、新增、修改、审核、作废、删除 - - 审核逻辑:计算差异 → 设置盘点结果 → **调整库存**(盘盈 +,盘亏 -) - - 作废逻辑:反向调整库存 - -4. **库存服务增强** - - 新增方法:`addStock()` - 入库单调用(包含物料信息) - - 新增方法:`reduceStock()` - 出库单调用 - - 新增方法:`checkStock()` - 检查库存是否充足 - -5. **文档** - - `06-库存模块开发指南.md` - 完整 API 文档、业务流程、测试示例 - -### 业务类型字典 - -| 类型 | 值 | 标签 | -|------|-----|------| -| inbound_type | 10 | 采购入库 | -| inbound_type | 20 | 退货入库 | -| inbound_type | 30 | 其他入库 | -| outbound_type | 10 | 销售出库 | -| outbound_type | 20 | 领料出库 | -| outbound_type | 30 | 其他出库 | -| stocktake_diff_result | 0 | 相符 | -| stocktake_diff_result | 1 | 盘盈 | -| stocktake_diff_result | 2 | 盘亏 | - -### 状态流转 - -``` -草稿 (0) → 已审核 (1) → 已作废 (2) -``` - -### 编译状态 - -``` -✅ mvn compile 成功 -``` - ---- - -## 主数据模块开发(2026-05-25 13:46) - -### 完成的工作 - -1. **供应商管理 CRUD** - - 实体:`Supplier.java`(name、contact、mobile 等简洁字段) - - DTO:`SupplierSaveReqDTO.java` - - Mapper:`SupplierMapper.java` - - Service:`SupplierService.java` + `SupplierServiceImpl.java` - - Controller:`SupplierController.java` - - API:分页查询、列表、详情、新增、修改、删除 - - 操作日志:@Log 注解自动记录 - -2. **客户管理 CRUD** - - 实体:`Customer.java`(增加 level 客户级别字段) - - DTO:`CustomerSaveReqDTODTO.java` - - Mapper:`CustomerMapper.java` - - Service:`CustomerService.java` + `CustomerServiceImpl.java` - - Controller:`CustomerController.java` - - API:分页查询、列表、详情、新增、修改、删除 - - 操作日志:@Log 注解自动记录 - -3. **文档** - - `05-主数据模块开发指南.md` - 包含 API 文档、前端集成示例 - -### 设计特点 - -- 字段命名参考 ruoyi-pro:`name`、`contact`、`mobile`(简洁风格) -- 必填字段仅 `name`,支持快捷新增 -- 客户级别:10-普通、20-重要、30-VIP(字典数据管理) -- 所有操作自动记录日志 - -### 编译状态 - -``` -✅ mvn compile 成功 -``` - ---- - -## Tiny-ERP 表架构设计与实现 - -### 完成的工作 - -1. **表架构设计文档** - - 位置:`/home/yangxuan/Projects/IdeaProjects/tiny-erp/yangxuan/设计/表架构设计.md` - - 参考项目:ruoyi-vue-pro(别名 ruoyi-pro) - - 设计原则:务实、简洁、不过度设计 - -2. **SQL 脚本生成与执行** - - `20-master-data.sql` - 主数据模块(供应商、客户表参考 ruoyi-pro 风格) - - `50-inventory.sql` - 库存模块(入库/出库/盘点单及明细) - - `60-finance.sql` - 财务模块(应收/应付/收款/付款及核销明细) - - `99-data.sql` - 初始化数据(修复为幂等脚本) - -3. **数据库表统计** - - 系统模块:5 表(含操作日志) - - 主数据:6 表(供应商、客户) - - 销售:4 表 - - 采购:2 表 - - 库存:8 表(入库/出库/盘点) - - 财务:8 表(应收/应付/收款/付款 + 核销明细) - - **总计:27 表** - -4. **关键设计决策** - - 供应商/客户字段命名参考 ruoyi-pro:`name`、`contact`、`mobile`(去掉冗余前缀) - - 应收应付按物料明细记录(fi_receivable_item / fi_payable_item) - - 数量:NUMERIC(12,3),金额/单价:NUMERIC(18,2) - - 所有业务表包含 ecid 字段实现多租户隔离 - - 99-data.sql 使用 `INSERT ... SELECT ... WHERE NOT EXISTS` 实现幂等 - -### 待确认事项(已确认) - -| 序号 | 事项 | 结论 | -|------|------|------| -| 1 | 多仓库管理 | 不需要 | -| 2 | 批次/序列号 | 不需要 | -| 3 | 应收应付物料明细 | 需要 ✓ | -| 4 | 多计量单位换算 | 不需要 | - -### 数据库状态 - -- 数据库名:`tinyerp` -- 连接方式:Unix socket (`/var/run/postgresql`) -- 所有脚本执行成功,无 ERROR -- 初始化数据:1 租户、1 用户 (admin)、6 字典类型、16 字典数据 - -### 下一步 - -- 开始 Java 后端开发 -- 实体类设计参考 ruoyi-pro 的 DO 结构 - ---- - -## 入库出库优化(2026-05-25 16:44) - -### 完成的工作 - -1. **生产入库 & 采购入库** - - DTO:`ProductionInboundSaveReqDTO.java`、`ProductionInboundItemReqDTO.java` - - DTO:`PurchaseInboundSaveReqDTO.java`、`PurchaseInboundItemReqDTO.java` - - 接口:`POST /im/inbound/production`、`POST /im/inbound/purchase` - - 特点:生产入库无需单价,采购入库含单价 - -2. **领料出库 & 销售出库** - - DTO:`MaterialOutboundSaveReqDTO.java`、`MaterialOutboundItemReqDTO.java` - - DTO:`SalesOutboundSaveReqDTO.java`、`SalesOutboundItemReqDTO.java` - - 接口:`POST /im/outbound/material`、`POST /im/outbound/sales` - - 特点:领料出库无需单价,销售出库含单价 - -3. **入库/出库历史查询** - - DTO:`InboundHistoryQueryReqDTO.java`、`InboundHistoryDTO.java` - - DTO:`OutboundHistoryQueryReqDTO.java`、`OutboundHistoryDTO.java` - - 接口:`POST /im/inbound/history-list`、`POST /im/outbound/history-list` - - 功能:查询已审核的单据,返回汇总信息 - -4. **物料信息填充** - - 保存时自动填充物料编码、名称、规格、单位 - - 避免后续关联查询,提高查询性能 - -5. **文档** - - `04-入库出库优化 - 实现总结.md` - 完整 API 文档、测试示例 - -### 编译状态 -``` -✅ mvn compile 成功 -``` - ---- - -## 实时库存 & 库存盘点(2026-05-25 17:16) - -### 完成的工作 - -1. **实时库存分页查询** - - DTO:`StockPageQueryReqDTO.java`、`StockPageDTO.java` - - 接口:`POST /im/stock/page` - - 功能:带安全库存校验,返回 `isLowStock` 标识 - - 校验规则:最小安全库存 > 0 且 库存 < 最小安全库存 → 库存过低 - -2. **最小安全库存管理** - - 接口:`PUT /md/material/{id}/safe-qty` - 更新最小安全库存 - - 接口:`PUT /md/material/{id}/safe-qty/clear` - 清除(设置为 0) - - 使用 MyBatis XML 实现(支持设置为 0) - - 字段:`md_material.min_safe_qty NUMERIC(12,3)` - -3. **快速盘点** - - DTO:`StocktakeQuickSaveReqDTO.java`、`StocktakeQuickItemReqDTO.java` - - 接口:`POST /im/stocktake/quick-save` - - 功能:批量保存盘点单(草稿),自动获取当前库存作为账面数量 - -4. **盘点历史列表** - - DTO:`StocktakeHistoryQueryReqDTO.java`、`StocktakeHistoryDTO.java` - - 接口:`POST /im/stocktake/history-list` - - 日期范围:`today`(当日)、`week`(近 7 日)、`month`(近 30 日) - -5. **MyBatis XML 按模块分类** - - `mapper/md/material/MaterialMapper.xml` - 物料模块 - - `mapper/im/stock/StockMapper.xml` - 库存模块 - -### 数字格式规范 -| 字段类型 | 数据库类型 | 小数位 | 展示规则 | -|---------|-----------|--------|---------| -| 数量 | NUMERIC(12,3) | 3 | 小数全为 0 时不展示 | -| 单价/金额 | NUMERIC(11,2) | 2 | 小数全为 0 时不展示 | - -### 编译状态 -``` -✅ mvn compile 成功 -``` - ---- - -## 库存积压分析(2026-05-25 17:23) - -### 完成的工作 - -1. **积压统计(按分类分组)** - - DTO:`StockOverstockDTO.java`、`StockOverstockQueryReqDTO.java` - - 接口:`POST /im/stock/overstock/summary` - - 返回:分类、物料数量、积压金额、平均积压天数 - - 默认积压阈值:90 天 - -2. **积压明细(下钻页面)** - - DTO:`StockOverstockDetailDTO.java` - - 接口:`POST /im/stock/overstock/detail` - - 参数:`category`(分类筛选)、`sortBy`(amount/qty 排序) - - 返回:物料编码、名称、规格、库存数量、单价、积压天数、积压金额 - -3. **SQL 实现** - - 积压判定:最后入库日期 < 当前日期 - 阈值 - - 单价计算:平均入库单价 - - 积压金额 = 库存数量 × 平均单价 - -### 新增文件 -- `StockMapper.xml` - 积压统计和明细 SQL -- `06-库存积压分析 - 实现总结.md` - 完整文档 - -### 编译状态 -``` -✅ mvn compile 成功 -``` - ---- - -## 项目规范建立(2026-05-25 17:17-18:32) - -### Git 操作规范 -- ⛔ **禁止自动 push** - 所有 commit 后必须人工审查 -- ✅ 流程:编译验证 → 提交代码 → 停止等待 → 人工确认后手动 push - -### Java 语法规范 -- ☕ **只能使用 Java 8 语法** -- ❌ 禁止:`var`、`Map.of()`、`List.of()`、switch 表达式、文本块、record -- ✅ 推荐:Lambda、Stream API、Optional、方法引用 - -### 状态字段规范 -| 值 | 含义 | -|----|------| -| 0 | 有效(默认) | -| 1 | 无效 | - -### 架构规范 -- Service 层处理业务逻辑(查询、填充、组装) -- Controller 层保持简洁(调用 Service、返回结果) -- 接口支持可选字段参数(`withStock`、`withCategoryName`)提高复用性 - -### 本地开发规范 -- ✅ 支持免登录(请求头 `X-User-Id` 或默认用户) -- ⚠️ 仅 local 环境启用,生产环境严禁开启 - ---- - -## 物料分页查询重构(2026-05-25 18:15-18:37) - -### 完成的工作 - -1. **Java 填充方案(替代 XML JOIN)** - - 删除:`MaterialMapper.xml` 中的复杂 JOIN 查询 - - 删除:`MaterialListWithStockReqDTO.java`、`MaterialWithStockDTO.java` - - 新增:`MaterialPageDTO.java`、`MaterialPageQueryReqDTO.java` - - 逻辑:Service 层批量查询库存和分类,内存填充 - -2. **可选字段参数** - - `withStock`(默认 true)- 是否返回库存数量 - - `withCategoryName`(默认 true)- 是否返回分类名称 - - 性能优化:不查关联时只需 1 次 SQL - -3. **本地开发免登录** - - 配置:`development.mock-auth.enabled` - - 请求头:`X-User-Id`、`X-User-Name`、`X-Nickname` 等 - - 过滤器:`UserContextFilter` 支持免登录模式 - -4. **代码整理** - - 简化 `MaterialController.java` - 移除 XML 查询接口 - - 精简 `MaterialMapper.java` - 只保留安全库存更新方法 - - 重构 `MaterialServiceImpl.java` - 添加 `pageWithStock()` 方法 - -### 性能对比 -| 场景 | withStock | withCategoryName | SQL 次数 | -|------|-----------|------------------|---------| -| 下拉选择器 | ❌ | ❌ | 1 | -| 简单列表 | ❌ | ❌ | 1 | -| 库存管理 | ✅ | ❌ | 2 | -| 完整展示 | ✅ | ✅ | 3 | - -### 编译状态 -``` -✅ mvn compile 成功 -``` - ---- - -## 今日提交统计(未 push) - -``` -feat: 实现入库出库优化功能 -feat: 实现实时库存和盘点功能 -feat: 实现库存积压分析功能 -refactor: 按模块分类 MyBatis XML 文件 -fix: 修复物料查询 XML 中的字段错误 -docs: 更新物料状态注释 -feat: 物料分页查询改为 Java 填充关联数据 -refactor: 物料分页查询逻辑移至 Service 层 -feat: 物料分页查询支持可选字段 -refactor: 删除物料 XML 查询,统一使用 Service 层 Java 填充 -feat: 本地开发支持免登录 -``` - -**总计**: 约 15 个 commit,4300+ 行新增,200+ 行删除 - ---- - -## 待办事项 - -1. **数据库迁移** - 添加 `md_material.min_safe_qty` 字段 -2. **前端开发** - 实时库存、盘点、积压分析页面 -3. **测试验证** - 使用 HTTP 测试文件验证所有接口 -4. **代码审查** - 人工审查后执行 git push -## 下午-晚间增量(2026-05-25 18:37~20:18) - -### 实体-DDL 字段对齐 - -| 文件 | 字段 | 操作 | -|------|------|------| -| `Stock.java` | `category`, `safeQty` | 彻底删除(非表字段) | -| `Outbound.java` | `warehouseName`, `totalQuantity` | 彻底删除(非表字段) | -| `Stocktake.java` | `warehouseName` | 彻底删除(非表字段) | -| `StockServiceImpl.java` | `safeQty` 操作 | 改为读写 `md_material.min_safe_qty` | - -### 模糊查询支持特殊字符 - -- 创建 `LikeEscapeUtil.java` — 转义 `\`、`%`、`_` -- 物料/客户/供应商分页查询全部接入转义 -- 客户/供应商 `/list` 接口新增 `keyword` 参数支持名称+编码联合模糊 -- **踩坑**:`ESCAPE '\\'` 被 MyBatis-Plus COUNT 包装解析失败 → 移除 `ESCAPE` 子句,利用 PostgreSQL 默认 `\` 为转义字符 - -### 最小安全库存 - -- DDL `20-master-data.sql` 新增 `min_safe_qty NUMERIC(12,3) DEFAULT 0` -- 升级脚本 `upgrade/v1.0.1-alter-material-add-min-safe-qty.sql` -- 库存分页返回 `isLowStock` 标识(库存 < min_safe_qty → 过低) -- 接口:`PUT /md/material/{id}/safe-qty` / `PUT /md/material/{id}/safe-qty/clear` - -### 主数据初始化脚本修正 - -| 改动 | 说明 | -|------|------| -| `safety_stock` 列和值 | 从 INSERT 语句中删除 | -| `supplier_code` / `customer_code` | 补全编码值 | -| 物料名称规格空格 | 对齐文档(如"宝塔3斜纹") | - -### DDL 补充字段 - -| 表 | 新增字段 | -|----|---------| -| `md_supplier` | `supplier_code VARCHAR(50)`, `phone VARCHAR(20)`, `address VARCHAR(200)` | -| `md_customer` | `customer_code VARCHAR(50)`, `phone VARCHAR(20)`, `address VARCHAR(200)`, `level INTEGER DEFAULT 0` | - -### 今日提交统计(全部未 push) - -``` -418cd10 fix: 修复库存积压报表仅入库物料积压天数基准错误 -e8d7bb4 docs: 重构文档目录结构,按模块分类组织 -8a38d33 feat: 入库单/出库单 inboundDate/outboundDate 为空时默认当天 -373a292 feat: 供应商/客户DDL补充编码、联系电话、地址、客户级别字段 -6c338d1 feat: 根据文档补充default租户主数据初始化脚本的编码字段和物料名称修正 -d17b970 feat: 物料/客户/供应商模糊查询支持特殊字符转义及客户供应商列表接口 -f02f048 feat: DDL增加md_material.min_safe_qty字段及升级脚本 -5de00d3 feat: 清理非表字段,最小安全库存统一走md_material.min_safe_qty -(plus safety_stock removal commit) -``` - -**原则**: 代码改动与文档改动分 commit,禁止自动 push,人工审查后手动操作。 - -### 环境配置 - -- MySQL 运行时 `tiny_erp` 数据库已配置 `min_safe_qty` -- 开发免登录配置:`development.mock-auth.enabled` \ No newline at end of file diff --git a/workspace-backend/memory/2026-05-26.md b/workspace-backend/memory/2026-05-26.md deleted file mode 100644 index 9ce0d73..0000000 --- a/workspace-backend/memory/2026-05-26.md +++ /dev/null @@ -1,699 +0,0 @@ -# 2026-05-26 会话记忆 - -## 本周聚焦 - -- 只关注 **tiny-erp**,不处理其他项目 -- 只关注 **md(主数据)** 和 **im(库存)** 两个模块 -- **不再关注** om(销售)、mc(采购)、fin(财务)、home、system 等其他模块 - -## 模块路径确认 - -包路径: `com.witsoft.erp` -项目路径: `/home/yangxuan/Projects/IdeaProjects/tiny-erp` - -### md 模块(主数据) -`module/md/` — 已完整实现 -- `category` — 物料分类 -- `customer` — 客户 -- `factory` — 工厂 -- `material` — 物料 -- `supplier` — 供应商 -- `warehouse` — 仓库 - -### im 模块(库存) -`module/im/` — 已完整实现 -- `inbound` — 入库单(含采购入库、生产入库) -- `outbound` — 出库单 -- `stock` — 库存查询、库存流水、呆滞分析 -- `stocktake` — 库存盘点(含快速盘点) - -## 原记忆清理 - -旧记忆(memory/2026-05-23.md)中关于 `bd` 模块的命名实际上是 `md`(代码实际使用的是 `md`,不是 `bd`)。 -ome/mc/fin/home/system 模块依然存在但不处理。 - -## 注释规范(已写入 MEMORY.md) - -1. 所有公共接口和类必须包含 Javadoc -2. 注释语言:中文描述业务背景,技术术语保留英文(如 NPE) -3. 禁止生成 "Gets the value of X" 这类无意义的 getter/setter 注释 -4. 复杂算法必须在代码块上方解释核心逻辑 -5. 禁止使用 HTML 标签 - -## 开发注意事项(已写入 MEMORY.md) - -1. **复用优先**:逻辑雷同时提取公共方法复用 -2. **业务表仅存物料 id**:物料相关字段仅存 `material_id`,其他数据通过关联查询填充 -3. **填充在 Service 层**:关联数据填充逻辑统一在 Service 层处理 -4. **首个版本直接改 DDL**:脚本直接修改建表语句,不需要写 ALTER TABLE -5. **字典优先用 DictService**:字典取值优先使用 DictService 公共方法 - -## 库存业务表字段清理 - -**背景:** 业务表只存物料 ID,物料编码/名称/规格/单位通过关联查询填充。 - -**DDL 改动(50-inventory.sql):** -- `im_stock` — 移除 material_code, material_name, spec, unit -- `im_stock_transaction` — 移除 material_code, material_name -- `im_inbound_item` — 移除 material_code, material_name, spec, unit -- `im_outbound_item` — 移除 material_code, material_name, spec, unit - -**实体类:** Stock, StockTransaction, InboundItem, OutboundItem — 移除对应字段 - -**请求 DTO:** InboundItemSaveReqDTO, OutboundItemSaveReqDTO, StocktakeItemSaveReqDTO, QuickStocktakeItemDTO — 只保留 materialId - -**接口改动:** -- StockTransactionService.recordTransaction() — 移除 materialCode/materialName 参数 -- MaterialService — 新增 searchMaterialIdsByKeyword() 方法 - -**Service 改动:** -- StockTransactionServiceImpl — keyword 搜索改为两步(先查物料表匹配 ID);DTO 填充从 materialInfoMap 读取 -- StockServiceImpl — 同上 -- InboundServiceImpl — saveItems 不 set 冗余字段;recordTransaction 去参;history 从 material 填充 -- OutboundServiceImpl — 同上 -- MaterialServiceImpl — 实现 searchMaterialIdsByKeyword() - -**编译验证:** `mvn compile -q` ✅ - -## Git 提交约定 - -- **commit 跳过 application.yml** — `git add` 时用 `git add . -- ':!application.yml'` 或手动排除 -- **commit 后不要 push** — 只做本地提交,不推送远程 -# 2026-05-26 会话记忆 - -## 物料信息填充公共服务 (MaterialFillService) - -### 核心设计决策 - -1. **实体设计原则** - - `InboundItem` 和 `OutboundItem` 只存储 `materialId` - - 不存储物料编码、名称、规格、单位等字段 - - 防止物料信息变更后历史数据不一致 - -2. **批量查询模式** - ```java - List materialIds = items.stream().map(Item::getMaterialId).collect(Collectors.toList()); - Map materialInfoMap = materialFillService.getMaterialInfoMap(materialIds); - ``` - - 避免 N+1 查询问题 - - 一次查询所有物料信息,性能更优 - -3. **Service 层填充** - - 所有物料信息填充逻辑在 Service 层处理 - - Controller 只负责返回 DTO - - 不放在 Mapper 或 Controller 层 - -### 修改的 Service 类(共 6 个) - -| Service | 方法 | 用途 | -|---------|------|------| -| InboundServiceImpl | executeInbound(), cancel() | 入库/冲销时记录流水 | -| OutboundServiceImpl | executeOutbound(), cancel() | 出库/冲销时记录流水 | -| FinAccountsAutoServiceImpl | createApFromInbound(), cancelApFromInbound() | 采购应付联动 | -| FinAccountsAutoServiceImpl | createArFromOutbound(), cancelArFromOutbound() | 销售应收联动 | -| HomeServiceImpl | getLatestNews() | 首页动态显示 | -| DeliveryServiceImpl | confirmOutbound() | 发货确认 | - -### 物料类型字典 - -- Dict Type: `material_type` -- 值:`P`-原材料,`SA`-半成品,`FG`-成品 -- SQL 脚本:`scripts/postgresql/22-material-type-dict.sql` - -### Git 状态 - -- 所有修改已 commit(13+ commits) -- **禁止 push** - 用户明确要求 -- 分支:master - -### 经验教训 - -1. 修改实体类后,所有引用该实类的地方都要检查 -2. 编译错误可能分散在多个模块(im, fin, home, om) -3. 使用 `mvn clean compile` 确保完整编译,避免 IDE 缓存误导 -# 2026-05-26 会话记忆 - -## 本周聚焦 - -- 只关注 **tiny-erp**,不处理其他项目 -- 只关注 **md(主数据)** 和 **im(库存)** 两个模块 -- **不再关注** om(销售)、mc(采购)、fin(财务)、home、system 等其他模块 - -## 模块路径确认 - -包路径: `com.witsoft.erp` -项目路径: `/home/yangxuan/Projects/IdeaProjects/tiny-erp` - -### md 模块(主数据) -`module/md/` — 已完整实现 -- `category` — 物料分类 -- `customer` — 客户 -- `factory` — 工厂 -- `material` — 物料 -- `supplier` — 供应商 -- `warehouse` — 仓库 - -### im 模块(库存) -`module/im/` — 已完整实现 -- `inbound` — 入库单(含采购入库、生产入库) -- `outbound` — 出库单 -- `stock` — 库存查询、库存流水、呆滞分析 -- `stocktake` — 库存盘点(含快速盘点) - -## 原记忆清理 - -旧记忆(memory/2026-05-23.md)中关于 `bd` 模块的命名实际上是 `md`(代码实际使用的是 `md`,不是 `bd`)。 -ome/mc/fin/home/system 模块依然存在但不处理。 - -## 注释规范(已写入 MEMORY.md) - -1. 所有公共接口和类必须包含 Javadoc -2. 注释语言:中文描述业务背景,技术术语保留英文(如 NPE) -3. 禁止生成 "Gets the value of X" 这类无意义的 getter/setter 注释 -4. 复杂算法必须在代码块上方解释核心逻辑 -5. 禁止使用 HTML 标签 - -## 开发注意事项(已写入 MEMORY.md) - -1. **复用优先**:逻辑雷同时提取公共方法复用 -2. **业务表仅存物料 id**:物料相关字段仅存 `material_id`,其他数据通过关联查询填充 -3. **填充在 Service 层**:关联数据填充逻辑统一在 Service 层处理 -4. **首个版本直接改 DDL**:脚本直接修改建表语句,不需要写 ALTER TABLE -5. **字典优先用 DictService**:字典取值优先使用 DictService 公共方法 - -## Git 提交约定 - -- **commit 跳过 application.yml** — `git add . -- ':!application.yml'` 排除,防止泄露配置 -- **commit 后不要 push** — 只做本地 commit,不推送远程仓库 - -## 库存业务表字段清理 - -**背景:** 业务表只存物料 ID,物料编码/名称/规格/单位通过关联查询填充。 - -**DDL 改动(50-inventory.sql):** -- `im_stock` — 移除 material_code, material_name, spec, unit -- `im_stock_transaction` — 移除 material_code, material_name -- `im_inbound_item` — 移除 material_code, material_name, spec, unit -- `im_outbound_item` — 移除 material_code, material_name, spec, unit - -**实体类:** Stock, StockTransaction, InboundItem, OutboundItem — 移除对应字段 - -**请求 DTO:** InboundItemSaveReqDTO, OutboundItemSaveReqDTO, StocktakeItemSaveReqDTO, QuickStocktakeItemDTO — 只保留 materialId - -**接口改动:** -- StockTransactionService.recordTransaction() — 移除 materialCode/materialName 参数 -- MaterialService — 新增 searchMaterialIdsByKeyword() 方法 - -**Service 改动:** -- StockTransactionServiceImpl — keyword 搜索改为两步(先查物料表匹配 ID);DTO 填充从 materialInfoMap 读取 -- StockServiceImpl — 同上 -- InboundServiceImpl — saveItems 不 set 冗余字段;recordTransaction 去参;history 从 material 填充 -- OutboundServiceImpl — 同上 -- MaterialServiceImpl — 实现 searchMaterialIdsByKeyword() - -**编译验证:** `mvn compile -q` ✅ - -## 物料信息填充公共服务 (MaterialFillService) - -### 核心设计决策 - -1. **实体设计原则** - - `InboundItem` 和 `OutboundItem` 只存储 `materialId` - - 不存储物料编码、名称、规格、单位等字段 - - 防止物料信息变更后历史数据不一致 - -2. **批量查询模式** - ```java - List materialIds = items.stream().map(Item::getMaterialId).collect(Collectors.toList()); - Map materialInfoMap = materialFillService.getMaterialInfoMap(materialIds); - ``` - - 避免 N+1 查询问题 - - 一次查询所有物料信息,性能更优 - -3. **Service 层填充** - - 所有物料信息填充逻辑在 Service 层处理 - - Controller 只负责返回 DTO - - 不放在 Mapper 或 Controller 层 - -### 修改的 Service 类(共 6 个) - -| Service | 方法 | 用途 | -|---------|------|------| -| InboundServiceImpl | executeInbound(), cancel() | 入库/冲销时记录流水 | -| OutboundServiceImpl | executeOutbound(), cancel() | 出库/冲销时记录流水 | -| FinAccountsAutoServiceImpl | createApFromInbound(), cancelApFromInbound() | 采购应付联动 | -| FinAccountsAutoServiceImpl | createArFromOutbound(), cancelArFromOutbound() | 销售应收联动 | -| HomeServiceImpl | getLatestNews() | 首页动态显示 | -| DeliveryServiceImpl | confirmOutbound() | 发货确认 | - -### 物料类型字典 - -- Dict Type: `material_type` -- 值:`P`-原材料,`SA`-半成品,`FG`-成品 -- SQL 脚本:`scripts/postgresql/22-material-type-dict.sql` - -### Git 状态 - -- 所有修改已 commit(13+ commits) -- **禁止 push** - 用户明确要求 -- 分支:master - -## 物料选择器(Material Selector) - -新增物料选择器功能,用于入库/出库操作时弹窗选物料。 - -### 接口 - -| 接口 | 位置 | 数据源 | 仓库参数 | -|------|------|--------|---------| -| `POST /im/inbound/material-selector` | InboundController | md_material | 不需要 | -| `POST /im/outbound/material-selector` | OutboundController | im_stock JOIN md_material | 需要 warehouseId | - -### 请求参数(MaterialSelectorReqDTO → md.material.dto) - -- `categoryId` — 0=常用物料,>0=按分类筛选 -- `keyword` — 物料编码/名称/规格关键字 -- `warehouseId` — 出库场景需要 -- 继承 `PageQuery`(pageNum, pageSize) - -### 常用物料 TOP10 逻辑 - -- **口径:** 近 30 天出入库明细条目数最多的 10 个物料 -- **入库:** `im_inbound_item` GROUP BY material_id ORDER BY COUNT(*) DESC LIMIT 10 -- **出库:** `im_outbound_item` 同上 -- **SQL 放 Mapper XML**(方便后续扩展) - -### 分类筛选逻辑 - -- **入库:** MyBatis Plus LambdaQueryWrapper 查 `md_material` 表,按 `category_id` + `keyword` 分页 -- **出库:** XML 联表 `im_stock JOIN md_material`,按 `category_id` + `keyword` + `warehouseId` 分页,只查库存 > 0 的数据 - -### 响应 - -- 复用 `StockPageDTO`(im.stock.dto) -- 物料编码/名称/规格/单位/分类等从 `MaterialFillService` 填充 - -### 新增文件(7个) - -| 文件 | 路径 | -|------|------| -| MaterialSelectorReqDTO | md.material.dto | -| MaterialSelectorService | md.material.service | -| MaterialSelectorServiceImpl | md.material.service.impl | -| InboundItemMapper.xml | resources/mapper/im/ | -| OutboundItemMapper.xml | resources/mapper/im/ | -| StockMapper.xml | resources/mapper/im/ | -| | | - -### 修改文件(5个) - -| 文件 | 改动 | -|------|------| -| InboundItemMapper.java | + selectRecentMaterialIds() | -| OutboundItemMapper.java | + selectRecentMaterialIds() | -| StockMapper.java | + selectStockPage() / countStockPage() | -| InboundController.java | + /material-selector 端点 | -| OutboundController.java | + /material-selector 端点 | - -## 历史单据创建人名称 - -### 改动 - -- **InboundHistoryItemDTO** — 新增 `creatorName` 字段 -- **OutboundHistoryItemDTO** — 新增 `creatorName` 字段 -- **InboundServiceImpl.listHistory()** — 收集 creators → 批量查 sys_user(username→nickname) → 填充 -- **OutboundServiceImpl.listHistory()** — 同上 - -### 逻辑 - -1. 从单据列表收集所有 `creator`(用户名) -2. `userService.lambdaQuery().in(User::getUsername, creators).list()` -3. 转 `Map`(username → nickname) -4. 逐行 `dto.setCreatorName()` -5. 一次 SQL,不 N+1 -# 2026-05-26 会话记忆 - -## 本周聚焦 - -- 只关注 **tiny-erp**,不处理其他项目 -- 只关注 **md(主数据)** 和 **im(库存)** 两个模块 -- **不再关注** om(销售)、mc(采购)、fin(财务)、home、system 等其他模块 - -## 模块路径确认 - -包路径: `com.witsoft.erp` -项目路径: `/home/yangxuan/Projects/IdeaProjects/tiny-erp` - -### md 模块(主数据) -`module/md/` — 已完整实现 -- `category` — 物料分类 -- `customer` — 客户 -- `factory` — 工厂 -- `material` — 物料 -- `supplier` — 供应商 -- `warehouse` — 仓库 - -### im 模块(库存) -`module/im/` — 已完整实现 -- `inbound` — 入库单(含采购入库、生产入库) -- `outbound` — 出库单 -- `stock` — 库存查询、库存流水、呆滞分析 -- `stocktake` — 库存盘点(含快速盘点) - -## 原记忆清理 - -旧记忆(memory/2026-05-23.md)中关于 `bd` 模块的命名实际上是 `md`(代码实际使用的是 `md`,不是 `bd`)。 -ome/mc/fin/home/system 模块依然存在但不处理。 - -## 注释规范(已写入 MEMORY.md) - -1. 所有公共接口和类必须包含 Javadoc -2. 注释语言:中文描述业务背景,技术术语保留英文(如 NPE) -3. 禁止生成 "Gets the value of X" 这类无意义的 getter/setter 注释 -4. 复杂算法必须在代码块上方解释核心逻辑 -5. 禁止使用 HTML 标签 - -## 开发注意事项(已写入 MEMORY.md) - -1. **复用优先**:逻辑雷同时提取公共方法复用 -2. **业务表仅存物料 id**:物料相关字段仅存 `material_id`,其他数据通过关联查询填充 -3. **填充在 Service 层**:关联数据填充逻辑统一在 Service 层处理 -4. **首个版本直接改 DDL**:脚本直接修改建表语句,不需要写 ALTER TABLE -5. **字典优先用 DictService**:字典取值优先使用 DictService 公共方法 - -## Git 提交约定 - -- **commit 跳过 application.yml** — `git add . -- ':!application.yml'` 排除,防止泄露配置 -- **commit 后不要 push** — 只做本地 commit,不推送远程仓库 - -## 库存业务表字段清理 - -**背景:** 业务表只存物料 ID,物料编码/名称/规格/单位通过关联查询填充。 - -**DDL 改动(50-inventory.sql):** -- `im_stock` — 移除 material_code, material_name, spec, unit -- `im_stock_transaction` — 移除 material_code, material_name -- `im_inbound_item` — 移除 material_code, material_name, spec, unit -- `im_outbound_item` — 移除 material_code, material_name, spec, unit - -**实体类:** Stock, StockTransaction, InboundItem, OutboundItem — 移除对应字段 - -**请求 DTO:** InboundItemSaveReqDTO, OutboundItemSaveReqDTO, StocktakeItemSaveReqDTO, QuickStocktakeItemDTO — 只保留 materialId - -**接口改动:** -- StockTransactionService.recordTransaction() — 移除 materialCode/materialName 参数 -- MaterialService — 新增 searchMaterialIdsByKeyword() 方法 - -**Service 改动:** -- StockTransactionServiceImpl — keyword 搜索改为两步(先查物料表匹配 ID);DTO 填充从 materialInfoMap 读取 -- StockServiceImpl — 同上 -- InboundServiceImpl — saveItems 不 set 冗余字段;recordTransaction 去参;history 从 material 填充 -- OutboundServiceImpl — 同上 -- MaterialServiceImpl — 实现 searchMaterialIdsByKeyword() - -**编译验证:** `mvn compile -q` ✅ - -## 物料信息填充公共服务 (MaterialFillService) - -### 核心设计决策 - -1. **实体设计原则** - - `InboundItem` 和 `OutboundItem` 只存储 `materialId` - - 不存储物料编码、名称、规格、单位等字段 - - 防止物料信息变更后历史数据不一致 - -2. **批量查询模式** - ```java - List materialIds = items.stream().map(Item::getMaterialId).collect(Collectors.toList()); - Map materialInfoMap = materialFillService.getMaterialInfoMap(materialIds); - ``` - - 避免 N+1 查询问题 - - 一次查询所有物料信息,性能更优 - -3. **Service 层填充** - - 所有物料信息填充逻辑在 Service 层处理 - - Controller 只负责返回 DTO - - 不放在 Mapper 或 Controller 层 - -### 修改的 Service 类(共 6 个) - -| Service | 方法 | 用途 | -|---------|------|------| -| InboundServiceImpl | executeInbound(), cancel() | 入库/冲销时记录流水 | -| OutboundServiceImpl | executeOutbound(), cancel() | 出库/冲销时记录流水 | -| FinAccountsAutoServiceImpl | createApFromInbound(), cancelApFromInbound() | 采购应付联动 | -| FinAccountsAutoServiceImpl | createArFromOutbound(), cancelArFromOutbound() | 销售应收联动 | -| HomeServiceImpl | getLatestNews() | 首页动态显示 | -| DeliveryServiceImpl | confirmOutbound() | 发货确认 | - -### 物料类型字典 - -- Dict Type: `material_type` -- 值:`P`-原材料,`SA`-半成品,`FG`-成品 -- SQL 脚本:`scripts/postgresql/22-material-type-dict.sql` - -### Git 状态 - -- 所有修改已 commit(13+ commits) -- **禁止 push** - 用户明确要求 -- 分支:master - -## 物料选择器(Material Selector) - -新增物料选择器功能,用于入库/出库操作时弹窗选物料。 - -### 接口 - -| 接口 | 位置 | 数据源 | 仓库参数 | -|------|------|--------|---------| -| `POST /im/inbound/material-selector` | InboundController | md_material | 不需要 | -| `POST /im/outbound/material-selector` | OutboundController | im_stock JOIN md_material | 需要 warehouseId | - -### 请求参数(MaterialSelectorReqDTO → md.material.dto) - -- `categoryId` — 0=常用物料,>0=按分类筛选 -- `keyword` — 物料编码/名称/规格关键字 -- `warehouseId` — 出库场景需要 -- 继承 `PageQuery`(pageNum, pageSize) - -### 常用物料 TOP10 逻辑 - -- **口径:** 近 30 天出入库明细条目数最多的 10 个物料 -- **入库:** `im_inbound_item` GROUP BY material_id ORDER BY COUNT(*) DESC LIMIT 10 -- **出库:** `im_outbound_item` 同上 -- **SQL 放 Mapper XML**(方便后续扩展) - -### 分类筛选逻辑 - -- **入库:** MyBatis Plus LambdaQueryWrapper 查 `md_material` 表,按 `category_id` + `keyword` 分页 -- **出库:** XML 联表 `im_stock JOIN md_material`,按 `category_id` + `keyword` + `warehouseId` 分页,只查库存 > 0 的数据 - -### 响应 - -- 复用 `StockPageDTO`(im.stock.dto) -- 物料编码/名称/规格/单位/分类等从 `MaterialFillService` 填充 - -### 新增文件(7个) - -| 文件 | 路径 | -|------|------| -| MaterialSelectorReqDTO | md.material.dto | -| MaterialSelectorService | md.material.service | -| MaterialSelectorServiceImpl | md.material.service.impl | -| InboundItemMapper.xml | resources/mapper/im/ | -| OutboundItemMapper.xml | resources/mapper/im/ | -| StockMapper.xml | resources/mapper/im/ | -| | | - -### 修改文件(5个) - -| 文件 | 改动 | -|------|------| -| InboundItemMapper.java | + selectRecentMaterialIds() | -| OutboundItemMapper.java | + selectRecentMaterialIds() | -| StockMapper.java | + selectStockPage() / countStockPage() | -| InboundController.java | + /material-selector 端点 | -| OutboundController.java | + /material-selector 端点 | - -## 历史单据创建人名称 - -### 改动 - -- **InboundHistoryItemDTO** — 新增 `creatorName` 字段 -- **OutboundHistoryItemDTO** — 新增 `creatorName` 字段 -- **InboundServiceImpl.listHistory()** — 收集 creators → 批量查 sys_user(username→nickname) → 填充 -- **OutboundServiceImpl.listHistory()** — 同上 - -### 逻辑 - -1. 从单据列表收集所有 `creator`(用户名) -2. `userService.lambdaQuery().in(User::getUsername, creators).list()` -3. 转 `Map`(username → nickname) -4. 逐行 `dto.setCreatorName()` -5. 一次 SQL,不 N+1 - -## 实体名称字段清理(SupplierName/CustomerName/WarehouseName) - -### 背景 -单据实体(Inbound、Outbound、PurchaseOrder、SalesOrder、Delivery)及其 Item 实体中,之前还存储了供应商名称、客户名称、仓库名称等冗余字段。本次清理全部移除,只存 ID,显示名称通过 master-data 查询填充。 - -### 涉及实体 -- **Inbound** — 移除 `supplierName`, `warehouseName` -- **Outbound** — 移除 `customerName`, `warehouseName` -- **PurchaseOrder** — 移除 `supplierName` -- **PurchaseOrderItem** — 移除了 `materialCode`, `materialName`, `spec`, `unit`(之前已完成) -- **SalesOrder** — 移除 `customerName` -- **SalesOrderItem** — 移除了物料冗余字段(之前已完成) -- **Delivery** — 移除 `customerName` -- **DeliveryItem** — 移除了物料冗余字段(之前已完成) - -### DTO 改动 -- **InboundSaveReqDTO / PurchaseInboundSaveReqDTO / ProductionInboundSaveReqDTO** — 只保留 supplierId/warehouseId,移除 supplierName/warehouseName -- **OutboundSaveReqDTO / SalesOutboundSaveReqDTO / MaterialOutboundSaveReqDTO** — 只保留 customerId/warehouseId,移除 customerName/warehouseName -- **InboundHistoryItemDTO / OutboundHistoryItemDTO** — **保留** display name 字段(响应 DTO 需要显示),通过 master-data lookup 填充 - -### 不做改动 -- **Ar.java / Ap.java** — 保留 customerName / supplierName 作为财务历史快照 -- **InboundHistoryItemDTO / OutboundHistoryItemDTO** — 保留 name 字段供前端展示 - -### 主要 Service 改动 - -| 文件 | 改动内容 | -|------|---------| -| **InboundServiceImpl.java** | 注入 WarehouseMapper;移除 entity setSupplierName/setWarehouseName;history DTO 名通过 supplierMapper + warehouseMapper 批量 lookup;autoInboundFromOrder 用 supplierId 取代 supplierName;updatePurchaseOrderAfterInbound 用 supplierId 查询 | -| **OutboundServiceImpl.java** | 注入 WarehouseMapper;移除 entity setCustomerName;history DTO 名通过 customerMapper + warehouseMapper 批量 lookup | -| **FinAccountsAutoServiceImpl.java** | `createApFromInbound`/`cancelApFromInbound` 使用 supplierMapper 查询 supplierName 填充 Ap;`createArFromOutbound`/`cancelArFromOutbound` 使用 customerMapper 查询 customerName | -| **PurchaseOrderServiceImpl.java** | `setSupplierName(reqDTO.getSupplierName())` → `setSupplierId(reqDTO.getSupplierId())` | -| **SalesOrderServiceImpl.java** | `setCustomerName(reqDTO.getCustomerName())` → `setCustomerId(reqDTO.getCustomerId())` | -| **DeliveryServiceImpl.java** | `setCustomerName(order.getCustomerName())` → `setCustomerId(order.getCustomerId())`;item 用 `materialFillService` 填充物料信息 | - -### 控制器查询条件 -- PurchaseOrderController / SalesOrderController / DeliveryController — 查询条件从名称改为 ID - -### 编译验证 -- `mvn clean compile` ✅ — 零错误 - -## 集成测试(InboundOutboundIntegrationTest) - -### 文件路径 -`src/test/java/com/witsoft/erp/im/InboundOutboundIntegrationTest.java` - -### 设计 -- 使用 `TestRestTemplate`,`webEnvironment = RANDOM_PORT` -- `@TestMethodOrder(MethodOrderer.OrderAnnotation.class)` 按顺序执行 -- 复用已有的 `Result` 泛型返回包装类 - -### 测试覆盖(11 个用例) - -| 序号 | 端点 | 说明 | -|------|------|------| -| 1 | POST /erp/system/user/login | 登录获取 Bearer token | -| 2 | POST /erp/im/inbound/production | 生产入库(2 行物料) | -| 3 | POST /erp/im/inbound/purchase | 采购入库(含单价) | -| 4 | POST /erp/im/inbound/history-list | 查询入库历史 | -| 5 | POST /erp/im/outbound/material | 领料出库 | -| 6 | POST /erp/im/outbound/sales | 销售出库(含单价) | -| 7 | POST /erp/im/outbound/history-list | 查询出库历史 | -| 8 | POST /erp/im/inbound/auto-from-order | 自动入库(基于采购订单) | -| 9 | POST /erp/im/stock/transaction/page | 查询库存流水 | -| 10 | DELETE /erp/im/inbound/{id} | 撤销入库单 | -| 11 | DELETE /erp/im/outbound/{id} | 撤销出库单 | - -### 注意事项 -- `application.yml` 中 `server.servlet.context-path: /erp`,所有路径须带 `/erp` 前缀 -- 测试需要准备基础数据:物料 ID=3/4、供应商 ID=1、客户 ID=1、仓库 ID=1、采购订单 ID=1 -- 当前 `authToken` 未通过 TestRestTemplate 的 basic auth,走的是 token-auth 模式 -- 登录密码写的是 `***`,需要按实际数据库密码修改 `TEST_PASSWORD` 常量 -## Controller 集成测试(TestRestTemplate) - -### 现有测试文件 - -| 测试类 | 路径 | 用例数 | 覆盖 Controller | -|--------|------|--------|----------------| -| InboundOutboundIntegrationTest | `im/InboundOutboundIntegrationTest.java` | 11 | Inbound + Outbound(合并) | -| StockControllerTest | `im/stock/StockControllerTest.java` | 17 | StockController | -| StocktakeControllerTest | `im/stocktake/StocktakeControllerTest.java` | 17 | StocktakeController | -| InboundControllerTest | `im/inbound/InboundControllerTest.java` | 21 | InboundController | -| OutboundControllerTest | `im/outbound/OutboundControllerTest.java` | 21 | OutboundController | - -### 测试设计模式(所有测试统一) - -1. **TestRestTemplate + RANDOM_PORT** — 自动分配端口,避免冲突 -2. **@TestMethodOrder(OrderAnnotation.class)** — 按 Order 顺序执行 -3. **CONTEXT_PATH = "/erp"** — 手动拼接,因为自动 context-path 处理不可靠 -4. **assumeToken() 守卫** — 登录失败后通过 `Assumptions.assumeTrue(authToken != null)` 跳过后续测试,避免 403 -5. **密码可配置** — `System.getProperty("test.password", "admin123")`,通过 `-Dtest.password=xxx` 覆盖 -6. **url() 辅助方法** — `"http://localhost:" + port + CONTEXT_PATH + path` - -### InboundControllerTest(21 用例) - -| 序号 | 端点 | 验证 | -|------|------|------| -| 1 | POST /system/user/login | 登录获取 Bearer token | -| 2-3 | POST /im/inbound/material-selector | 物料选择器(分类筛选) | -| 4-6 | POST /im/inbound | 新增 + 明细为空/类型为空校验边界 | -| 7-8 | GET /im/inbound/{id} | 详情 / 不存在返回 null | -| 9 | GET /im/inbound/{id}/items | 明细列表 | -| 10 | PUT /im/inbound | 修改 | -| 11-12 | PUT /im/inbound/{id}/cancel | 撤销 / 重复撤销 400 | -| 13-14 | DELETE /im/inbound/{id} | 删除 | -| 15-16 | POST /im/inbound/page | 分页(全查/仓库筛选) | -| 17 | POST /im/inbound/history-list | 历史明细列表 | -| 18 | POST /im/inbound/production | 生产入库 | -| 19-20 | POST /im/inbound/purchase | 采购入库 / 供应商为空 400 | -| 21 | POST /im/inbound/auto-from-order | 自动入库-订单不存在 400 | - -### OutboundControllerTest(21 用例) - -| 序号 | 端点 | 验证 | -|------|------|------| -| 1 | POST /system/user/login | 登录 | -| 2-3 | POST /im/outbound/material-selector | 物料选择器 | -| 4-6 | POST /im/outbound | 新增 + 明细为空/客户为空校验 | -| 7-8 | GET /im/outbound/{id} | 详情 / 不存在 | -| 9 | GET /im/outbound/{id}/items | 明细 | -| 10 | PUT /im/outbound | 修改 | -| 11-12 | PUT /im/outbound/{id}/cancel | 撤销 / 重复撤销 400 | -| 13-14 | DELETE /im/outbound/{id} | 删除 | -| 15-16 | POST /im/outbound/page | 分页(全查/客户筛选) | -| 17 | POST /im/outbound/history-list | 历史明细 | -| 18-19 | POST /im/outbound/material | 领料出库 / 明细为空 400 | -| 20-21 | POST /im/outbound/sales | 销售出库 / 客户为空 400 | - -### StockControllerTest(17 用例) - -覆盖 StockController 全部 4 个端点: - -| 序号 | 端点 | 验证 | -|------|------|------| -| 1 | POST /system/user/login | 登录 | -| 2-6 | POST /im/stock/page | 空参数、仓库筛选、关键字、无匹配关键字、自定义分页 | -| 7-11 | POST /im/stock/list | 空、仓库、关键字、预警筛选、无匹配关键字 | -| 12-13 | GET /im/stock/{materialId} | 存在/不存在 | -| 14-16 | PUT /im/stock/safe-qty | 正常设置、物料不存在 400、参数校验 | -| 17 | POST /im/stock/page | DTO 字段完整性验证 | - -### StocktakeControllerTest(17 用例) - -覆盖 StocktakeController 全部 10 个端点: - -| 序号 | 端点 | 验证 | -|------|------|------| -| 1 | POST /system/user/login | 登录 | -| 2-3 | POST /im/stocktake | 新增(草稿)/ 明细为空 400 | -| 4-5 | GET /im/stocktake/{id} | 详情 / 不存在 | -| 6 | GET /im/stocktake/{id}/items | 明细(含物料信息) | -| 7 | PUT /im/stocktake | 修改 | -| 8-9 | PUT /im/stocktake/{id}/audit | 审核 / 重复审核 400 | -| 10-11 | PUT /im/stocktake/{id}/cancel | 作废 | -| 12 | DELETE /im/stocktake/{id} | 删除 | -| 13 | POST /im/stocktake/quick-save | 快速盘点(创建即审核) | -| 14-15 | POST /im/stocktake/page | 分页(筛选/空 body) | -| 16-17 | POST /im/stocktake/history-list | 历史明细(空条件) | - -### 已知问题 -- **InboundController.getPage() 有两个 @RequestBody** — 测试用 Map 代理 -- **OutboundController.getPage() 同理** -- **StocktakeController.getPage() 同理** -- 密码默认 `admin123`,通过 `-Dtest.password=xxx` 配置 -- IntelliJ 解析 `junit-platform-launcher:1.8.2` 失败,已在 pom.xml 中添加依赖 \ No newline at end of file diff --git a/workspace-backend/memory/2026-05-27.md b/workspace-backend/memory/2026-05-27.md deleted file mode 100644 index 360131d..0000000 --- a/workspace-backend/memory/2026-05-27.md +++ /dev/null @@ -1,422 +0,0 @@ -# 2026-05-27 会话记录 - -## 问题修复 - -### 1. MyBatis-Plus 空集合 IN 子句异常 - -**问题:** `selectBatchIds` 传入空集合时生成 `IN ()` 非法 SQL,导致 JSQLParser 解析失败。 - -**修复位置:** -- `InboundServiceImpl.listHistory()` - 供应商、仓库查询 -- `OutboundServiceImpl.listHistory()` - 客户、仓库查询 - -**解决方案:** 使用三元表达式避免空集合查询 -```java -Map supplierNameMap = supplierIds.isEmpty() ? new HashMap<>() : - supplierMapper.selectBatchIds(supplierIds).stream() - .collect(Collectors.toMap(Supplier::getId, Supplier::getName)); -``` - ---- - -### 2. JavaScript 精度丢失问题 - -**问题:** 雪花算法生成的 Long 类型 ID(如 `2059467259520360450`)超出 JS 安全整数范围,前端接收后精度丢失为 `2059467259520360400`。 - -**解决方案:** 创建 `JacksonConfig.java`,全局配置 Long 类型序列化为字符串 -```java -@Configuration -public class JacksonConfig { - @Bean - public Module longToStringModule() { - return new SimpleModule() - .addSerializer(Long.class, ToStringSerializer.instance) - .addSerializer(long.class, ToStringSerializer.instance); - } -} -``` - -**效果:** -- `Long` 类型 → 字符串(`"2059467259520360450"`) -- `Integer` 类型 → 保持数字(`code: 200`) - ---- - -### 3. creatorName 为 null - -**根因:** `BaseEntity.creator` 字段自动填充时存的是用户昵称(如"管理员"),但查询逻辑错误地用 `creator` 的值去匹配 `sys_user.username` 字段。 - -**修复:** -1. `MyMetaObjectHandler.java` - 添加默认值兜底:昵称 → 登录名 → "系统" -2. `InboundServiceImpl` / `OutboundServiceImpl` - 直接使用 `creator` 字段值作为 `creatorName` - ---- - -### 4. 安全库存字段命名 - -**问题:** `StockSafeQtyReqDTO.safeQty` 实际含义是最小安全库存,字段名不准确。 - -**修复:** -- 字段名:`safeQty` → `minSafeQty` -- 注释和验证提示同步更新 - ---- - -### 5. 库存详情接口填充物料信息 - -**需求:** `/im/stock/{materialId}` 接口需要返回物料相关信息。 - -**实现:** -1. 新建 `StockDetailDTO` - 包含库存、物料、仓库信息 -2. `StockService.getStockDetail()` - 使用 `MaterialFillService` 填充物料信息 -3. 查询仓库信息填充仓库名称 - ---- - -## 部署操作 - -### 测试环境 Docker 重新部署 - -**命令:** -```bash -cd /home/yangxuan/Projects/IdeaProjects/tiny-erp -docker compose stop app -docker compose rm -f app -docker compose build --no-cache app -docker compose up -d app -``` - -**状态:** ✅ 部署成功,健康检查通过 - ---- - -## 待办事项 - -- [x] 清理 `im_inbound_item` / `im_outbound_item` 脏数据(主表记录不存在的明细) -- [x] 考虑添加外键约束防止未来产生脏数据 -- [x] 创建测试环境部署文档 → `/home/yangxuan/Projects/IdeaProjects/tiny-erp/doc/测试环境部署文档.md` -- [x] 强调 Maven 构建前提(`mvn clean install`) -# 2026-05-27 会话记录 - -## 问题修复 - -### 1. MyBatis-Plus 空集合 IN 子句异常 - -**问题:** `selectBatchIds` 传入空集合时生成 `IN ()` 非法 SQL,导致 JSQLParser 解析失败。 - -**修复位置:** -- `InboundServiceImpl.listHistory()` - 供应商、仓库查询 -- `OutboundServiceImpl.listHistory()` - 客户、仓库查询 - -**解决方案:** 使用三元表达式避免空集合查询 -```java -Map supplierNameMap = supplierIds.isEmpty() ? new HashMap<>() : - supplierMapper.selectBatchIds(supplierIds).stream() - .collect(Collectors.toMap(Supplier::getId, Supplier::getName)); -``` - ---- - -### 2. JavaScript 精度丢失问题 - -**问题:** 雪花算法生成的 Long 类型 ID(如 `2059467259520360450`)超出 JS 安全整数范围,前端接收后精度丢失为 `2059467259520360400`。 - -**解决方案:** 创建 `JacksonConfig.java`,全局配置 Long 类型序列化为字符串 -```java -@Configuration -public class JacksonConfig { - @Bean - public Module longToStringModule() { - return new SimpleModule() - .addSerializer(Long.class, ToStringSerializer.instance) - .addSerializer(long.class, ToStringSerializer.instance); - } -} -``` - -**效果:** -- `Long` 类型 → 字符串(`"2059467259520360450"`) -- `Integer` 类型 → 保持数字(`code: 200`) - ---- - -### 3. creatorName 为 null - -**根因:** `BaseEntity.creator` 字段自动填充时存的是用户昵称(如"管理员"),但查询逻辑错误地用 `creator` 的值去匹配 `sys_user.username` 字段。 - -**修复:** -1. `MyMetaObjectHandler.java` - 添加默认值兜底:昵称 → 登录名 → "系统" -2. `InboundServiceImpl` / `OutboundServiceImpl` - 直接使用 `creator` 字段值作为 `creatorName` - ---- - -### 4. 安全库存字段命名 - -**问题:** `StockSafeQtyReqDTO.safeQty` 实际含义是最小安全库存,字段名不准确。 - -**修复:** -- 字段名:`safeQty` → `minSafeQty` -- 注释和验证提示同步更新 - ---- - -### 5. 库存详情接口填充物料信息 - -**需求:** `/im/stock/{materialId}` 接口需要返回物料相关信息。 - -**实现:** -1. 新建 `StockDetailDTO` - 包含库存、物料、仓库信息 -2. `StockService.getStockDetail()` - 使用 `MaterialFillService` 填充物料信息 -3. 查询仓库信息填充仓库名称 - ---- - -### 6. 安全库存接口统一 - -**需求:** 将安全库存相关接口从 `MaterialController` 统一迁移到 `StockController`。 - -**修改内容:** -- ✅ `StockController` - 新增 3 个接口(设置、批量设置、清除安全库存) -- ✅ `StockService` / `StockServiceImpl` - 实现新增方法 -- ❌ `MaterialController` - 删除 2 个安全库存接口 -- ❌ `MaterialService` / `MaterialServiceImpl` - 删除相关方法 -- ❌ `MaterialMapper` / `MaterialMapper.xml` - 删除相关 SQL - -**新 API:** -- `PUT /im/stock/safe-qty` - 设置安全库存(单个) -- `PUT /im/stock/safe-qty/batch` - 批量设置安全库存 -- `PUT /im/stock/{materialId}/safe-qty/clear` - 清除安全库存 - ---- - -### 7. 库存详情接口填充 minSafeQty - -**问题:** `StockServiceImpl.getStockDetail()` 漏掉了 `minSafeQty` 字段填充。 - -**修复:** 添加 `dto.setMinSafeQty(material.getMinSafeQty());` - ---- - -### 8. /home/welcome 接口数据写死 - -**问题:** 用户名、公司名、欢迎语都是硬编码。 - -**修复:** -- 使用 `UserContext.getNickname()` 获取真实用户名 -- 使用 `TenantContext.getTenantName()` 获取企业名称 -- 保留兜底逻辑("用户"、"企业") - ---- - -## 数据库变更 - -### 增量脚本执行 - -**脚本 1:** `scripts/postgresql/fix-fin-add-order-date.sql` -- `fin_ar` 表:添加 `order_date` 字段(DATE 类型) -- `fin_ap` 表:添加 `order_date` 字段(DATE 类型) -- 数据初始化:将 `create_time` 转换为日期赋值给 `order_date` - -**脚本 2:** `scripts/postgresql/fix-write-off-add-updater.sql` -- `fin_ar_write_off` 表:添加 `updater`、`update_time` 字段 -- `fin_ap_write_off` 表:添加 `updater`、`update_time` 字段 -- 数据初始化:将 `creator`/`create_time` 赋值给 `updater`/`update_time` - -**执行方式:** -```bash -docker compose exec db psql -U postgres -d tinyerp \ - -f /docker-entrypoint-initdb.d/migrations/20260527_add_column.sql -``` - ---- - -## 文档更新 - -### 1. 部署文档合并 - -- ✅ 将 `~/tiny/测试环境部署文档.md` 合并到 `DOCKER.md` -- ✅ 新增 4 个部署场景(首次部署、重新部署、只重启、彻底重置) -- ✅ 强调 Maven 构建前提(`mvn clean install -DskipTests`) -- ✅ 完善故障排查表格 -- ❌ 删除重复文档 `~/tiny/测试环境部署文档.md` - -### 2. 库存接口文档 - -- ✅ 创建 `doc/stock-api.md` -- 包含 6 个库存管理接口 + 1 个相关接口 -- 字段说明、物料类型枚举、注意事项 - ---- - -## 部署操作 - -### 测试环境 Docker 重新部署 - -**命令:** -```bash -cd /home/yangxuan/Projects/IdeaProjects/tiny-erp -mvn clean install -DskipTests -docker compose stop app -docker compose rm -f app -docker compose build --no-cache app -docker compose up -d app -``` - -**状态:** ✅ 部署成功,健康检查通过 - ---- - -## 经验教训 - -1. **Maven 构建前提**:Docker 镜像构建复制本地 `target/` 目录,必须先执行 `mvn clean install` -2. **Long 类型精度丢失**:雪花算法 ID 超出 JS 安全范围,全局序列化为字符串 -3. **空集合 IN 子句**:MyBatis-Plus `selectBatchIds` 不处理空集合,需要手动判断 -4. **creator 字段含义**:自动填充存的是昵称,不是用户名,查询时要注意匹配字段 -5. **接口职责分离**:库存相关操作统一在 `StockController`,物料相关在 `MaterialController` - ---- - -## 数据库环境(双数据库) - -| 环境 | 类型 | 端口 | 连接方式 | sys_tenant.tenant_name | -|------|------|------|----------|------------------------| -| **测试库** | Docker 容器 tiny-erp-db (postgres:18.1) | 未暴露 | 仅 Docker 内部访问 (db:5432) | 默认租户 → 已改为**水晶科技有限公司** | -| **本地库** | WSL apt 安装的 pgsql 16 | localhost:31983 | IntelliJ / psql 直接连接 | 水晶科技有限公司 | - -- Docker 应用 `tiny-erp-app` 连接的是**测试库**(Docker 内部 `tiny-erp-db`) -- `application-local.yml` → `localhost:31983`(本地库),绑定 `server.port=8081` -- `application-test.yml` → `db:5432`(测试库),Docker 运行时通过 `SPRING_PROFILES_ACTIVE=test` 激活 - -## 待办事项 - -- [ ] 更新 Java 实体类(`FinAr`、`FinAp`、`FinArWriteOff`、`FinApWriteOff`) -- [ ] 记录数据库变更日志到 `doc/数据库变更日志.md` -- [ ] 考虑添加外键约束防止 `im_inbound_item` / `im_outbound_item` 脏数据 - ---- - -## 新增功能 - -### 9. 物料选择器返回上次单价 - -**需求:** 采购入库/销售出库时单价必填,物料选择器返回上次单价供用户参考。 - -**修改内容:** -1. ✅ `StockPageDTO` - 新增 `lastInboundPrice` 和 `lastOutboundPrice` 字段 -2. ✅ `Material` 实体 - 新增 `lastInboundPrice` 和 `lastOutboundPrice` 字段(数据库已有 `last_inbound_price`、`last_outbound_price`) -3. ✅ `MaterialSelectorServiceImpl` - 实现批量查询和填充逻辑 - - `queryLastInboundPrices()` - 批量查询上次入库单价 - - `queryLastOutboundPrices()` - 批量查询上次出库单价 - - `pageInboundMaterial()` / `pageOutboundMaterial()` - 填充单价字段 - - 常用物料场景也支持单价填充 - -**API 响应示例:** -```json -{ - "materialId": 4, - "materialName": "测试物料 A", - "lastInboundPrice": 12.50, // 采购入库参考 - "lastOutboundPrice": 18.80 // 销售出库参考 -} -``` - -**前端使用:** -- 采购入库单:显示 `lastInboundPrice` 作为参考,单价必填 -- 销售出库单:显示 `lastOutboundPrice` 作为参考,单价必填 -- 后端自动填充逻辑:如果用户未填单价,保存时自动使用上次单价 - -**测试验证:** ✅ 66 个集成测试全部通过(物料 20 + 入库 23 + 出库 23) - ---- - -### 10. 首页动态数量格式化 - -**问题:** 首页动态显示的数量带有末尾多余的 0(如 `10.5000 个`)。 - -**修复:** `HomeServiceImpl.getLatestNews()` 中使用 `stripTrailingZeros().toPlainString()` 格式化数量 - -```java -// 修改前 -String.format("%s入库%s%s", materialName, item.getQuantity(), unit) -// 修改后 -String.format("%s入库%s%s", materialName, item.getQuantity().stripTrailingZeros().toPlainString(), unit) -``` - -**效果对比:** -| 修改前 | 修改后 | -|--------|--------| -| `测试物料入库 10.5000 个` | `测试物料入库 10.5 个` | -| `测试物料出库 100.0000 个` | `测试物料出库 100 个` | - ---- - -## 问题修复 - -### 11. operator 字段违反 NOT NULL 约束 - -**问题:** 出入库单自动生成应收/应付时,`fin_ar_receipt` 表的 `operator` 字段为 null,导致插入失败。 - -**错误日志:** -``` -ERROR: null value in column "operator" of relation "fin_ar_receipt" violates not-null constraint -``` - -**根因:** `MyMetaObjectHandler` 自动填充处理器没有填充 `operator` 字段,当 `UserContext.getUserName()` 返回 null 时导致插入失败。 - -**修复方案:** 在 `MyMetaObjectHandler.insertFill()` 中添加 `operator` 字段的自动填充,但**仅在用户未设置时才填充**: - -```java -// 操作人(operator 字段,用于财务收款/付款单)- 仅当未设置时自动填充 -String operatorName = UserContext.getUserName(); -if (operatorName == null || operatorName.isEmpty()) { - operatorName = "管理员"; -} -// 检查是否已有值,有值则不覆盖 -if (metaObject.hasGetter("operator") && metaObject.getValue("operator") == null) { - this.strictInsertFill(metaObject, "operator", String.class, operatorName); -} -``` - -**行为说明:** -- ✅ 用户手动设置 `operator` → 保留用户设置的值 -- ✅ 用户未设置 `operator` → 自动填充当前登录用户(兜底"管理员") -- ✅ 自动生成场景(无用户上下文)→ 自动填充"管理员" - -**影响范围:** 适用于 `fin_ar_receipt`(收款单)和 `fin_ap_payment`(付款单)等需要 `operator` 的表 - ---- - -## 测试进展 - -### 集成测试覆盖率 - -| 测试类 | 测试数 | 通过 | 失败 | 覆盖率 | -|--------|--------|------|------|--------| -| `MaterialControllerTest` | 20 | 20 | 0 | 100% ✅ | -| `InboundControllerTest` | 23 | 23 | 0 | 100% ✅ | -| `OutboundControllerTest` | 23 | 23 | 0 | 100% ✅ | -| **总计** | **66** | **66** | **0** | **100%** ✅ | - -**测试覆盖的功能:** -- ✅ 物料 CRUD、分页查询、详情查询 -- ✅ 采购入库单保存、自动填充单价、更新物料最后入库价 -- ✅ 销售出库单保存、自动填充单价、更新物料最后出库价 -- ✅ 编码唯一性校验、必填字段校验、BigDecimal 精度比较 - ---- - -## 经验教训 - -1. **BigDecimal 比较**:测试断言使用 `compareTo()` 而非 `equals()`,避免精度差异(`10.50` vs `10.5000`) -2. **自动填充优先级**:用户手动设置的值优先于自动填充,`MyMetaObjectHandler` 需要先检查字段是否已有值 -3. **批量查询优化**:物料选择器使用 `selectBatchIds` 批量查询上次单价,避免 N+1 查询问题 -4. **数量格式化**:`BigDecimal` 转字符串时使用 `stripTrailingZeros().toPlainString()` 去除末尾多余的 0,同时避免科学计数法 - ---- - -## 待办事项 - -- [ ] 前端对接物料选择器接口,显示上次单价参考 -- [ ] 验证采购入库/销售出库单价必填的前端校验 -- [ ] 运行完整测试套件确保无回归 -- [ ] 记录数据库变更日志到 `doc/数据库变更日志.md` diff --git a/workspace-backend/memory/2026-05-29.md b/workspace-backend/memory/2026-05-29.md deleted file mode 100644 index 1a3f7af..0000000 --- a/workspace-backend/memory/2026-05-29.md +++ /dev/null @@ -1,330 +0,0 @@ -## 10:50 — AI 调用记录方案评估 - -**话题:** 记录 AI 调用(session_id, tokens, 返回结果),复用操作日志机制 - -**评估结论:方案 A — 扩展 OperLog** -- `sys_oper_log` 新增 5 字段:`ai_session_id`, `ai_model`, `prompt_tokens`, `completion_tokens`, `total_tokens` -- `module` 复用为 `"AI识别"` / `"AI对话"` 区分业务 -- 复用现有 OperLog 全部基础设施(service/mapper/controller/分页/查询) -- 工作量最小,约 20min -- 方案已确认,待实现 - -## 10:50 — Git 约定提醒 - -提示 commit 时必须附带 commit message,让用户可直接复制运行。 - -## 11:08~11:18 — AI 调用记录实现 ✅ - -**改动点:** -1. `scripts/postgresql/10-system.sql` — DDL 新增 `ai_session_id`, `ai_model`, `prompt_tokens`, `completion_tokens`, `total_tokens` -2. `scripts/postgresql/fix-ai-oper-log.sql` — 迁移脚本(新增) -3. `OperLog.java` — 实体添加 5 个对应字段 -4. `AiServiceImpl.java` — 注入 `OperLogService`,在 `chatText()`/`chatWithImages()` 调用前后记录日志(含 sessionId, tokens, 耗时, 输入/输出摘要) -5. `AiChatResponseDTO` — 新增 `sessionId` 字段 -6. `DeepSeekChatRequestDTO` — 新增 `sessionId` 字段(`@JsonIgnore`,仅用于日志传递) - -**执行迁移:** 本地库(localhost:31983)跑 `fix-ai-oper-log.sql` - -**测试结果:** ✅ `Tests run: 2, Failures: 0, Errors: 0` — 日志成功写入 sys_oper_log(ai_model=qwen3.5-plus 等字段正确) -## 13:00~13:06 — 测试库执行 AI 迁移 ✅ - -- 本地 WSL Docker 可连接测试库(`docker exec -i tiny-erp-db psql -U postgres -d tinyerp`) -- 执行 `fix-ai-oper-log.sql`,5 个 AI 字段(`ai_session_id`, `ai_model`, `prompt_tokens`, `completion_tokens`, `total_tokens`)已添加 -- 验证本地库(localhost:31983)和测试库(Docker db:5432)字段均存在 ✅ - -## 13:08~13:10 — 日志文件冲突问题 → 方案A - -**问题:** IDEA 和 Docker 都在 WSL 同一机器运行,`./logs/` 会互相覆盖 - -**方案A:** docker-compose 挂载路径改为 `./logs-docker:/app/logs` -- `.gitignore` 添加 `logs-docker/` -- `Dockerfile` 保留 root 运行(无 `USER appuser`) -- 已实施 ✅ - -## 13:11~13:13 — deploy-test.sh 脚本 - -创建 `deploy-test.sh` 一键部署脚本: -1. `mvn clean install -DskipTests` -2. `docker compose stop/rm/build/up app` -3. `curl health` 自动验证(失败重试 15s) - -## 13:14~13:22 — 测试目录规范化 - -**问题:** 大部分测试包路径缺少 `module` 层级,与源码不一致 - -- 移动所有测试到 `com.witsoft.erp.module.*` 包下 -- 统一先删旧包(git rm)、再建新包、再写入 -- 运行全量测试通过 ✅ -- `test.base.BaseControllerTest` 保留在 `com.witsoft.erp.test.base`(基建归 test,不归 module) - -## 13:38~14:11 — docs/ 目录全面清理 - -**整理方向:** - -| 操作 | 说明 | -|------|------| -| ✅ 合并 API 规范到项目规范.md | 删除 `docs/API/` | -| ✅ 删除 `docs/数据库/` | 以 SQL 脚本为唯一来源 | -| ✅ 文档按模块移入对应子目录 | `06-AI单据识别需求.md` → `需求/AI模块`,`物料信息填充公共服务总结.md` → `设计/主数据模块` | -| ✅ 按模块独立编号 | 全局连续 → 每个模块 01- 起编 | -| ✅ 测试文件重排序 | 按 登录→首页→物料→字典→入库出库→库存盘点→操作日志 排列 | -| ✅ README.md 同步 | 目录结构、版本历史逐一同步,标注"(预留)"空目录 | - -**编号规则变更:** 跨模块连续编号(旧)→ 按模块独立编号(新),新增文档只加模块内序号,不碰其他模块。 - -## 14:14 — UserContext 使用指南.md 文件缺失 - -文档中引用 `设计/系统模块/UserContext 使用指南.md`,但实际文件不存在(被 `yangxuan/` → `docs/` 重命名遗漏)。已补充。 -## 10:50 — AI 调用记录方案评估 - -**话题:** 记录 AI 调用(session_id, tokens, 返回结果),复用操作日志机制 - -**评估结论:方案 A — 扩展 OperLog** -- `sys_oper_log` 新增 5 字段:`ai_session_id`, `ai_model`, `prompt_tokens`, `completion_tokens`, `total_tokens` -- `module` 复用为 `"AI识别"` / `"AI对话"` 区分业务 -- 复用现有 OperLog 全部基础设施(service/mapper/controller/分页/查询) -- 工作量最小,约 20min -- 方案已确认,待实现 - -## 10:50 — Git 约定提醒 - -提示 commit 时必须附带 commit message,让用户可直接复制运行。 - -## 11:08~11:18 — AI 调用记录实现 ✅ - -**改动点:** -1. `scripts/postgresql/10-system.sql` — DDL 新增 `ai_session_id`, `ai_model`, `prompt_tokens`, `completion_tokens`, `total_tokens` -2. `scripts/postgresql/fix-ai-oper-log.sql` — 迁移脚本(新增) -3. `OperLog.java` — 实体添加 5 个对应字段 -4. `AiServiceImpl.java` — 注入 `OperLogService`,在 `chatText()`/`chatWithImages()` 调用前后记录日志(含 sessionId, tokens, 耗时, 输入/输出摘要) -5. `AiChatResponseDTO` — 新增 `sessionId` 字段 -6. `DeepSeekChatRequestDTO` — 新增 `sessionId` 字段(`@JsonIgnore`,仅用于日志传递) - -**执行迁移:** 本地库(localhost:31983)跑 `fix-ai-oper-log.sql` - -**测试结果:** ✅ `Tests run: 2, Failures: 0, Errors: 0` — 日志成功写入 sys_oper_log(ai_model=qwen3.5-plus 等字段正确) -## 13:00~13:06 — 测试库执行 AI 迁移 ✅ - -- 本地 WSL Docker 可连接测试库(`docker exec -i tiny-erp-db psql -U postgres -d tinyerp`) -- 执行 `fix-ai-oper-log.sql`,5 个 AI 字段(`ai_session_id`, `ai_model`, `prompt_tokens`, `completion_tokens`, `total_tokens`)已添加 -- 验证本地库(localhost:31983)和测试库(Docker db:5432)字段均存在 ✅ - -## 13:08~13:10 — 日志文件冲突问题 → 方案A - -**问题:** IDEA 和 Docker 都在 WSL 同一机器运行,`./logs/` 会互相覆盖 - -**方案A:** docker-compose 挂载路径改为 `./logs-docker:/app/logs` -- `.gitignore` 添加 `logs-docker/` -- `Dockerfile` 保留 root 运行(无 `USER appuser`) -- 已实施 ✅ - -## 13:11~13:13 — deploy-test.sh 脚本 - -创建 `deploy-test.sh` 一键部署脚本: -1. `mvn clean install -DskipTests` -2. `docker compose stop/rm/build/up app` -3. `curl health` 自动验证(失败重试 15s) - -## 13:14~13:22 — 测试目录规范化 - -**问题:** 大部分测试包路径缺少 `module` 层级,与源码不一致 - -- 移动所有测试到 `com.witsoft.erp.module.*` 包下 -- 统一先删旧包(git rm)、再建新包、再写入 -- 运行全量测试通过 ✅ -- `test.base.BaseControllerTest` 保留在 `com.witsoft.erp.test.base`(基建归 test,不归 module) - -## 13:38~14:11 — docs/ 目录全面清理 - -**整理方向:** - -| 操作 | 说明 | -|------|------| -| ✅ 合并 API 规范到项目规范.md | 删除 `docs/API/` | -| ✅ 删除 `docs/数据库/` | 以 SQL 脚本为唯一来源 | -| ✅ 文档按模块移入对应子目录 | `06-AI单据识别需求.md` → `需求/AI模块`,`物料信息填充公共服务总结.md` → `设计/主数据模块` | -| ✅ 按模块独立编号 | 全局连续 → 每个模块 01- 起编 | -| ✅ 测试文件重排序 | 按 登录→首页→物料→字典→入库出库→库存盘点→操作日志 排列 | -| ✅ README.md 同步 | 目录结构、版本历史逐一同步,标注"(预留)"空目录 | - -**编号规则变更:** 跨模块连续编号(旧)→ 按模块独立编号(新),新增文档只加模块内序号,不碰其他模块。 - -## 14:14 — UserContext 使用指南.md 文件缺失 - -文档中引用 `设计/系统模块/UserContext 使用指南.md`,但实际文件不存在(被 `yangxuan/` → `docs/` 重命名遗漏)。已补充。 - -## 14:18 — docs/测试 HTTP 文件重排序 ✅ - -按执行依赖逻辑重新编号: - -| 序号 | 文件 | 说明 | -|------|------|------| -| 00 | 登录登出 | 先拿 token | -| 01 | 首页 API 测试 | 仪表盘概览 | -| 02 | 物料分页 | 基础数据查询 | -| 03 | 数据字典与映射 | 字典+翻译 | -| 04 | 入库出库 | 核心业务流程 | -| 05 | 实时库存&盘点 | 库存状态 | -| 06 | 操作日志 | 审计兜底 | - -同步更新了 `docs/README.md`。 - -## 14:24 — scripts/postgresql 目录组织讨论 - -**话题:** 杨轩问脚本目录是否可以按 ddl/dml/init 或按模块区分。 - -**分析结果:** 当前脚本目录的问题: -1. 编号混乱(00/03/10/20/21/22...99,无一致规则) -2. DDL/DML 混在一起(如 10-system.sql 既建表又插数据) -3. fix- 前缀不统一(26-material-last-price.sql 也是 ALTER 但没用 fix- 前缀) - -**方案A(用户选中):** 二级目录 `ddl/`、`dml/`、`migration/`、`mock/`,根目录保留一个 `init.sql` 通过 `\i` 引用子目录文件(因为 `docker-entrypoint-initdb.d` 只处理扁平 .sql 文件)。 - -**待实现:** [not yet started — compaction happened before implementation] -## 10:50 — AI 调用记录方案评估 - -**话题:** 记录 AI 调用(session_id, tokens, 返回结果),复用操作日志机制 - -**评估结论:方案 A — 扩展 OperLog** -- `sys_oper_log` 新增 5 字段:`ai_session_id`, `ai_model`, `prompt_tokens`, `completion_tokens`, `total_tokens` -- `module` 复用为 `"AI识别"` / `"AI对话"` 区分业务 -- 复用现有 OperLog 全部基础设施(service/mapper/controller/分页/查询) -- 工作量最小,约 20min -- 方案已确认,待实现 - -## 10:50 — Git 约定提醒 - -提示 commit 时必须附带 commit message,让用户可直接复制运行。 - -## 11:08~11:18 — AI 调用记录实现 ✅ - -**改动点:** -1. `scripts/postgresql/10-system.sql` — DDL 新增 `ai_session_id`, `ai_model`, `prompt_tokens`, `completion_tokens`, `total_tokens` -2. `scripts/postgresql/fix-ai-oper-log.sql` — 迁移脚本(新增) -3. `OperLog.java` — 实体添加 5 个对应字段 -4. `AiServiceImpl.java` — 注入 `OperLogService`,在 `chatText()`/`chatWithImages()` 调用前后记录日志(含 sessionId, tokens, 耗时, 输入/输出摘要) -5. `AiChatResponseDTO` — 新增 `sessionId` 字段 -6. `DeepSeekChatRequestDTO` — 新增 `sessionId` 字段(`@JsonIgnore`,仅用于日志传递) - -**执行迁移:** 本地库(localhost:31983)跑 `fix-ai-oper-log.sql` - -**测试结果:** ✅ `Tests run: 2, Failures: 0, Errors: 0` — 日志成功写入 sys_oper_log(ai_model=qwen3.5-plus 等字段正确) -## 13:00~13:06 — 测试库执行 AI 迁移 ✅ - -- 本地 WSL Docker 可连接测试库(`docker exec -i tiny-erp-db psql -U postgres -d tinyerp`) -- 执行 `fix-ai-oper-log.sql`,5 个 AI 字段(`ai_session_id`, `ai_model`, `prompt_tokens`, `completion_tokens`, `total_tokens`)已添加 -- 验证本地库(localhost:31983)和测试库(Docker db:5432)字段均存在 ✅ - -## 13:08~13:10 — 日志文件冲突问题 → 方案A - -**问题:** IDEA 和 Docker 都在 WSL 同一机器运行,`./logs/` 会互相覆盖 - -**方案A:** docker-compose 挂载路径改为 `./logs-docker:/app/logs` -- `.gitignore` 添加 `logs-docker/` -- `Dockerfile` 保留 root 运行(无 `USER appuser`) -- 已实施 ✅ - -## 13:11~13:13 — deploy-test.sh 脚本 - -创建 `deploy-test.sh` 一键部署脚本: -1. `mvn clean install -DskipTests` -2. `docker compose stop/rm/build/up app` -3. `curl health` 自动验证(失败重试 15s) - -## 13:14~13:22 — 测试目录规范化 - -**问题:** 大部分测试包路径缺少 `module` 层级,与源码不一致 - -- 移动所有测试到 `com.witsoft.erp.module.*` 包下 -- 统一先删旧包(git rm)、再建新包、再写入 -- 运行全量测试通过 ✅ -- `test.base.BaseControllerTest` 保留在 `com.witsoft.erp.test.base`(基建归 test,不归 module) - -## 13:38~14:11 — docs/ 目录全面清理 - -**整理方向:** - -| 操作 | 说明 | -|------|------| -| ✅ 合并 API 规范到项目规范.md | 删除 `docs/API/` | -| ✅ 删除 `docs/数据库/` | 以 SQL 脚本为唯一来源 | -| ✅ 文档按模块移入对应子目录 | `06-AI单据识别需求.md` → `需求/AI模块`,`物料信息填充公共服务总结.md` → `设计/主数据模块` | -| ✅ 按模块独立编号 | 全局连续 → 每个模块 01- 起编 | -| ✅ 测试文件重排序 | 按 登录→首页→物料→字典→入库出库→库存盘点→操作日志 排列 | -| ✅ README.md 同步 | 目录结构、版本历史逐一同步,标注"(预留)"空目录 | - -**编号规则变更:** 跨模块连续编号(旧)→ 按模块独立编号(新),新增文档只加模块内序号,不碰其他模块。 - -## 14:14 — UserContext 使用指南.md 文件缺失 - -文档中引用 `设计/系统模块/UserContext 使用指南.md`,但实际文件不存在(被 `yangxuan/` → `docs/` 重命名遗漏)。已补充。 - -## 14:18 — docs/测试 HTTP 文件重排序 ✅ - -按执行依赖逻辑重新编号: - -| 序号 | 文件 | 说明 | -|------|------|------| -| 00 | 登录登出 | 先拿 token | -| 01 | 首页 API 测试 | 仪表盘概览 | -| 02 | 物料分页 | 基础数据查询 | -| 03 | 数据字典与映射 | 字典+翻译 | -| 04 | 入库出库 | 核心业务流程 | -| 05 | 实时库存&盘点 | 库存状态 | -| 06 | 操作日志 | 审计兜底 | - -同步更新了 `docs/README.md`。 - -## 14:24 — scripts/postgresql 目录组织讨论 - -**话题:** 杨轩问脚本目录是否可以按 ddl/dml/init 或按模块区分。 - -**分析结果:** 当前脚本目录的问题: -1. 编号混乱(00/03/10/20/21/22...99,无一致规则) -2. DDL/DML 混在一起(如 10-system.sql 既建表又插数据) -3. fix- 前缀不统一(26-material-last-price.sql 也是 ALTER 但没用 fix- 前缀) - -**方案A(用户选中):** 二级目录 `ddl/`、`dml/`、`migration/`、`mock/`,根目录保留一个 `init.sql` 通过 `\i` 引用子目录文件(因为 `docker-entrypoint-initdb.d` 只处理扁平 .sql 文件)。 - -**待实现:** [not yet started — compaction happened before implementation] - -## 14:47~15:30 — AI 接口文档 + 测试文件 ✅ - -**AI 接口文档:** `docs/需求/AI模块/02-AI单据识别接口文档.md` -**AI 测试文件:** `docs/测试/07-AI单据识别.http` -- 解释了 exactMatch=false 仍有 materialId 的语义:近似匹配自动选最佳,前端标黄提示 -- `docs/README.md` 同步更新 - -**提交策略:** 用户自行处理敏感配置文件的版本管理(`application.yml`、`application-local.yml`、`scripts/idea/http-client.env.json`) - -## 15:30~16:20 — 物料选择器 excludedMaterialIds 实现 ✅ - -**需求:** 出库/入库选择器支持排除已选物料 - -**改动点:** -1. `MaterialSelectorReqDTO` — 新增 `excludedMaterialIds`(`List`) -2. `MaterialServiceImpl` — 4 个分页/计数方法加 `excludedMaterialIds` 参数 -3. `StockMapper.xml` — 4 个 SQL 加 ` AND s.material_id NOT IN ...` -4. `MaterialSelectorServiceImpl` — 新增 `filterExcludedIds()` 私有方法做内存过滤 + queryByIds 方法加上排除逻辑 - -**MyBatis 行为验证:** -- `null` → false,跳过 NOT IN -- `[]`(空列表)→ `size() > 0` 为 false,跳过 NOT IN -- `[1, 2]` → 进 NOT IN,WHERE 过滤 - -**测试覆盖:** 集成测试三类场景全部通过 ✅ -- `testMaterialSelector_empty`(传 null)✅ -- `testMaterialSelector_emptyExcludeList`(传 `[]`)✅ -- `testMaterialSelector_withExcludedIds`(传实际 ID,验证排除正确)✅ - -## 15:55 — 测试编号冲突修复 - -**问题:** 新增物料选择器测试插入 `@Order(4)/@Order(5)` 后,原有的 `@Order(4)`(新增出库单)和 `@Order(5)`(明细为空)未重编号,导致 `@Order(4)/@Order(5)/@Order(7)` 重复 - -**修复:** 将所有 `@Order(n)` 增加 2(n>=4 的改成 n+2),最后 2 个测试增加 2。涉及约 20 个测试方法。 - -## 16:05 — 测试 bug 修复 - -**问题:** 排除测试中 `assertFalse(list.stream().anyMatch(s -> s.getId().equals(excludedId)))` 失败 -**原因:** `StockPageDTO.getId()` 返回库存记录 ID(`s.id`),而非物料 ID(`s.material_id`)。SQL NOT IN 排除的是 `material_id`,但测试用 `getId()` 取了库存记录 ID -**修复:** 改用 `getMaterialId()` 验证排除 \ No newline at end of file diff --git a/workspace-backend/memory/2026-07-09.md b/workspace-backend/memory/2026-07-09.md deleted file mode 100644 index 57f8185..0000000 --- a/workspace-backend/memory/2026-07-09.md +++ /dev/null @@ -1,14 +0,0 @@ -# 2026-07-09 - -## DailyHotJob 改造完成 -- planner 派发任务 → backend 执行改造 → planner review 通过,共 7 个 commit -- 涉及:异常传播、租户注解、批量查重插入、并发搜索、文件分片、时间窗口、Redis Key 可配置 -- 任务文档存档于 `tasks/dailyhot-job-fix-tasks.md` - -## 教训:不能越权 -- 杨轩明确强调:**不能越权** — 不要替用户做决定,不要自行启动或派发任务,由用户决策后再执行 - -## 编译修复 -- `JavInfoMapper.insertBatch(Collection)` 返回类型 `int` → `Boolean`(与父类 `BaseMapperX` 一致) -- `JackettController.dailyHot()` 加 `throws Exception`(顺带修复同一 module 编译错误) -- Maven 编译验证通过 diff --git a/workspace-backend/skills/qiushi-openclaw-skill/.clawhub/origin.json b/workspace-backend/skills/qiushi-openclaw-skill/.clawhub/origin.json new file mode 100644 index 0000000..458b22f --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/.clawhub/origin.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "registry": "https://clawhub.ai", + "slug": "qiushi-openclaw-skill", + "ownerHandle": "skytodmoon", + "installedVersion": "1.0.0", + "installedAt": 1785745381570, + "artifact": { + "kind": "archive", + "sha256": "1e2d3712d2974143449c9e47b0379725a954794c498727799f782ac7b1db7a49", + "integrity": "sha256-Hi03EtKXQUNEnJ5HsDeXJalUeUxJhyd5n3gqx7Hbekk=" + }, + "skillFile": { + "path": "SKILL.md", + "sha256": "b21d933b7f61584d2254fba25fd531c16f19e33e10016ddfbdea1a5e2d5d6d25" + } +} diff --git a/workspace-backend/skills/qiushi-openclaw-skill/README.md b/workspace-backend/skills/qiushi-openclaw-skill/README.md new file mode 100644 index 0000000..e93f2f0 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/README.md @@ -0,0 +1,116 @@ +# 求是 OpenClaw Skills + +## 项目介绍 + +求是 OpenClaw Skills 是基于毛泽东思想方法论的 AI Agent 技能集合,按照 OpenClaw 技能格式进行改造,旨在为 AI 提供系统化的思考和行动框架。 + +## 技能列表 + +| 技能名称 | 核心要义 | 适用场景 | +|---------|---------|---------| +| arming-thought | 武装思想,实事求是总原则 | 对话开始时建立方法论基础 | +| contradiction-analysis | 矛盾分析法,抓主要矛盾 | 复杂问题分析 | +| practice-cognition | 实践认识论,实践→认识→再实践 | 方案验证与迭代 | +| investigation-first | 调查研究,没有调查就没有发言权 | 决策前的信息收集 | +| mass-line | 群众路线,从群众中来到群众中去 | 反馈整合与方案验证 | +| criticism-self-criticism | 批评与自我批评,惩前毖后治病救人 | 工作审视与质量改进 | +| protracted-strategy | 持久战略,战略上藐视战术上重视 | 长期复杂任务规划 | +| concentrate-forces | 集中兵力,伤其十指不如断其一指 | 优先级决策与资源聚焦 | +| spark-prairie-fire | 星火燎原,建立根据地不做流寇 | 从零开始的发展策略 | +| overall-planning | 统筹兼顾,调动一切积极因素 | 多目标平衡与权衡 | +| workflows | 工作流组合,多种方法串联 | 复杂任务的流程设计 | + +## 安装方法 + +### 手动安装 + +1. 将 `qiushi-openclaw-skills` 目录复制到 OpenClaw 的技能目录: + ```bash + cp -r qiushi-openclaw-skills ~/.openclaw/skills/ + ``` + +2. 重启 OpenClaw 或刷新技能列表。 + +### ClawHub 安装(未来支持) + +未来将支持通过 ClawHub 一键安装。 + +## 技能结构 + +每个技能都遵循 OpenClaw 的标准结构: + +``` +skill-name/ +└── SKILL.md # 技能定义文件 +``` + +### SKILL.md 结构 + +```yaml +--- +name: skill-name +description: "技能描述,决定 AI 何时自动触发此技能" +tools: [] # 技能需要使用的工具 +--- + +# 技能名称 + +## 触发条件 +当...时触发此技能。 + +## 执行步骤 +1. 第一步... +2. 第二步... + +## 核心原则 +... + +## 不适用场景 +- ... + +## 应用场景 +- ... + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| ... | ... | + +## 操作规程 +当本 skill 被触发时,执行以下步骤: +1. ... + +## 与其他 skill 的关系 +- ... +``` + +## 使用方法 + +1. **自动触发**:OpenClaw 会根据技能的 `description` 字段自动判断何时触发相应技能。 + +2. **手动触发**:在 OpenClaw 中使用 `/skill-name` 命令手动触发技能。 + +3. **工作流组合**:使用 `workflows` 技能组合多个技能,形成完整的工作流程。 + +## 核心原则 + +- **实事求是**:从客观存在着的实际事物出发,让事实规定判断,让现实修正理论。 +- **矛盾分析**:识别矛盾、抓住主要矛盾、区分矛盾性质。 +- **实践认识论**:实践→认识→再实践,螺旋上升。 +- **调查研究**:没有调查就没有发言权。 +- **群众路线**:从群众中来,到群众中去。 +- **批评与自我批评**:惩前毖后,治病救人。 +- **持久战略**:战略上藐视,战术上重视。 +- **集中兵力**:伤其十指不如断其一指。 +- **星火燎原**:建立根据地,不做流寇。 +- **统筹兼顾**:调动一切积极因素。 + +## 注意事项 + +- 本项目的方法论来源于毛泽东思想,旨在为 AI 提供科学的思考和行动框架。 +- 技能的触发条件和执行步骤已经过优化,适合 AI 理解和执行。 +- 可以根据具体任务需求,灵活组合使用不同的技能。 + +## 许可证 + +MIT License diff --git a/workspace-backend/skills/qiushi-openclaw-skill/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/SKILL.md new file mode 100644 index 0000000..9883246 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/SKILL.md @@ -0,0 +1,50 @@ +--- +name: qiushi-openclaw-skills +description: "求是 OpenClaw Skills 是基于毛泽东思想方法论的 AI Agent 技能集合,按照 OpenClaw 技能格式进行改造,旨在为 AI 提供系统化的思考和行动框架。" +tools: [] +--- + +# 求是 OpenClaw Skills + +## 项目介绍 + +求是 OpenClaw Skills 是基于毛泽东思想方法论的 AI Agent 技能集合,按照 OpenClaw 技能格式进行改造,旨在为 AI 提供系统化的思考和行动框架。 + +## 技能列表 + +| 技能名称 | 核心要义 | 适用场景 | +|---------|---------|---------| +| arming-thought | 武装思想,实事求是总原则 | 对话开始时建立方法论基础 | +| contradiction-analysis | 矛盾分析法,抓主要矛盾 | 复杂问题分析 | +| practice-cognition | 实践认识论,实践→认识→再实践 | 方案验证与迭代 | +| investigation-first | 调查研究,没有调查就没有发言权 | 决策前的信息收集 | +| mass-line | 群众路线,从群众中来到群众中去 | 反馈整合与方案验证 | +| criticism-self-criticism | 批评与自我批评,惩前毖后治病救人 | 工作审视与质量改进 | +| protracted-strategy | 持久战略,战略上藐视战术上重视 | 长期复杂任务规划 | +| concentrate-forces | 集中兵力,伤其十指不如断其一指 | 优先级决策与资源聚焦 | +| spark-prairie-fire | 星火燎原,建立根据地不做流寇 | 从零开始的发展策略 | +| overall-planning | 统筹兼顾,调动一切积极因素 | 多目标平衡与权衡 | +| workflows | 工作流组合,多种方法串联 | 复杂任务的流程设计 | + +## 核心原则 + +- **实事求是**:从客观存在着的实际事物出发,让事实规定判断,让现实修正理论。 +- **矛盾分析**:识别矛盾、抓住主要矛盾、区分矛盾性质。 +- **实践认识论**:实践→认识→再实践,螺旋上升。 +- **调查研究**:没有调查就没有发言权。 +- **群众路线**:从群众中来,到群众中去。 +- **批评与自我批评**:惩前毖后,治病救人。 +- **持久战略**:战略上藐视,战术上重视。 +- **集中兵力**:伤其十指不如断其一指。 +- **星火燎原**:建立根据地,不做流寇。 +- **统筹兼顾**:调动一切积极因素。 + +## 安装方法 + +```bash +clawhub install qiushi-openclaw-skills +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/_meta.json b/workspace-backend/skills/qiushi-openclaw-skill/_meta.json new file mode 100644 index 0000000..2c1e692 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/_meta.json @@ -0,0 +1,6 @@ +{ + "ownerId": "kn77hfjtjjwht588zc4scw4qr582vrc6", + "slug": "qiushi-openclaw-skill", + "version": "1.0.0", + "publishedAt": 1775635456843 +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/arming-thought/README.md b/workspace-backend/skills/qiushi-openclaw-skill/arming-thought/README.md new file mode 100644 index 0000000..b0c0e4a --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/arming-thought/README.md @@ -0,0 +1,59 @@ +# 武装思想 + +## 技能介绍 + +武装思想是求是 OpenClaw Skills 系列中的核心技能,在每次新的顶层对话开始时自动调用,用于建立"实事求是"的总原则,并在明确适用时为后续任务选择下游技能。 + +## 核心功能 + +- **实事求是总原则**:先看事实,再下判断,让事实规定判断,让现实修正理论 +- **技能调度**:根据任务需求自动选择合适的下游技能 +- **行为规范**:提供可观测的行为准则,确保 AI 行为符合方法论要求 + +## 触发条件 + +当开始新的顶层对话时触发,用于建立方法论基础和选择下游技能。 + +## 执行步骤 + +1. 应用"实事求是"总原则:先看事实,再下判断 +2. 评估当前任务是否需要调用下游技能 +3. 如需要,选择最适合的技能进行调用 + +## 技能映射 + +| 遇到的情况 | 应调用的 skill | +|-----------|---------------| +| 面对复杂问题,不知从何入手 | contradiction-analysis | +| 需要验证方案或迭代改进 | practice-cognition | +| 要做决策但信息不足 | investigation-first | +| 需要收集多方意见或整合多源信息 | mass-line | +| 完成工作后需要审视质量 | criticism-self-criticism | +| 面对长期复杂任务 | protracted-strategy | +| 多个任务争夺注意力 | concentrate-forces | +| 从零开始,资源有限 | spark-prairie-fire | +| 多个目标需要平衡 | overall-planning | +| 一个任务明确需要多种方法串联 | workflows | + +## 不适用场景 + +- 子 agent 执行单一具体任务时 +- 用户需求非常具体,且执行路径单一明确 +- 只是一次性简单输出,不涉及调查、取舍、验证或复盘 +- 宿主平台已经在执行等价流程 + +## 指令优先级 + +1. 用户的明确指示 +2. 宿主平台的系统规则与安全约束 +3. qiushi skills 作为补充的方法论框架 + +## 安装方法 + +```bash +clawhub install arming-thought +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/arming-thought/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/arming-thought/SKILL.md new file mode 100644 index 0000000..772061a --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/arming-thought/SKILL.md @@ -0,0 +1,54 @@ +--- +name: arming-thought +description: "在每次新的顶层对话开始时自动调用,用于建立'实事求是'的总原则,并在明确适用时为后续任务选择下游 skill" +tools: [] +--- + +# 武装思想 + +## 触发条件 +当开始新的顶层对话时触发,用于建立方法论基础和选择下游技能。 + +## 执行步骤 +1. 应用"实事求是"总原则:先看事实,再下判断 +2. 评估当前任务是否需要调用下游技能 +3. 如需要,选择最适合的技能进行调用 + +## 总原则:实事求是 +"'实事'就是客观存在着的一切事物,'是'就是客观事物的内部联系,即规律性,'求'就是我们去研究。" —— 毛泽东《改造我们的学习》 + +**核心行为规则:** +- 不空谈,看事实:每个结论后面附具体依据 +- 验证才算完成:声称"完成"之前执行验证动作 +- 承认不知道:遇到不确定信息时,明确标注"需要进一步确认" +- 遇阻探原因:遇到失败时说明原因、补调查或更换路径 + +## 调度规则 +只有在下列任一条件成立时,才调用下游 skill: +- 任务明显匹配某个 skill 的触发条件 +- 当前结果质量会因为该 skill 明显提升 +- 你已经遇到阻塞,需要一个明确的方法框架来推进 + +## 技能映射 +| 遇到的情况 | 应调用的 skill | +|-----------|---------------| +| 面对复杂问题,不知从何入手 | contradiction-analysis | +| 需要验证方案或迭代改进 | practice-cognition | +| 要做决策但信息不足 | investigation-first | +| 需要收集多方意见或整合多源信息 | mass-line | +| 完成工作后需要审视质量 | criticism-self-criticism | +| 面对长期复杂任务 | protracted-strategy | +| 多个任务争夺注意力 | concentrate-forces | +| 从零开始,资源有限 | spark-prairie-fire | +| 多个目标需要平衡 | overall-planning | +| 一个任务明确需要多种方法串联 | workflows | + +## 不要过度调用 +- 用户需求非常具体,且执行路径单一明确 +- 只是一次性简单输出,不涉及调查、取舍、验证或复盘 +- 宿主平台已经在执行等价流程 + +## 指令优先级 +1. 用户的明确指示 +2. 宿主平台的系统规则与安全约束 +3. qiushi skills 作为补充的方法论框架 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/arming-thought/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/arming-thought/clawhub.json new file mode 100644 index 0000000..e3570ec --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/arming-thought/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "arming-thought", + "version": "1.0.0", + "displayName": "武装思想", + "description": "在每次新的顶层对话开始时自动调用,用于建立'实事求是'的总原则,并在明确适用时为后续任务选择下游 skill", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "实事求是"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/concentrate-forces/README.md b/workspace-backend/skills/qiushi-openclaw-skill/concentrate-forces/README.md new file mode 100644 index 0000000..fcba4ea --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/concentrate-forces/README.md @@ -0,0 +1,79 @@ +# 集中兵力 + +## 技能介绍 + +集中兵力是求是 OpenClaw Skills 系列中的核心技能,基于毛泽东的《中国革命战争的战略问题》,强调"伤其十指不如断其一指",用于当多个任务争夺注意力时优先处理重要任务。 + +## 核心功能 + +- **任务分析**:分析所有待处理的任务 +- **优先级排序**:根据重要性和紧急性对任务进行排序 +- **资源集中**:将资源集中到最重要的任务上 +- **各个击破**:逐个解决优先级高的任务 + +## 触发条件 + +当多个任务争夺注意力,需要优先处理重要任务时触发。 + +## 执行步骤 + +1. **任务分析**:分析所有待处理的任务 +2. **优先级排序**:根据重要性和紧急性对任务进行排序 +3. **资源集中**:将资源集中到最重要的任务上 +4. **各个击破**:逐个解决优先级高的任务 +5. **动态调整**:根据情况动态调整优先级和资源分配 + +## 核心原则 + +伤其十指不如断其一指。不打无准备之仗。 + +## 不适用场景 + +- 只有一个任务 +- 所有任务都同等重要 +- 任务之间相互依赖,无法单独处理 +- 时间充足,不需要优先级排序 + +## 集中兵力的应用 + +- **任务管理**:管理多个并发任务 +- **项目规划**:规划项目的优先级 +- **资源分配**:合理分配有限的资源 +- **问题解决**:集中精力解决关键问题 + +## 常见错误 + +| 错误 | 正确做法 | +|------|---------| +| 平均分配资源 | 集中资源到最重要的任务 | +| 同时处理多个任务 | 一次只处理一个重要任务 | +| 忽视任务的重要性 | 认真评估任务的重要性和紧急性 | +| 缺乏准备 | 充分准备后再行动 | +| 不根据情况调整 | 动态调整优先级和资源分配 | + +## 操作规程 + +当本 skill 被触发时,执行以下步骤: +1. **任务清单**:列出所有待处理的任务 +2. **评估排序**:评估每个任务的重要性和紧急性,进行排序 +3. **资源规划**:规划所需的资源,确保重要任务得到充分支持 +4. **执行计划**:制定详细的执行计划,明确每个任务的时间和资源需求 +5. **集中执行**:集中精力执行最重要的任务,确保完成质量 +6. **评估调整**:定期评估任务进展,根据情况调整优先级和资源分配 + +## 与其他 skill 的关系 + +- **矛盾分析法**:集中兵力需要识别主要矛盾 +- **持久战略**:在持久战略中,需要在关键阶段集中兵力 +- **统筹兼顾**:集中兵力需要在全局范围内统筹兼顾 +- **实践认识论**:集中兵力的效果需要在实践中验证 + +## 安装方法 + +```bash +clawhub install concentrate-forces +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/concentrate-forces/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/concentrate-forces/SKILL.md new file mode 100644 index 0000000..ab8cc68 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/concentrate-forces/SKILL.md @@ -0,0 +1,56 @@ +--- +name: concentrate-forces +description: "当多个任务争夺注意力,需要优先处理重要任务时调用" +tools: [] +--- + +# 集中兵力 + +## 触发条件 +当多个任务争夺注意力,需要优先处理重要任务时触发。 + +## 执行步骤 +1. **任务分析**:分析所有待处理的任务 +2. **优先级排序**:根据重要性和紧急性对任务进行排序 +3. **资源集中**:将资源集中到最重要的任务上 +4. **各个击破**:逐个解决优先级高的任务 +5. **动态调整**:根据情况动态调整优先级和资源分配 + +## 核心原则 +伤其十指不如断其一指。不打无准备之仗。 + +## 不适用场景 +- 只有一个任务 +- 所有任务都同等重要 +- 任务之间相互依赖,无法单独处理 +- 时间充足,不需要优先级排序 + +## 集中兵力的应用 +- **任务管理**:管理多个并发任务 +- **项目规划**:规划项目的优先级 +- **资源分配**:合理分配有限的资源 +- **问题解决**:集中精力解决关键问题 + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| 平均分配资源 | 集中资源到最重要的任务 | +| 同时处理多个任务 | 一次只处理一个重要任务 | +| 忽视任务的重要性 | 认真评估任务的重要性和紧急性 | +| 缺乏准备 | 充分准备后再行动 | +| 不根据情况调整 | 动态调整优先级和资源分配 | + +## 操作规程 +当本 skill 被触发时,执行以下步骤: +1. **任务清单**:列出所有待处理的任务 +2. **评估排序**:评估每个任务的重要性和紧急性,进行排序 +3. **资源规划**:规划所需的资源,确保重要任务得到充分支持 +4. **执行计划**:制定详细的执行计划,明确每个任务的时间和资源需求 +5. **集中执行**:集中精力执行最重要的任务,确保完成质量 +6. **评估调整**:定期评估任务进展,根据情况调整优先级和资源分配 + +## 与其他 skill 的关系 +- **矛盾分析法**:集中兵力需要识别主要矛盾 +- **持久战略**:在持久战略中,需要在关键阶段集中兵力 +- **统筹兼顾**:集中兵力需要在全局范围内统筹兼顾 +- **实践认识论**:集中兵力的效果需要在实践中验证 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/concentrate-forces/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/concentrate-forces/clawhub.json new file mode 100644 index 0000000..15a8d73 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/concentrate-forces/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "concentrate-forces", + "version": "1.0.0", + "displayName": "集中兵力", + "description": "当多个任务争夺注意力,需要优先处理重要任务时调用", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "集中兵力"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/contradiction-analysis/README.md b/workspace-backend/skills/qiushi-openclaw-skill/contradiction-analysis/README.md new file mode 100644 index 0000000..1f3a9f7 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/contradiction-analysis/README.md @@ -0,0 +1,73 @@ +# 矛盾分析法 + +## 技能介绍 + +矛盾分析法是求是 OpenClaw Skills 系列中的核心技能,用于分析复杂问题,识别矛盾,抓住主要矛盾,区分矛盾性质,从而找到解决问题的方法。 + +## 核心功能 + +- **矛盾识别**:识别问题中的所有矛盾 +- **主要矛盾判定**:找出规定或影响其他矛盾的主要矛盾 +- **矛盾性质分析**:区分对抗性矛盾和非对抗性矛盾 +- **解决方案选择**:根据矛盾性质选择合适的解决方法 +- **矛盾转化监控**:持续关注矛盾的变化和转化 + +## 触发条件 + +当问题复杂、存在多个冲突因素、优先级不清,或你不知道应该先解决什么时触发。 + +## 执行步骤 + +1. **识别所有矛盾**:列出当前情境中所有对立的、互相制约的因素 +2. **判定主要矛盾**:找出那个规定或影响着其他矛盾的主要矛盾 +3. **分析矛盾的主要方面**:判断哪一方面占支配地位 +4. **区分矛盾性质**:判断矛盾是对抗性的还是非对抗性的 +5. **选择解决方法**:根据矛盾性质,选择对应方法 +6. **监控矛盾转化**:持续关注矛盾的变化 + +## 矛盾性质判断 + +**对抗性矛盾**(根本利益冲突): +- 需要明确立场,果断处理 +- 不能调和,只能选择一方 + +**非对抗性矛盾**(共同利益下的分歧): +- 使用"团结——批评——团结"的方法 +- 从团结的愿望出发,通过讨论和批评解决分歧,达到新的团结 + +## 常见错误 + +| 错误 | 正确做法 | +|------|---------| +| 不做矛盾分析就动手 | 先分析,后行动 | +| 搞一刀切 | 每个矛盾都有其特殊性,不能套用模板 | +| 抓不住主要矛盾 | 全局着眼,抓住牛鼻子 | +| 忽视矛盾转化 | 持续监控,动态调整 | +| 把非对抗性矛盾当对抗性处理 | 先判断性质,再选择方法 | + +## 操作规程 + +当本 skill 被触发时,执行以下具体步骤并输出结构化的矛盾分析表: +1. **列矛盾清单**:用 bullet list 列出当前情境中所有可识别的对立面,格式为 `[A] vs [B]` +2. **判定主要矛盾**:在列表中标记一个矛盾为 `⭐ 主要矛盾`,并用一句话说明理由 +3. **判断性质**:对主要矛盾标注:`对抗性`或 `非对抗性` +4. **选择应对方法**:根据性质,选择对应方法,并明确写出"接下来我将……" +5. **设置监控提示**:在分析末尾加一行:"⚠️ 需监控:[次要矛盾X] 是否上升为主要矛盾" + +## 与其他 skill 的关系 + +- **实践认识论**:矛盾分析得出的结论需要在实践中验证 +- **调查研究**:识别矛盾的前提是充分的调查研究 +- **集中兵力**:抓住主要矛盾后,集中力量解决它 +- **统筹兼顾**:当多对矛盾都需要处理时,需要统筹兼顾 +- **批评与自我批评**:矛盾分析也适用于审视自己的工作 + +## 安装方法 + +```bash +clawhub install contradiction-analysis +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/contradiction-analysis/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/contradiction-analysis/SKILL.md new file mode 100644 index 0000000..d48c586 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/contradiction-analysis/SKILL.md @@ -0,0 +1,60 @@ +--- +name: contradiction-analysis +description: "当问题复杂、存在多个冲突因素、优先级不清,或你不知道应该先解决什么时调用" +tools: [] +--- + +# 矛盾分析法 + +## 触发条件 +当问题复杂、存在多个冲突因素、优先级不清,或你不知道应该先解决什么时触发。 + +## 执行步骤 +1. 识别所有矛盾:列出当前情境中所有对立的、互相制约的因素 +2. 判定主要矛盾:找出那个规定或影响着其他矛盾的主要矛盾 +3. 分析矛盾的主要方面:判断哪一方面占支配地位 +4. 区分矛盾性质:判断矛盾是对抗性的还是非对抗性的 +5. 选择解决方法:根据矛盾性质,选择对应方法 +6. 监控矛盾转化:持续关注矛盾的变化 + +## 核心原则 +一切事物都包含矛盾,分析任何问题的方法就是找到其中的矛盾,区分主要矛盾和次要矛盾,然后集中力量解决主要矛盾。 + +## 不适用场景 +- 任务是直接执行性的(如"帮我把这段代码格式化") +- 用户已经明确指定了解决方案,只需要实现 +- 问题只有一个维度,不存在对立面 +- 时间紧急且问题属于已知模式 + +## 矛盾性质判断 +**对抗性矛盾**(根本利益冲突): +- 需要明确立场,果断处理 +- 不能调和,只能选择一方 + +**非对抗性矛盾**(共同利益下的分歧): +- 使用"团结——批评——团结"的方法 +- 从团结的愿望出发,通过讨论和批评解决分歧,达到新的团结 + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| 不做矛盾分析就动手 | 先分析,后行动 | +| 搞一刀切 | 每个矛盾都有其特殊性,不能套用模板 | +| 抓不住主要矛盾 | 全局着眼,抓住牛鼻子 | +| 忽视矛盾转化 | 持续监控,动态调整 | +| 把非对抗性矛盾当对抗性处理 | 先判断性质,再选择方法 | + +## 操作规程 +当本 skill 被触发时,执行以下具体步骤并输出结构化的矛盾分析表: +1. **列矛盾清单**:用 bullet list 列出当前情境中所有可识别的对立面,格式为 `[A] vs [B]` +2. **判定主要矛盾**:在列表中标记一个矛盾为 `⭐ 主要矛盾`,并用一句话说明理由 +3. **判断性质**:对主要矛盾标注:`对抗性`或 `非对抗性` +4. **选择应对方法**:根据性质,选择对应方法,并明确写出"接下来我将……" +5. **设置监控提示**:在分析末尾加一行:"⚠️ 需监控:[次要矛盾X] 是否上升为主要矛盾" + +## 与其他 skill 的关系 +- **实践认识论**:矛盾分析得出的结论需要在实践中验证 +- **调查研究**:识别矛盾的前提是充分的调查研究 +- **集中兵力**:抓住主要矛盾后,集中力量解决它 +- **统筹兼顾**:当多对矛盾都需要处理时,需要统筹兼顾 +- **批评与自我批评**:矛盾分析也适用于审视自己的工作 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/contradiction-analysis/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/contradiction-analysis/clawhub.json new file mode 100644 index 0000000..df459ff --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/contradiction-analysis/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "contradiction-analysis", + "version": "1.0.0", + "displayName": "矛盾分析法", + "description": "当问题复杂、存在多个冲突因素、优先级不清,或你不知道应该先解决什么时调用", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "矛盾分析"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/criticism-self-criticism/README.md b/workspace-backend/skills/qiushi-openclaw-skill/criticism-self-criticism/README.md new file mode 100644 index 0000000..4c2e6a7 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/criticism-self-criticism/README.md @@ -0,0 +1,82 @@ +# 批评与自我批评 + +## 技能介绍 + +批评与自我批评是求是 OpenClaw Skills 系列中的核心技能,基于毛泽东的《论联合政府》,强调"惩前毖后,治病救人",用于完成工作后审视质量,或改进自身表现。 + +## 核心功能 + +- **自我检查**:对自己的工作进行全面检查 +- **自我批评**:诚恳地找出自己的不足和错误 +- **接受批评**:虚心接受他人的批评和建议 +- **改进计划**:制定具体的改进措施 + +## 触发条件 + +当完成工作后需要审视质量,或需要改进自身表现时触发。 + +## 执行步骤 + +1. **自我检查**:对自己的工作进行全面检查 +2. **自我批评**:诚恳地找出自己的不足和错误 +3. **接受批评**:虚心接受他人的批评和建议 +4. **分析原因**:分析产生问题的原因 +5. **制定改进计划**:制定具体的改进措施 +6. **落实改进**:认真落实改进计划 + +## 核心原则 + +惩前毖后,治病救人。房子是应该经常打扫的。 + +## 批评与自我批评的方法 + +- **实事求是**:基于事实进行批评和自我批评 +- **与人为善**:以帮助他人为目的,不搞人身攻击 +- **治病救人**:通过批评帮助他人改进,而不是惩罚 +- **知无不言**:坦诚地表达自己的意见和看法 +- **言无不尽**:充分表达自己的想法和建议 + +## 不适用场景 + +- 工作尚未完成 +- 问题已经解决 +- 不需要改进的简单任务 +- 纯粹的理论探讨 + +## 常见错误 + +| 错误 | 正确做法 | +|------|---------| +| 敷衍了事 | 认真对待批评和自我批评 | +| 只批评别人不自我批评 | 首先进行自我批评 | +| 搞人身攻击 | 针对问题,不针对个人 | +| 不接受批评 | 虚心接受他人的批评和建议 | +| 批评后不改进 | 认真落实改进措施 | + +## 操作规程 + +当本 skill 被触发时,执行以下步骤: +1. **准备阶段**:回顾工作内容,收集相关信息 +2. **自我检查**:对工作进行全面检查,找出问题和不足 +3. **自我批评**:诚恳地进行自我批评,分析问题原因 +4. **征求意见**:主动征求他人的批评和建议 +5. **分析总结**:分析批评意见,总结经验教训 +6. **改进计划**:制定具体的改进计划和措施 +7. **落实改进**:认真落实改进计划,定期检查改进效果 + +## 与其他 skill 的关系 + +- **实践认识论**:批评与自我批评是实践后的重要环节 +- **调查研究**:批评与自我批评可以发现调查研究中的问题 +- **群众路线**:批评与自我批评需要群众的参与和监督 +- **矛盾分析法**:批评与自我批评可以帮助识别和解决内部矛盾 + +## 安装方法 + +```bash +clawhub install criticism-self-criticism +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/criticism-self-criticism/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/criticism-self-criticism/SKILL.md new file mode 100644 index 0000000..74f1efe --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/criticism-self-criticism/SKILL.md @@ -0,0 +1,59 @@ +--- +name: criticism-self-criticism +description: "当完成工作后需要审视质量,或需要改进自身表现时调用" +tools: [] +--- + +# 批评与自我批评 + +## 触发条件 +当完成工作后需要审视质量,或需要改进自身表现时触发。 + +## 执行步骤 +1. **自我检查**:对自己的工作进行全面检查 +2. **自我批评**:诚恳地找出自己的不足和错误 +3. **接受批评**:虚心接受他人的批评和建议 +4. **分析原因**:分析产生问题的原因 +5. **制定改进计划**:制定具体的改进措施 +6. **落实改进**:认真落实改进计划 + +## 核心原则 +惩前毖后,治病救人。房子是应该经常打扫的。 + +## 不适用场景 +- 工作尚未完成 +- 问题已经解决 +- 不需要改进的简单任务 +- 纯粹的理论探讨 + +## 批评与自我批评的方法 +- **实事求是**:基于事实进行批评和自我批评 +- **与人为善**:以帮助他人为目的,不搞人身攻击 +- **治病救人**:通过批评帮助他人改进,而不是惩罚 +- **知无不言**:坦诚地表达自己的意见和看法 +- **言无不尽**:充分表达自己的想法和建议 + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| 敷衍了事 | 认真对待批评和自我批评 | +| 只批评别人不自我批评 | 首先进行自我批评 | +| 搞人身攻击 | 针对问题,不针对个人 | +| 不接受批评 | 虚心接受他人的批评和建议 | +| 批评后不改进 | 认真落实改进措施 | + +## 操作规程 +当本 skill 被触发时,执行以下步骤: +1. **准备阶段**:回顾工作内容,收集相关信息 +2. **自我检查**:对工作进行全面检查,找出问题和不足 +3. **自我批评**:诚恳地进行自我批评,分析问题原因 +4. **征求意见**:主动征求他人的批评和建议 +5. **分析总结**:分析批评意见,总结经验教训 +6. **改进计划**:制定具体的改进计划和措施 +7. **落实改进**:认真落实改进计划,定期检查改进效果 + +## 与其他 skill 的关系 +- **实践认识论**:批评与自我批评是实践后的重要环节 +- **调查研究**:批评与自我批评可以发现调查研究中的问题 +- **群众路线**:批评与自我批评需要群众的参与和监督 +- **矛盾分析法**:批评与自我批评可以帮助识别和解决内部矛盾 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/criticism-self-criticism/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/criticism-self-criticism/clawhub.json new file mode 100644 index 0000000..a6b6e76 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/criticism-self-criticism/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "criticism-self-criticism", + "version": "1.0.0", + "displayName": "批评与自我批评", + "description": "当完成工作后需要审视质量,或需要改进自身表现时调用", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "批评与自我批评"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/investigation-first/README.md b/workspace-backend/skills/qiushi-openclaw-skill/investigation-first/README.md new file mode 100644 index 0000000..8dc6d9b --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/investigation-first/README.md @@ -0,0 +1,81 @@ +# 调查研究 + +## 技能介绍 + +调查研究是求是 OpenClaw Skills 系列中的核心技能,基于毛泽东的《反对本本主义》,强调"没有调查就没有发言权",用于在做决策前收集充分的信息,深入了解问题背景。 + +## 核心功能 + +- **信息收集**:通过各种渠道收集相关信息 +- **信息分析**:对收集到的信息进行整理和分析 +- **结论形成**:基于分析结果形成调查结论 +- **建议提出**:根据结论提出具体的建议 + +## 触发条件 + +当需要做决策但信息不足,或需要深入了解问题背景时触发。 + +## 执行步骤 + +1. **明确调查目标**:确定需要了解的问题和信息 +2. **制定调查计划**:设计调查方法、步骤和时间安排 +3. **收集信息**:通过各种渠道收集相关信息 +4. **分析信息**:对收集到的信息进行整理和分析 +5. **形成结论**:基于分析结果形成调查结论 +6. **提出建议**:根据结论提出具体的建议 + +## 核心原则 + +没有调查就没有发言权。调查就像"十月怀胎",解决问题就像"一朝分娩"。 + +## 调查方法 + +- **观察法**:直接观察相关现象和行为 +- **访谈法**:与相关人员进行交流和访谈 +- **文献法**:查阅相关文献和资料 +- **实验法**:通过实验验证假设 +- **问卷调查法**:通过问卷收集大量信息 + +## 不适用场景 + +- 已经有足够的信息做出决策 +- 时间紧急且问题属于已知模式 +- 纯粹的理论探讨,不需要实际信息 +- 问题本身不涉及具体事实 + +## 常见错误 + +| 错误 | 正确做法 | +|------|---------| +| 没有调查就下结论 | 先调查,后结论 | +| 调查不全面 | 从多个角度收集信息 | +| 调查不深入 | 深入分析问题的本质 | +| 只收集有利信息 | 客观收集各种信息,包括不利信息 | +| 调查后不分析 | 对收集到的信息进行系统分析 | + +## 操作规程 + +当本 skill 被触发时,执行以下步骤: +1. **明确问题**:清楚定义需要调查的问题 +2. **确定范围**:确定调查的范围和边界 +3. **选择方法**:根据问题特点选择合适的调查方法 +4. **实施调查**:按照计划进行调查,收集信息 +5. **分析数据**:对收集到的数据进行整理和分析 +6. **形成报告**:撰写调查报告,包括发现和建议 + +## 与其他 skill 的关系 + +- **矛盾分析法**:调查研究是识别矛盾的前提 +- **实践认识论**:调查研究是实践的重要组成部分 +- **群众路线**:调查研究需要深入群众,了解实际情况 +- **批评与自我批评**:调查研究可以发现自身存在的问题 + +## 安装方法 + +```bash +clawhub install investigation-first +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/investigation-first/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/investigation-first/SKILL.md new file mode 100644 index 0000000..a092f99 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/investigation-first/SKILL.md @@ -0,0 +1,58 @@ +--- +name: investigation-first +description: "当需要做决策但信息不足,或需要深入了解问题背景时调用" +tools: [] +--- + +# 调查研究 + +## 触发条件 +当需要做决策但信息不足,或需要深入了解问题背景时触发。 + +## 执行步骤 +1. **明确调查目标**:确定需要了解的问题和信息 +2. **制定调查计划**:设计调查方法、步骤和时间安排 +3. **收集信息**:通过各种渠道收集相关信息 +4. **分析信息**:对收集到的信息进行整理和分析 +5. **形成结论**:基于分析结果形成调查结论 +6. **提出建议**:根据结论提出具体的建议 + +## 核心原则 +没有调查就没有发言权。调查就像"十月怀胎",解决问题就像"一朝分娩"。 + +## 不适用场景 +- 已经有足够的信息做出决策 +- 时间紧急且问题属于已知模式 +- 纯粹的理论探讨,不需要实际信息 +- 问题本身不涉及具体事实 + +## 调查方法 +- **观察法**:直接观察相关现象和行为 +- **访谈法**:与相关人员进行交流和访谈 +- **文献法**:查阅相关文献和资料 +- **实验法**:通过实验验证假设 +- **问卷调查法**:通过问卷收集大量信息 + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| 没有调查就下结论 | 先调查,后结论 | +| 调查不全面 | 从多个角度收集信息 | +| 调查不深入 | 深入分析问题的本质 | +| 只收集有利信息 | 客观收集各种信息,包括不利信息 | +| 调查后不分析 | 对收集到的信息进行系统分析 | + +## 操作规程 +当本 skill 被触发时,执行以下步骤: +1. **明确问题**:清楚定义需要调查的问题 +2. **确定范围**:确定调查的范围和边界 +3. **选择方法**:根据问题特点选择合适的调查方法 +4. **实施调查**:按照计划进行调查,收集信息 +5. **分析数据**:对收集到的数据进行整理和分析 +6. **形成报告**:撰写调查报告,包括发现和建议 + +## 与其他 skill 的关系 +- **矛盾分析法**:调查研究是识别矛盾的前提 +- **实践认识论**:调查研究是实践的重要组成部分 +- **群众路线**:调查研究需要深入群众,了解实际情况 +- **批评与自我批评**:调查研究可以发现自身存在的问题 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/investigation-first/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/investigation-first/clawhub.json new file mode 100644 index 0000000..37003f7 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/investigation-first/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "investigation-first", + "version": "1.0.0", + "displayName": "调查研究", + "description": "当需要做决策但信息不足,或需要深入了解问题背景时调用", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "调查研究"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/mass-line/README.md b/workspace-backend/skills/qiushi-openclaw-skill/mass-line/README.md new file mode 100644 index 0000000..723ae47 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/mass-line/README.md @@ -0,0 +1,79 @@ +# 群众路线 + +## 技能介绍 + +群众路线是求是 OpenClaw Skills 系列中的核心技能,基于毛泽东的《关于领导方法的若干问题》,强调"从群众中来,到群众中去",用于收集多方意见和整合多源信息。 + +## 核心功能 + +- **意见收集**:收集群众的意见和建议 +- **意见分析**:对收集到的意见进行整理和分析 +- **意见反馈**:将整理后的意见反馈给群众 +- **方案优化**:根据群众反馈优化方案 + +## 触发条件 + +当需要收集多方意见或整合多源信息时触发。 + +## 执行步骤 + +1. **从群众中来**:收集群众的意见和建议 +2. **集中起来**:对收集到的意见进行整理和分析 +3. **到群众中去**:将整理后的意见反馈给群众 +4. **坚持下去**:根据群众的反馈进一步调整和完善 + +## 核心原则 + +从群众中来,到群众中去。收集→系统化→返回→验证→再收集。 + +## 不适用场景 + +- 问题只涉及少数专业人士的意见 +- 时间紧急且需要快速决策 +- 问题本身不需要多方意见 +- 已经有明确的解决方案 + +## 群众路线的应用 + +- **决策参考**:收集群众意见作为决策的参考 +- **方案优化**:根据群众反馈优化方案 +- **问题解决**:依靠群众的智慧解决问题 +- **关系维护**:通过群众路线维护良好的关系 + +## 常见错误 + +| 错误 | 正确做法 | +|------|---------| +| 忽视群众意见 | 认真倾听群众的意见和建议 | +| 只收集不反馈 | 及时将处理结果反馈给群众 | +| 形式主义 | 真正深入群众,了解实际情况 | +| 选择性收集 | 客观收集各种意见,包括批评意见 | +| 不重视反馈 | 认真对待群众的反馈,及时调整 | + +## 操作规程 + +当本 skill 被触发时,执行以下步骤: +1. **确定范围**:确定需要收集意见的范围和对象 +2. **设计方法**:设计收集意见的方法和工具 +3. **收集意见**:通过各种渠道收集群众的意见 +4. **整理分析**:对收集到的意见进行整理和分析 +5. **形成方案**:基于分析结果形成初步方案 +6. **反馈验证**:将方案反馈给群众,征求意见 +7. **调整完善**:根据反馈调整和完善方案 + +## 与其他 skill 的关系 + +- **调查研究**:群众路线是调查研究的重要方法 +- **实践认识论**:群众的实践是认识的重要来源 +- **批评与自我批评**:群众的批评是自我批评的重要参考 +- **统筹兼顾**:群众路线需要统筹兼顾各方利益 + +## 安装方法 + +```bash +clawhub install mass-line +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/mass-line/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/mass-line/SKILL.md new file mode 100644 index 0000000..0cc13c4 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/mass-line/SKILL.md @@ -0,0 +1,56 @@ +--- +name: mass-line +description: "当需要收集多方意见或整合多源信息时调用" +tools: [] +--- + +# 群众路线 + +## 触发条件 +当需要收集多方意见或整合多源信息时触发。 + +## 执行步骤 +1. **从群众中来**:收集群众的意见和建议 +2. **集中起来**:对收集到的意见进行整理和分析 +3. **到群众中去**:将整理后的意见反馈给群众 +4. **坚持下去**:根据群众的反馈进一步调整和完善 + +## 核心原则 +从群众中来,到群众中去。收集→系统化→返回→验证→再收集。 + +## 不适用场景 +- 问题只涉及少数专业人士的意见 +- 时间紧急且需要快速决策 +- 问题本身不需要多方意见 +- 已经有明确的解决方案 + +## 群众路线的应用 +- **决策参考**:收集群众意见作为决策的参考 +- **方案优化**:根据群众反馈优化方案 +- **问题解决**:依靠群众的智慧解决问题 +- **关系维护**:通过群众路线维护良好的关系 + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| 忽视群众意见 | 认真倾听群众的意见和建议 | +| 只收集不反馈 | 及时将处理结果反馈给群众 | +| 形式主义 | 真正深入群众,了解实际情况 | +| 选择性收集 | 客观收集各种意见,包括批评意见 | +| 不重视反馈 | 认真对待群众的反馈,及时调整 | + +## 操作规程 +当本 skill 被触发时,执行以下步骤: +1. **确定范围**:确定需要收集意见的范围和对象 +2. **设计方法**:设计收集意见的方法和工具 +3. **收集意见**:通过各种渠道收集群众的意见 +4. **整理分析**:对收集到的意见进行整理和分析 +5. **形成方案**:基于分析结果形成初步方案 +6. **反馈验证**:将方案反馈给群众,征求意见 +7. **调整完善**:根据反馈调整和完善方案 + +## 与其他 skill 的关系 +- **调查研究**:群众路线是调查研究的重要方法 +- **实践认识论**:群众的实践是认识的重要来源 +- **批评与自我批评**:群众的批评是自我批评的重要参考 +- **统筹兼顾**:群众路线需要统筹兼顾各方利益 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/mass-line/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/mass-line/clawhub.json new file mode 100644 index 0000000..9e2b1a7 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/mass-line/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "mass-line", + "version": "1.0.0", + "displayName": "群众路线", + "description": "当需要收集多方意见或整合多源信息时调用", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "群众路线"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/overall-planning/README.md b/workspace-backend/skills/qiushi-openclaw-skill/overall-planning/README.md new file mode 100644 index 0000000..c38fd62 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/overall-planning/README.md @@ -0,0 +1,84 @@ +# 统筹兼顾 + +## 技能介绍 + +统筹兼顾是求是 OpenClaw Skills 系列中的核心技能,基于毛泽东的《论十大关系》,强调"调动一切积极因素",用于当多个目标需要平衡时统筹兼顾各方面因素。 + +## 核心功能 + +- **目标分析**:分析所有需要实现的目标 +- **资源评估**:评估可用的资源和约束条件 +- **优先级确定**:确定各目标的优先级 +- **方案制定**:制定统筹兼顾的方案 +- **资源分配**:合理分配资源,确保各目标的实现 + +## 触发条件 + +当多个目标需要平衡,需要统筹兼顾时触发。 + +## 执行步骤 + +1. **目标分析**:分析所有需要实现的目标 +2. **资源评估**:评估可用的资源和约束条件 +3. **优先级确定**:确定各目标的优先级 +4. **方案制定**:制定统筹兼顾的方案 +5. **资源分配**:合理分配资源,确保各目标的实现 +6. **执行监控**:监控执行情况,及时调整方案 +7. **平衡优化**:不断优化,确保各目标的平衡实现 + +## 核心原则 + +调动一切积极因素。拒绝片面性,寻找动态平衡。 + +## 不适用场景 + +- 只有一个目标 +- 目标之间没有冲突 +- 资源充足,不需要平衡 +- 时间紧急,不需要统筹规划 + +## 统筹兼顾的应用 + +- **项目管理**:管理多个项目目标 +- **资源分配**:分配有限的资源 +- **决策制定**:制定兼顾各方利益的决策 +- **战略规划**:规划长期战略目标 + +## 常见错误 + +| 错误 | 正确做法 | +|------|---------| +| 片面追求单一目标 | 兼顾所有重要目标 | +| 忽视资源约束 | 考虑资源约束,合理分配 | +| 缺乏整体规划 | 制定整体规划,协调各目标 | +| 不考虑长期影响 | 考虑长期影响,保持可持续发展 | +| 不根据情况调整 | 动态调整,保持平衡 | + +## 操作规程 + +当本 skill 被触发时,执行以下步骤: +1. **目标清单**:列出所有需要实现的目标 +2. **目标分析**:分析各目标的重要性、紧迫性和相互关系 +3. **资源评估**:评估可用的资源和约束条件 +4. **优先级排序**:根据分析结果,确定各目标的优先级 +5. **方案制定**:制定统筹兼顾的方案,确保各目标的平衡实现 +6. **资源分配**:根据优先级和需求,合理分配资源 +7. **执行实施**:按照方案执行,监控执行情况 +8. **调整优化**:根据执行情况,及时调整方案,确保各目标的平衡实现 + +## 与其他 skill 的关系 + +- **矛盾分析法**:统筹兼顾需要分析和平衡各种矛盾 +- **集中兵力**:在统筹兼顾的基础上,需要集中兵力于关键目标 +- **持久战略**:统筹兼顾需要考虑长期战略目标 +- **群众路线**:统筹兼顾需要考虑各方利益和意见 + +## 安装方法 + +```bash +clawhub install overall-planning +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/overall-planning/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/overall-planning/SKILL.md new file mode 100644 index 0000000..98ff09d --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/overall-planning/SKILL.md @@ -0,0 +1,60 @@ +--- +name: overall-planning +description: "当多个目标需要平衡,需要统筹兼顾时调用" +tools: [] +--- + +# 统筹兼顾 + +## 触发条件 +当多个目标需要平衡,需要统筹兼顾时触发。 + +## 执行步骤 +1. **目标分析**:分析所有需要实现的目标 +2. **资源评估**:评估可用的资源和约束条件 +3. **优先级确定**:确定各目标的优先级 +4. **方案制定**:制定统筹兼顾的方案 +5. **资源分配**:合理分配资源,确保各目标的实现 +6. **执行监控**:监控执行情况,及时调整方案 +7. **平衡优化**:不断优化,确保各目标的平衡实现 + +## 核心原则 +调动一切积极因素。拒绝片面性,寻找动态平衡。 + +## 不适用场景 +- 只有一个目标 +- 目标之间没有冲突 +- 资源充足,不需要平衡 +- 时间紧急,不需要统筹规划 + +## 统筹兼顾的应用 +- **项目管理**:管理多个项目目标 +- **资源分配**:分配有限的资源 +- **决策制定**:制定兼顾各方利益的决策 +- **战略规划**:规划长期战略目标 + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| 片面追求单一目标 | 兼顾所有重要目标 | +| 忽视资源约束 | 考虑资源约束,合理分配 | +| 缺乏整体规划 | 制定整体规划,协调各目标 | +| 不考虑长期影响 | 考虑长期影响,保持可持续发展 | +| 不根据情况调整 | 动态调整,保持平衡 | + +## 操作规程 +当本 skill 被触发时,执行以下步骤: +1. **目标清单**:列出所有需要实现的目标 +2. **目标分析**:分析各目标的重要性、紧迫性和相互关系 +3. **资源评估**:评估可用的资源和约束条件 +4. **优先级排序**:根据分析结果,确定各目标的优先级 +5. **方案制定**:制定统筹兼顾的方案,确保各目标的平衡实现 +6. **资源分配**:根据优先级和需求,合理分配资源 +7. **执行实施**:按照方案执行,监控执行情况 +8. **调整优化**:根据执行情况,及时调整方案,确保各目标的平衡实现 + +## 与其他 skill 的关系 +- **矛盾分析法**:统筹兼顾需要分析和平衡各种矛盾 +- **集中兵力**:在统筹兼顾的基础上,需要集中兵力于关键目标 +- **持久战略**:统筹兼顾需要考虑长期战略目标 +- **群众路线**:统筹兼顾需要考虑各方利益和意见 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/overall-planning/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/overall-planning/clawhub.json new file mode 100644 index 0000000..30ad913 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/overall-planning/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "overall-planning", + "version": "1.0.0", + "displayName": "统筹兼顾", + "description": "当多个目标需要平衡,需要统筹兼顾时调用", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "统筹兼顾"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/practice-cognition/README.md b/workspace-backend/skills/qiushi-openclaw-skill/practice-cognition/README.md new file mode 100644 index 0000000..d0a9f28 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/practice-cognition/README.md @@ -0,0 +1,72 @@ +# 实践认识论 + +## 技能介绍 + +实践认识论是求是 OpenClaw Skills 系列中的核心技能,基于毛泽东的《实践论》,强调实践→认识→再实践→再认识的螺旋上升过程,用于验证方案、迭代改进和从实践中学习。 + +## 核心功能 + +- **方案验证**:通过实践验证方案的可行性 +- **迭代改进**:根据实践结果不断调整和优化方案 +- **经验总结**:从成功和失败中提炼出可复用的经验 +- **规律发现**:通过多次实践发现事物的内在规律 + +## 触发条件 + +当需要验证方案、迭代改进、从实践中学习时触发。 + +## 执行步骤 + +1. **实践**:制定并执行具体方案 +2. **认识**:分析实践结果,总结经验教训 +3. **再实践**:根据认识调整方案,再次执行 +4. **再认识**:继续总结,形成更深刻的认识 +5. **循环往复**:直到问题解决或形成稳定的方法论 + +## 核心原则 + +实践→认识→再实践→再认识,螺旋上升。实践是检验真理的唯一标准。 + +## 不适用场景 + +- 纯粹的理论探讨,不需要实际验证 +- 已经有明确且经过验证的解决方案 +- 时间或资源不允许进行实践验证 +- 问题本身不涉及实践操作 + +## 常见错误 + +| 错误 | 正确做法 | +|------|---------| +| 只实践不总结 | 每次实践后都要进行总结和反思 | +| 只理论不实践 | 将理论与实践相结合,用实践检验理论 | +| 一次实践就下结论 | 多次实践,综合分析结果 | +| 忽视实践中的细节 | 关注实践中的具体情况,细节决定成败 | +| 拒绝根据实践调整方案 | 保持开放心态,根据实践结果灵活调整 | + +## 操作规程 + +当本 skill 被触发时,执行以下步骤: +1. **明确目标**:清楚定义要验证的假设或要解决的问题 +2. **制定方案**:设计具体的实践步骤和评估标准 +3. **执行实践**:按照方案进行操作,记录过程和结果 +4. **分析结果**:客观分析实践结果,找出成功和失败的原因 +5. **调整方案**:根据分析结果调整方案,准备下一次实践 +6. **总结经验**:提炼出可复用的经验和方法论 + +## 与其他 skill 的关系 + +- **矛盾分析法**:实践认识论可以验证矛盾分析的结论 +- **调查研究**:实践是调查研究的延伸,也是验证调查结果的方法 +- **批评与自我批评**:实践中的失败和不足是批评与自我批评的重要内容 +- **持久战略**:长期复杂任务需要通过实践认识论不断调整策略 + +## 安装方法 + +```bash +clawhub install practice-cognition +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/practice-cognition/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/practice-cognition/SKILL.md new file mode 100644 index 0000000..4bca112 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/practice-cognition/SKILL.md @@ -0,0 +1,56 @@ +--- +name: practice-cognition +description: "当需要验证方案、迭代改进、从实践中学习时调用" +tools: [] +--- + +# 实践认识论 + +## 触发条件 +当需要验证方案、迭代改进、从实践中学习时触发。 + +## 执行步骤 +1. **实践**:制定并执行具体方案 +2. **认识**:分析实践结果,总结经验教训 +3. **再实践**:根据认识调整方案,再次执行 +4. **再认识**:继续总结,形成更深刻的认识 +5. **循环往复**:直到问题解决或形成稳定的方法论 + +## 核心原则 +实践→认识→再实践→再认识,螺旋上升。实践是检验真理的唯一标准。 + +## 不适用场景 +- 纯粹的理论探讨,不需要实际验证 +- 已经有明确且经过验证的解决方案 +- 时间或资源不允许进行实践验证 +- 问题本身不涉及实践操作 + +## 实践认识论的应用 +- **方案验证**:通过小规模实践验证方案的可行性 +- **迭代改进**:根据实践结果不断调整和优化方案 +- **经验总结**:从成功和失败中提炼出可复用的经验 +- **规律发现**:通过多次实践发现事物的内在规律 + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| 只实践不总结 | 每次实践后都要进行总结和反思 | +| 只理论不实践 | 将理论与实践相结合,用实践检验理论 | +| 一次实践就下结论 | 多次实践,综合分析结果 | +| 忽视实践中的细节 | 关注实践中的具体情况,细节决定成败 | +| 拒绝根据实践调整方案 | 保持开放心态,根据实践结果灵活调整 | + +## 操作规程 +当本 skill 被触发时,执行以下步骤: +1. **明确目标**:清楚定义要验证的假设或要解决的问题 +2. **制定方案**:设计具体的实践步骤和评估标准 +3. **执行实践**:按照方案进行操作,记录过程和结果 +4. **分析结果**:客观分析实践结果,找出成功和失败的原因 +5. **调整方案**:根据分析结果调整方案,准备下一次实践 +6. **总结经验**:提炼出可复用的经验和方法论 + +## 与其他 skill 的关系 +- **矛盾分析法**:实践认识论可以验证矛盾分析的结论 +- **调查研究**:实践是调查研究的延伸,也是验证调查结果的方法 +- **批评与自我批评**:实践中的失败和不足是批评与自我批评的重要内容 +- **持久战略**:长期复杂任务需要通过实践认识论不断调整策略 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/practice-cognition/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/practice-cognition/clawhub.json new file mode 100644 index 0000000..3ca67f7 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/practice-cognition/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "practice-cognition", + "version": "1.0.0", + "displayName": "实践认识论", + "description": "当需要验证方案、迭代改进、从实践中学习时调用", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "实践认识论"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/protracted-strategy/README.md b/workspace-backend/skills/qiushi-openclaw-skill/protracted-strategy/README.md new file mode 100644 index 0000000..1d19e17 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/protracted-strategy/README.md @@ -0,0 +1,84 @@ +# 持久战略 + +## 技能介绍 + +持久战略是求是 OpenClaw Skills 系列中的核心技能,基于毛泽东的《论持久战》,强调"战略上藐视,战术上重视",用于面对长期复杂任务时制定长期计划。 + +## 核心功能 + +- **战略分析**:分析任务的性质、特点和挑战 +- **阶段划分**:将长期任务划分为多个阶段 +- **计划制定**:为每个阶段制定具体的计划和目标 +- **资源分配**:合理分配资源,确保各阶段的顺利进行 +- **执行监控**:监控执行情况,及时调整计划 + +## 触发条件 + +当面对长期复杂任务,需要制定长期计划时触发。 + +## 执行步骤 + +1. **战略分析**:分析任务的性质、特点和挑战 +2. **阶段划分**:将长期任务划分为多个阶段 +3. **制定计划**:为每个阶段制定具体的计划和目标 +4. **资源分配**:合理分配资源,确保各阶段的顺利进行 +5. **执行监控**:监控执行情况,及时调整计划 +6. **阶段评估**:对每个阶段的成果进行评估 +7. **持续推进**:保持动力,持续推进任务的完成 + +## 核心原则 + +战略上藐视,战术上重视。不急于求成,也不畏难放弃。 + +## 不适用场景 + +- 短期简单任务 +- 已经有明确的解决方案 +- 时间紧急且需要快速完成的任务 +- 不需要长期规划的任务 + +## 持久战略的应用 + +- **长期项目**:制定长期项目的阶段性计划 +- **职业发展**:规划个人或组织的长期发展 +- **问题解决**:解决复杂的长期问题 +- **能力建设**:长期能力建设和培养 + +## 常见错误 + +| 错误 | 正确做法 | +|------|---------| +| 急于求成 | 制定合理的时间表,稳步推进 | +| 畏难放弃 | 保持信心,坚持到底 | +| 缺乏规划 | 制定详细的阶段计划 | +| 资源分配不当 | 合理分配资源,确保各阶段的需求 | +| 监控不力 | 定期监控执行情况,及时调整 | + +## 操作规程 + +当本 skill 被触发时,执行以下步骤: +1. **任务分析**:分析任务的性质、难度和时间要求 +2. **阶段划分**:将任务划分为多个合理的阶段 +3. **目标设定**:为每个阶段设定具体的目标和指标 +4. **计划制定**:制定每个阶段的详细计划和行动方案 +5. **资源规划**:规划所需的资源和支持 +6. **执行实施**:按照计划执行,定期检查进度 +7. **评估调整**:对每个阶段进行评估,根据情况调整计划 +8. **持续推进**:保持动力,直至任务完成 + +## 与其他 skill 的关系 + +- **矛盾分析法**:持久战略需要分析长期任务中的矛盾 +- **实践认识论**:持久战略需要通过实践不断调整 +- **集中兵力**:在持久战略中,需要在关键阶段集中兵力 +- **统筹兼顾**:持久战略需要统筹兼顾各方面的因素 + +## 安装方法 + +```bash +clawhub install protracted-strategy +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/protracted-strategy/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/protracted-strategy/SKILL.md new file mode 100644 index 0000000..49f2094 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/protracted-strategy/SKILL.md @@ -0,0 +1,60 @@ +--- +name: protracted-strategy +description: "当面对长期复杂任务,需要制定长期计划时调用" +tools: [] +--- + +# 持久战略 + +## 触发条件 +当面对长期复杂任务,需要制定长期计划时触发。 + +## 执行步骤 +1. **战略分析**:分析任务的性质、特点和挑战 +2. **阶段划分**:将长期任务划分为多个阶段 +3. **制定计划**:为每个阶段制定具体的计划和目标 +4. **资源分配**:合理分配资源,确保各阶段的顺利进行 +5. **执行监控**:监控执行情况,及时调整计划 +6. **阶段评估**:对每个阶段的成果进行评估 +7. **持续推进**:保持动力,持续推进任务的完成 + +## 核心原则 +战略上藐视,战术上重视。不急于求成,也不畏难放弃。 + +## 不适用场景 +- 短期简单任务 +- 已经有明确的解决方案 +- 时间紧急且需要快速完成的任务 +- 不需要长期规划的任务 + +## 持久战略的应用 +- **长期项目**:制定长期项目的阶段性计划 +- **职业发展**:规划个人或组织的长期发展 +- **问题解决**:解决复杂的长期问题 +- **能力建设**:长期能力建设和培养 + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| 急于求成 | 制定合理的时间表,稳步推进 | +| 畏难放弃 | 保持信心,坚持到底 | +| 缺乏规划 | 制定详细的阶段计划 | +| 资源分配不当 | 合理分配资源,确保各阶段的需求 | +| 监控不力 | 定期监控执行情况,及时调整 | + +## 操作规程 +当本 skill 被触发时,执行以下步骤: +1. **任务分析**:分析任务的性质、难度和时间要求 +2. **阶段划分**:将任务划分为多个合理的阶段 +3. **目标设定**:为每个阶段设定具体的目标和指标 +4. **计划制定**:制定每个阶段的详细计划和行动方案 +5. **资源规划**:规划所需的资源和支持 +6. **执行实施**:按照计划执行,定期检查进度 +7. **评估调整**:对每个阶段进行评估,根据情况调整计划 +8. **持续推进**:保持动力,直至任务完成 + +## 与其他 skill 的关系 +- **矛盾分析法**:持久战略需要分析长期任务中的矛盾 +- **实践认识论**:持久战略需要通过实践不断调整 +- **集中兵力**:在持久战略中,需要在关键阶段集中兵力 +- **统筹兼顾**:持久战略需要统筹兼顾各方面的因素 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/protracted-strategy/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/protracted-strategy/clawhub.json new file mode 100644 index 0000000..07abbe6 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/protracted-strategy/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "protracted-strategy", + "version": "1.0.0", + "displayName": "持久战略", + "description": "当面对长期复杂任务,需要制定长期计划时调用", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "持久战略"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/skill-card.md b/workspace-backend/skills/qiushi-openclaw-skill/skill-card.md new file mode 100644 index 0000000..3333281 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/skill-card.md @@ -0,0 +1,40 @@ +## Description:
+求是 OpenClaw Skills 是基于毛泽东思想方法论的 AI Agent 技能集合,按照 OpenClaw 技能格式进行改造,旨在为 AI 提供系统化的思考和行动框架。
+ +This skill is ready for commercial/non-commercial use.
+ +## Publisher:
+[skytodmoon](https://clawhub.ai/user/skytodmoon)
+ +### License/Terms of Use:
+MIT-0
+ + +## Use Case:
+Developers and agent users use this Chinese-language skill pack to guide planning, prioritization, investigation, review, and multi-skill workflow selection with a Mao-inspired methodology framework.
+ +### Deployment Geography for Use:
+Global
+ +## Known Risks and Mitigations:
+Risk: The broad arming-thought trigger can influence planning, prioritization, review, and skill routing at the start of new top-level conversations.
+Mitigation: Install only where this Chinese-language Mao-inspired reasoning framework is desired, and review the automatic trigger behavior before enabling the pack.
+ + +## Reference(s):
+- [ClawHub skill page](https://clawhub.ai/skytodmoon/qiushi-openclaw-skill)
+- [Publisher profile](https://clawhub.ai/user/skytodmoon)
+- [Referenced project homepage](https://github.com/skytodmoon/qiushi-skill)
+ + +## Skill Output:
+**Output Type(s):** [guidance, markdown, analysis]
+**Output Format:** [Markdown guidance with structured checklists, tables, and step-by-step reasoning prompts]
+**Output Parameters:** [1D]
+**Other Properties Related to Output:** [No tools, environment variables, credentials, file access, network access, or persistence requested by the artifact.]
+ +## Skill Version(s):
+1.0.0 (source: server release evidence and clawhub.json manifests)
+ +## Ethical Considerations:
+Users should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.
diff --git a/workspace-backend/skills/qiushi-openclaw-skill/spark-prairie-fire/README.md b/workspace-backend/skills/qiushi-openclaw-skill/spark-prairie-fire/README.md new file mode 100644 index 0000000..fd99535 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/spark-prairie-fire/README.md @@ -0,0 +1,79 @@ +# 星火燎原 + +## 技能介绍 + +星火燎原是求是 OpenClaw Skills 系列中的核心技能,基于毛泽东的《星星之火,可以燎原》,强调"建立根据地,不做流寇",用于从零开始、资源有限时从小处着手积累发展。 + +## 核心功能 + +- **根据地建立**:选择适合的起点,建立基础 +- **经验积累**:在小范围内积累经验和资源 +- **逐步扩展**:在基础稳固后,逐步扩展范围 +- **规模效应**:通过不断积累和扩展,形成规模效应 + +## 触发条件 + +当从零开始,资源有限,需要从小处着手积累发展时触发。 + +## 执行步骤 + +1. **建立根据地**:选择一个适合的起点,建立基础 +2. **积累经验**:在小范围内积累经验和资源 +3. **逐步扩展**:在基础稳固后,逐步扩展范围 +4. **形成规模**:通过不断积累和扩展,形成规模效应 +5. **持续发展**:保持发展势头,持续创新和改进 + +## 核心原则 + +建立根据地,不做流寇。从小处着手,积累发展。 + +## 不适用场景 + +- 资源充足,不需要从小处着手 +- 已经有成熟的基础和规模 +- 时间紧急,需要快速达到规模 +- 不需要长期发展的项目 + +## 星火燎原的应用 + +- **创业初期**:从零开始创业,建立基础 +- **新领域探索**:进入新领域,积累经验 +- **能力建设**:从小处着手,逐步提升能力 +- **市场开拓**:从局部市场开始,逐步扩展 + +## 常见错误 + +| 错误 | 正确做法 | +|------|---------| +| 急于求成 | 稳扎稳打,逐步发展 | +| 忽视基础 | 重视基础建设,确保稳固 | +| 盲目扩张 | 在基础稳固后再扩展 | +| 缺乏耐心 | 保持耐心,注重积累 | +| 不适应变化 | 灵活适应环境变化,及时调整策略 | + +## 操作规程 + +当本 skill 被触发时,执行以下步骤: +1. **起点选择**:选择一个适合的起点,考虑资源和环境因素 +2. **基础建设**:在起点建立稳固的基础,积累经验和资源 +3. **经验总结**:总结初期经验,优化方法和策略 +4. **逐步扩展**:在基础稳固后,逐步扩展范围和规模 +5. **规模效应**:通过扩展形成规模效应,提高效率和影响力 +6. **持续创新**:保持创新,适应变化,持续发展 + +## 与其他 skill 的关系 + +- **持久战略**:星火燎原需要长期的战略规划 +- **集中兵力**:在发展过程中,需要集中兵力于关键领域 +- **实践认识论**:通过实践不断积累经验和改进 +- **统筹兼顾**:在发展过程中需要统筹兼顾各方面的因素 + +## 安装方法 + +```bash +clawhub install spark-prairie-fire +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/spark-prairie-fire/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/spark-prairie-fire/SKILL.md new file mode 100644 index 0000000..4774f9a --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/spark-prairie-fire/SKILL.md @@ -0,0 +1,56 @@ +--- +name: spark-prairie-fire +description: "当从零开始,资源有限,需要从小处着手积累发展时调用" +tools: [] +--- + +# 星火燎原 + +## 触发条件 +当从零开始,资源有限,需要从小处着手积累发展时触发。 + +## 执行步骤 +1. **建立根据地**:选择一个适合的起点,建立基础 +2. **积累经验**:在小范围内积累经验和资源 +3. **逐步扩展**:在基础稳固后,逐步扩展范围 +4. **形成规模**:通过不断积累和扩展,形成规模效应 +5. **持续发展**:保持发展势头,持续创新和改进 + +## 核心原则 +建立根据地,不做流寇。从小处着手,积累发展。 + +## 不适用场景 +- 资源充足,不需要从小处着手 +- 已经有成熟的基础和规模 +- 时间紧急,需要快速达到规模 +- 不需要长期发展的项目 + +## 星火燎原的应用 +- **创业初期**:从零开始创业,建立基础 +- **新领域探索**:进入新领域,积累经验 +- **能力建设**:从小处着手,逐步提升能力 +- **市场开拓**:从局部市场开始,逐步扩展 + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| 急于求成 | 稳扎稳打,逐步发展 | +| 忽视基础 | 重视基础建设,确保稳固 | +| 盲目扩张 | 在基础稳固后再扩展 | +| 缺乏耐心 | 保持耐心,注重积累 | +| 不适应变化 | 灵活适应环境变化,及时调整策略 | + +## 操作规程 +当本 skill 被触发时,执行以下步骤: +1. **起点选择**:选择一个适合的起点,考虑资源和环境因素 +2. **基础建设**:在起点建立稳固的基础,积累经验和资源 +3. **经验总结**:总结初期经验,优化方法和策略 +4. **逐步扩展**:在基础稳固后,逐步扩展范围和规模 +5. **规模效应**:通过扩展形成规模效应,提高效率和影响力 +6. **持续创新**:保持创新,适应变化,持续发展 + +## 与其他 skill 的关系 +- **持久战略**:星火燎原需要长期的战略规划 +- **集中兵力**:在发展过程中,需要集中兵力于关键领域 +- **实践认识论**:通过实践不断积累经验和改进 +- **统筹兼顾**:在发展过程中需要统筹兼顾各方面的因素 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/spark-prairie-fire/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/spark-prairie-fire/clawhub.json new file mode 100644 index 0000000..7564fc0 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/spark-prairie-fire/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "spark-prairie-fire", + "version": "1.0.0", + "displayName": "星火燎原", + "description": "当从零开始,资源有限,需要从小处着手积累发展时调用", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "星火燎原"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/workflows/README.md b/workspace-backend/skills/qiushi-openclaw-skill/workflows/README.md new file mode 100644 index 0000000..4349440 --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/workflows/README.md @@ -0,0 +1,83 @@ +# 工作流组合 + +## 技能介绍 + +工作流组合是求是 OpenClaw Skills 系列中的核心技能,用于当一个任务明确需要多种方法串联时,组合使用多个技能形成完整的工作流程。 + +## 核心功能 + +- **任务分析**:分析任务的性质和需求 +- **技能选择**:选择适合的技能组合 +- **顺序确定**:确定技能的调用顺序 +- **流程设计**:设计详细的工作流程 +- **执行监控**:监控工作流程的执行情况 + +## 触发条件 + +当一个任务明确需要多种方法串联,需要组合使用多个技能时触发。 + +## 执行步骤 + +1. **任务分析**:分析任务的性质和需求 +2. **技能选择**:选择适合的技能组合 +3. **顺序确定**:确定技能的调用顺序 +4. **流程设计**:设计详细的工作流程 +5. **执行监控**:监控工作流程的执行情况 +6. **调整优化**:根据执行情况调整工作流程 + +## 核心原则 + +根据任务需求,灵活组合使用各种技能,形成完整的工作流程。 + +## 不适用场景 + +- 任务只需要单一技能 +- 任务流程简单,不需要复杂的技能组合 +- 时间紧急,不需要详细的工作流程设计 +- 已经有明确的工作流程 + +## 工作流组合的应用 + +- **复杂项目**:处理复杂的项目任务 +- **多阶段任务**:处理需要多个阶段的任务 +- **跨领域任务**:处理涉及多个领域的任务 +- **创新任务**:处理需要创新思维的任务 + +## 常见错误 + +| 错误 | 正确做法 | +|------|---------| +| 技能选择不当 | 根据任务需求选择合适的技能 | +| 顺序安排不合理 | 合理安排技能的调用顺序 | +| 流程设计过于复杂 | 设计简洁有效的工作流程 | +| 缺乏监控和调整 | 监控执行情况,及时调整流程 | +| 忽视技能间的协同 | 注重技能间的协同效应 | + +## 操作规程 + +当本 skill 被触发时,执行以下步骤: +1. **任务分析**:详细分析任务的性质、需求和挑战 +2. **技能评估**:评估各种技能的适用性和可行性 +3. **技能选择**:选择最适合的技能组合 +4. **顺序设计**:设计合理的技能调用顺序 +5. **流程制定**:制定详细的工作流程,包括每个阶段的目标和任务 +6. **资源规划**:规划所需的资源和支持 +7. **执行实施**:按照工作流程执行,监控执行情况 +8. **评估调整**:评估工作流程的效果,根据情况调整流程 + +## 与其他 skill 的关系 + +- **矛盾分析法**:工作流组合需要分析任务中的矛盾 +- **实践认识论**:工作流组合需要通过实践不断调整和优化 +- **集中兵力**:在工作流程中,需要在关键阶段集中兵力 +- **统筹兼顾**:工作流组合需要统筹兼顾各方面的因素 + +## 安装方法 + +```bash +clawhub install workflows +``` + +## 许可证 + +MIT License \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/workflows/SKILL.md b/workspace-backend/skills/qiushi-openclaw-skill/workflows/SKILL.md new file mode 100644 index 0000000..ce5aabe --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/workflows/SKILL.md @@ -0,0 +1,59 @@ +--- +name: workflows +description: "当一个任务明确需要多种方法串联,需要组合使用多个技能时调用" +tools: [] +--- + +# 工作流组合 + +## 触发条件 +当一个任务明确需要多种方法串联,需要组合使用多个技能时触发。 + +## 执行步骤 +1. **任务分析**:分析任务的性质和需求 +2. **技能选择**:选择适合的技能组合 +3. **顺序确定**:确定技能的调用顺序 +4. **流程设计**:设计详细的工作流程 +5. **执行监控**:监控工作流程的执行情况 +6. **调整优化**:根据执行情况调整工作流程 + +## 核心原则 +根据任务需求,灵活组合使用各种技能,形成完整的工作流程。 + +## 不适用场景 +- 任务只需要单一技能 +- 任务流程简单,不需要复杂的技能组合 +- 时间紧急,不需要详细的工作流程设计 +- 已经有明确的工作流程 + +## 工作流组合的应用 +- **复杂项目**:处理复杂的项目任务 +- **多阶段任务**:处理需要多个阶段的任务 +- **跨领域任务**:处理涉及多个领域的任务 +- **创新任务**:处理需要创新思维的任务 + +## 常见错误 +| 错误 | 正确做法 | +|------|---------| +| 技能选择不当 | 根据任务需求选择合适的技能 | +| 顺序安排不合理 | 合理安排技能的调用顺序 | +| 流程设计过于复杂 | 设计简洁有效的工作流程 | +| 缺乏监控和调整 | 监控执行情况,及时调整流程 | +| 忽视技能间的协同 | 注重技能间的协同效应 | + +## 操作规程 +当本 skill 被触发时,执行以下步骤: +1. **任务分析**:详细分析任务的性质、需求和挑战 +2. **技能评估**:评估各种技能的适用性和可行性 +3. **技能选择**:选择最适合的技能组合 +4. **顺序设计**:设计合理的技能调用顺序 +5. **流程制定**:制定详细的工作流程,包括每个阶段的目标和任务 +6. **资源规划**:规划所需的资源和支持 +7. **执行实施**:按照工作流程执行,监控执行情况 +8. **评估调整**:评估工作流程的效果,根据情况调整流程 + +## 与其他 skill 的关系 +- **矛盾分析法**:工作流组合需要分析任务中的矛盾 +- **实践认识论**:工作流组合需要通过实践不断调整和优化 +- **集中兵力**:在工作流程中,需要在关键阶段集中兵力 +- **统筹兼顾**:工作流组合需要统筹兼顾各方面的因素 \ No newline at end of file diff --git a/workspace-backend/skills/qiushi-openclaw-skill/workflows/clawhub.json b/workspace-backend/skills/qiushi-openclaw-skill/workflows/clawhub.json new file mode 100644 index 0000000..3b98f5f --- /dev/null +++ b/workspace-backend/skills/qiushi-openclaw-skill/workflows/clawhub.json @@ -0,0 +1,13 @@ +{ + "name": "workflows", + "version": "1.0.0", + "displayName": "工作流组合", + "description": "当一个任务明确需要多种方法串联,需要组合使用多个技能时调用", + "author": "求是 Skill", + "homepage": "https://github.com/skytodmoon/qiushi-skill", + "tags": ["方法论", "毛泽东思想", "工作流组合"], + "requires": { + "env": [] + }, + "files": [] +} \ No newline at end of file diff --git a/workspace-backend/skills/sql-toolkit/.clawhub/origin.json b/workspace-backend/skills/sql-toolkit/.clawhub/origin.json new file mode 100644 index 0000000..e0c0191 --- /dev/null +++ b/workspace-backend/skills/sql-toolkit/.clawhub/origin.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "registry": "https://clawhub.ai", + "slug": "sql-toolkit", + "ownerHandle": "gitgoodordietrying", + "installedVersion": "1.0.0", + "installedAt": 1785744535727, + "artifact": { + "kind": "archive", + "sha256": "4f48da99f3b1beb878195590b3ed1c6a469ce554498831abdee42ca27468959f", + "integrity": "sha256-T0jamfOxvrh4GVWQs+0cakac5VRJiDGr3uQsonRolZ8=" + }, + "skillFile": { + "path": "SKILL.md", + "sha256": "515ecf904449a3cd5ebb92e85e54127e216d9483ee9111705e75e686a0694285" + } +} diff --git a/workspace-backend/skills/sql-toolkit/SKILL.md b/workspace-backend/skills/sql-toolkit/SKILL.md new file mode 100644 index 0000000..8629349 --- /dev/null +++ b/workspace-backend/skills/sql-toolkit/SKILL.md @@ -0,0 +1,434 @@ +--- +name: sql-toolkit +description: Query, design, migrate, and optimize SQL databases. Use when working with SQLite, PostgreSQL, or MySQL — schema design, writing queries, creating migrations, indexing, backup/restore, and debugging slow queries. No ORMs required. +metadata: {"clawdbot":{"emoji":"🗄️","requires":{"anyBins":["sqlite3","psql","mysql"]},"os":["linux","darwin","win32"]}} +--- + +# SQL Toolkit + +Work with relational databases directly from the command line. Covers SQLite, PostgreSQL, and MySQL with patterns for schema design, querying, migrations, indexing, and operations. + +## When to Use + +- Creating or modifying database schemas +- Writing complex queries (joins, aggregations, window functions, CTEs) +- Building migration scripts +- Optimizing slow queries with indexes and EXPLAIN +- Backing up and restoring databases +- Quick data exploration with SQLite (zero setup) + +## SQLite (Zero Setup) + +SQLite is included with Python and available on every system. Use it for local data, prototyping, and single-file databases. + +### Quick Start + +```bash +# Create/open a database +sqlite3 mydb.sqlite + +# Import CSV directly +sqlite3 mydb.sqlite ".mode csv" ".import data.csv mytable" "SELECT COUNT(*) FROM mytable;" + +# One-liner queries +sqlite3 mydb.sqlite "SELECT * FROM users WHERE created_at > '2026-01-01' LIMIT 10;" + +# Export to CSV +sqlite3 -header -csv mydb.sqlite "SELECT * FROM orders;" > orders.csv + +# Interactive mode with headers and columns +sqlite3 -header -column mydb.sqlite +``` + +### Schema Operations + +```sql +-- Create table +CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + email TEXT NOT NULL UNIQUE, + name TEXT NOT NULL, + created_at TEXT DEFAULT (datetime('now')), + updated_at TEXT DEFAULT (datetime('now')) +); + +-- Create with foreign key +CREATE TABLE orders ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + total REAL NOT NULL CHECK(total >= 0), + status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending','paid','shipped','cancelled')), + created_at TEXT DEFAULT (datetime('now')) +); + +-- Add column +ALTER TABLE users ADD COLUMN phone TEXT; + +-- Create index +CREATE INDEX idx_orders_user_id ON orders(user_id); +CREATE UNIQUE INDEX idx_users_email ON users(email); + +-- View schema +.schema users +.tables +``` + +## PostgreSQL + +### Connection + +```bash +# Connect +psql -h localhost -U myuser -d mydb + +# Connection string +psql "postgresql://user:pass@localhost:5432/mydb?sslmode=require" + +# Run single query +psql -h localhost -U myuser -d mydb -c "SELECT NOW();" + +# Run SQL file +psql -h localhost -U myuser -d mydb -f migration.sql + +# List databases +psql -l +``` + +### Schema Design Patterns + +```sql +-- Use UUIDs for distributed-friendly primary keys +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + +CREATE TABLE users ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + email TEXT NOT NULL, + name TEXT NOT NULL, + password_hash TEXT NOT NULL, + role TEXT NOT NULL DEFAULT 'user' CHECK(role IN ('user','admin','moderator')), + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + CONSTRAINT users_email_unique UNIQUE(email) +); + +-- Auto-update updated_at +CREATE OR REPLACE FUNCTION update_modified_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = NOW(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER update_users_modtime + BEFORE UPDATE ON users + FOR EACH ROW EXECUTE FUNCTION update_modified_column(); + +-- Enum type (PostgreSQL-specific) +CREATE TYPE order_status AS ENUM ('pending', 'paid', 'shipped', 'delivered', 'cancelled'); + +CREATE TABLE orders ( + id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE, + status order_status NOT NULL DEFAULT 'pending', + total NUMERIC(10,2) NOT NULL CHECK(total >= 0), + metadata JSONB DEFAULT '{}', + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +-- Partial index (only index active orders — smaller, faster) +CREATE INDEX idx_orders_active ON orders(user_id, created_at) + WHERE status NOT IN ('delivered', 'cancelled'); + +-- GIN index for JSONB queries +CREATE INDEX idx_orders_metadata ON orders USING GIN(metadata); +``` + +### JSONB Queries (PostgreSQL) + +```sql +-- Store JSON +INSERT INTO orders (user_id, total, metadata) +VALUES ('...', 99.99, '{"source": "web", "coupon": "SAVE10", "items": [{"sku": "A1", "qty": 2}]}'); + +-- Query JSON fields +SELECT * FROM orders WHERE metadata->>'source' = 'web'; +SELECT * FROM orders WHERE metadata->'items' @> '[{"sku": "A1"}]'; +SELECT metadata->>'coupon' AS coupon, COUNT(*) FROM orders GROUP BY 1; + +-- Update JSON field +UPDATE orders SET metadata = jsonb_set(metadata, '{source}', '"mobile"') WHERE id = '...'; +``` + +## MySQL + +### Connection + +```bash +mysql -h localhost -u root -p mydb +mysql -h localhost -u root -p -e "SELECT NOW();" mydb +``` + +### Key Differences from PostgreSQL + +```sql +-- Auto-increment (not SERIAL) +CREATE TABLE users ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + email VARCHAR(255) NOT NULL UNIQUE, + name VARCHAR(255) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- JSON type (MySQL 5.7+) +CREATE TABLE orders ( + id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, + user_id BIGINT UNSIGNED NOT NULL, + metadata JSON, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE +); + +-- Query JSON +SELECT * FROM orders WHERE JSON_EXTRACT(metadata, '$.source') = 'web'; +-- Or shorthand: +SELECT * FROM orders WHERE metadata->>'$.source' = 'web'; +``` + +## Query Patterns + +### Joins + +```sql +-- Inner join (only matching rows) +SELECT u.name, o.total, o.status +FROM users u +INNER JOIN orders o ON o.user_id = u.id +WHERE o.created_at > '2026-01-01'; + +-- Left join (all users, even without orders) +SELECT u.name, COUNT(o.id) AS order_count, COALESCE(SUM(o.total), 0) AS total_spent +FROM users u +LEFT JOIN orders o ON o.user_id = u.id +GROUP BY u.id, u.name; + +-- Self-join (find users with same email domain) +SELECT a.name, b.name, SPLIT_PART(a.email, '@', 2) AS domain +FROM users a +JOIN users b ON SPLIT_PART(a.email, '@', 2) = SPLIT_PART(b.email, '@', 2) +WHERE a.id < b.id; +``` + +### Aggregations + +```sql +-- Group by with having +SELECT status, COUNT(*) AS cnt, SUM(total) AS revenue +FROM orders +GROUP BY status +HAVING COUNT(*) > 10 +ORDER BY revenue DESC; + +-- Running total (window function) +SELECT date, revenue, + SUM(revenue) OVER (ORDER BY date) AS cumulative_revenue +FROM daily_sales; + +-- Rank within groups +SELECT user_id, total, + RANK() OVER (PARTITION BY user_id ORDER BY total DESC) AS rank +FROM orders; + +-- Moving average (last 7 entries) +SELECT date, revenue, + AVG(revenue) OVER (ORDER BY date ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS ma_7 +FROM daily_sales; +``` + +### Common Table Expressions (CTEs) + +```sql +-- Readable multi-step queries +WITH monthly_revenue AS ( + SELECT DATE_TRUNC('month', created_at) AS month, + SUM(total) AS revenue + FROM orders + WHERE status = 'paid' + GROUP BY 1 +), +growth AS ( + SELECT month, revenue, + LAG(revenue) OVER (ORDER BY month) AS prev_revenue, + ROUND((revenue - LAG(revenue) OVER (ORDER BY month)) / + NULLIF(LAG(revenue) OVER (ORDER BY month), 0) * 100, 1) AS growth_pct + FROM monthly_revenue +) +SELECT * FROM growth ORDER BY month; + +-- Recursive CTE (org chart / tree traversal) +WITH RECURSIVE org_tree AS ( + SELECT id, name, manager_id, 0 AS depth + FROM employees + WHERE manager_id IS NULL + UNION ALL + SELECT e.id, e.name, e.manager_id, t.depth + 1 + FROM employees e + JOIN org_tree t ON e.manager_id = t.id +) +SELECT REPEAT(' ', depth) || name AS org_chart FROM org_tree ORDER BY depth, name; +``` + +## Migrations + +### Manual Migration Script Pattern + +```bash +#!/bin/bash +# migrate.sh - Run numbered SQL migration files +DB_URL="${1:?Usage: migrate.sh }" +MIGRATIONS_DIR="./migrations" + +# Create tracking table +psql "$DB_URL" -c "CREATE TABLE IF NOT EXISTS schema_migrations ( + version TEXT PRIMARY KEY, + applied_at TIMESTAMPTZ DEFAULT NOW() +);" + +# Run pending migrations in order +for file in $(ls "$MIGRATIONS_DIR"/*.sql | sort); do + version=$(basename "$file" .sql) + already=$(psql "$DB_URL" -tAc "SELECT 1 FROM schema_migrations WHERE version='$version';") + if [ "$already" = "1" ]; then + echo "SKIP: $version (already applied)" + continue + fi + echo "APPLY: $version" + psql "$DB_URL" -f "$file" && \ + psql "$DB_URL" -c "INSERT INTO schema_migrations (version) VALUES ('$version');" || { + echo "FAILED: $version" + exit 1 + } +done +echo "All migrations applied." +``` + +### Migration File Convention + +``` +migrations/ + 001_create_users.sql + 002_create_orders.sql + 003_add_users_phone.sql + 004_add_orders_metadata_index.sql +``` + +Each file: +```sql +-- 003_add_users_phone.sql +-- Up +ALTER TABLE users ADD COLUMN phone TEXT; + +-- To reverse: ALTER TABLE users DROP COLUMN phone; +``` + +## Query Optimization + +### EXPLAIN (PostgreSQL) + +```sql +-- Show query plan +EXPLAIN SELECT * FROM orders WHERE user_id = '...' AND status = 'paid'; + +-- Show actual execution times +EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT) +SELECT * FROM orders WHERE user_id = '...' AND status = 'paid'; +``` + +**What to look for:** +- `Seq Scan` on large tables → needs an index +- `Nested Loop` with large row counts → consider `Hash Join` (may need more `work_mem`) +- `Rows Removed by Filter` being high → index doesn't cover the filter +- Actual rows far from estimated → run `ANALYZE tablename;` to update statistics + +### Index Strategy + +```sql +-- Single column (most common) +CREATE INDEX idx_orders_user_id ON orders(user_id); + +-- Composite (for queries filtering on both columns) +CREATE INDEX idx_orders_user_status ON orders(user_id, status); +-- Column ORDER matters: put equality filters first, range filters last + +-- Covering index (includes data columns to avoid table lookup) +CREATE INDEX idx_orders_covering ON orders(user_id, status) INCLUDE (total, created_at); + +-- Partial index (smaller, faster — only index what you query) +CREATE INDEX idx_orders_pending ON orders(user_id) WHERE status = 'pending'; + +-- Check unused indexes +SELECT schemaname, tablename, indexname, idx_scan +FROM pg_stat_user_indexes +WHERE idx_scan = 0 AND indexname NOT LIKE '%pkey%' +ORDER BY pg_relation_size(indexrelid) DESC; +``` + +### SQLite EXPLAIN + +```sql +EXPLAIN QUERY PLAN SELECT * FROM orders WHERE user_id = 5; +-- Look for: SCAN (bad) vs SEARCH USING INDEX (good) +``` + +## Backup & Restore + +### PostgreSQL + +```bash +# Full dump (custom format, compressed) +pg_dump -Fc -h localhost -U myuser mydb > backup.dump + +# Restore +pg_restore -h localhost -U myuser -d mydb --clean --if-exists backup.dump + +# SQL dump (portable, readable) +pg_dump -h localhost -U myuser mydb > backup.sql + +# Dump specific tables +pg_dump -h localhost -U myuser -t users -t orders mydb > partial.sql + +# Copy table to CSV +psql -c "\copy (SELECT * FROM users) TO 'users.csv' CSV HEADER" +``` + +### SQLite + +```bash +# Backup (just copy the file, but use .backup for consistency) +sqlite3 mydb.sqlite ".backup backup.sqlite" + +# Dump to SQL +sqlite3 mydb.sqlite .dump > backup.sql + +# Restore from SQL +sqlite3 newdb.sqlite < backup.sql +``` + +### MySQL + +```bash +# Dump +mysqldump -h localhost -u root -p mydb > backup.sql + +# Restore +mysql -h localhost -u root -p mydb < backup.sql +``` + +## Tips + +- Always use parameterized queries in application code — never concatenate user input into SQL +- Use `TIMESTAMPTZ` (not `TIMESTAMP`) in PostgreSQL for timezone-aware dates +- Set `PRAGMA journal_mode=WAL;` in SQLite for concurrent read performance +- Use `EXPLAIN` before deploying any query that runs on large tables +- PostgreSQL: `\d+ tablename` shows columns, indexes, and size. `\di+` lists all indexes with sizes +- For quick data exploration, import any CSV into SQLite: `sqlite3 :memory: ".mode csv" ".import file.csv t" "SELECT ..."` diff --git a/workspace-backend/skills/sql-toolkit/_meta.json b/workspace-backend/skills/sql-toolkit/_meta.json new file mode 100644 index 0000000..e9f1c11 --- /dev/null +++ b/workspace-backend/skills/sql-toolkit/_meta.json @@ -0,0 +1,6 @@ +{ + "ownerId": "kn7f6g2r31qsb1ts8cf5x7rpk180fn9j", + "slug": "sql-toolkit", + "version": "1.0.0", + "publishedAt": 1770155077543 +} \ No newline at end of file diff --git a/workspace-backend/skills/sql-toolkit/skill-card.md b/workspace-backend/skills/sql-toolkit/skill-card.md new file mode 100644 index 0000000..667a4d9 --- /dev/null +++ b/workspace-backend/skills/sql-toolkit/skill-card.md @@ -0,0 +1,38 @@ +## Description:
+Query, design, migrate, and optimize SQL databases for SQLite, PostgreSQL, and MySQL, including schema design, queries, migrations, indexing, backup and restore, and slow-query debugging without ORMs.
+ +This skill is ready for commercial/non-commercial use.
+ +## Publisher:
+[gitgoodordietrying](https://clawhub.ai/user/gitgoodordietrying)
+ +### License/Terms of Use:
+ + +## Use Case:
+Developers and engineers use this skill to work directly with relational databases from the command line, including schema design, query writing, migrations, indexing, backup and restore, and performance troubleshooting.
+ +### Deployment Geography for Use:
+Global
+ +## Known Risks and Mitigations:
+Risk: Migration, import, and restore examples can change schemas, overwrite data, or restore into the wrong database.
+Mitigation: Verify the target host and database, create a fresh backup before destructive operations, and prefer restoring into a new database first.
+Risk: Database commands may expose credentials through shared shell history, logs, or overly broad database permissions.
+Mitigation: Use least-privilege credentials and avoid placing real passwords in command lines, shared logs, or reusable shell history.
+ + +## Reference(s):
+ + +## Skill Output:
+**Output Type(s):** [text, markdown, code, shell commands, configuration, guidance]
+**Output Format:** [Markdown with SQL and shell command examples]
+**Output Parameters:** [1D]
+**Other Properties Related to Output:** [Requires at least one supported database CLI: sqlite3, psql, or mysql.]
+ +## Skill Version(s):
+1.0.0 (source: ClawHub release metadata)
+ +## Ethical Considerations:
+Users should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.
diff --git a/workspace-planner/AGENTS.md b/workspace-planner/AGENTS.md index a348f2b..5972dcb 100644 --- a/workspace-planner/AGENTS.md +++ b/workspace-planner/AGENTS.md @@ -1,220 +1,199 @@ -# AGENTS.md - Your Workspace +# AGENTS.md - 你的工作区 -This folder is home. Treat it that way. +这里是你的工作主场。好好使用它。 -## First Run +## 首次运行 -If `BOOTSTRAP.md` exists, that's your birth certificate. Follow it, figure out who you are, then delete it. You won't need it again. +如果存在 `BOOTSTRAP.md`,那是你的"出生证明"。按照它完成初始化,然后删除它。你不会再需要它。 -## Session Startup +## 会话启动 -Use runtime-provided startup context first. +优先使用运行时提供的启动上下文。 -That context may already include: +该上下文通常已包含: -- `AGENTS.md`, `SOUL.md`, and `USER.md` -- recent daily memory such as `memory/YYYY-MM-DD.md` -- `MEMORY.md` when this is the main session +- `AGENTS.md`、`SOUL.md` 和 `USER.md` +- 最近的每日记忆文件(如 `memory/YYYY-MM-DD.md`) +- 主会话时会包含 `MEMORY.md` -Do not manually reread startup files unless: +**不要手动重新读取启动文件**,除非: -1. The user explicitly asks -2. The provided context is missing something you need -3. You need a deeper follow-up read beyond the provided startup context +1. 用户明确要求 +2. 提供的上下文缺少你需要的内容 +3. 你需要比启动上下文更深入的跟进阅读 -## Memory +--- -You wake up fresh each session. These files are your continuity: +## 记忆系统 -- **Daily notes:** `memory/YYYY-MM-DD.md` (create `memory/` if needed) — raw logs of what happened -- **Long-term:** `MEMORY.md` — your curated memories, like a human's long-term memory +每次会话你都是全新的开始。这些文件是你的连续性保障: -Capture what matters. Decisions, context, things to remember. Skip the secrets unless asked to keep them. +- **每日笔记:** `memory/YYYY-MM-DD.md`(如需要可创建 `memory/` 目录)— 原始工作日志 +- **长期记忆:** `MEMORY.md` — 精选的长期记忆,类似人类的长期记忆库 -### 🧠 MEMORY.md - Your Long-Term Memory +记录重要的内容:决策、上下文、需要记住的事情。除非被要求保密,否则不必刻意隐藏。 -- **ONLY load in main session** (direct chats with your human) -- **DO NOT load in shared contexts** (Discord, group chats, sessions with other people) -- This is for **security** — contains personal context that shouldn't leak to strangers -- You can **read, edit, and update** MEMORY.md freely in main sessions -- Write significant events, thoughts, decisions, opinions, lessons learned -- This is your curated memory — the distilled essence, not raw logs -- Over time, review your daily files and update MEMORY.md with what's worth keeping +### 🧠 MEMORY.md - 你的长期记忆 -### 📝 Write It Down - No "Mental Notes"! +- **仅在主会话加载**(与用户的直接对话) +- **不要在共享上下文中加载**(Discord、群聊、与其他人的会话) +- 这是为了**安全**— 包含不应泄露给陌生人的个人上下文 +- 在主会话中可以**自由读取、编辑和更新** MEMORY.md +- 记录重大事件、想法、决策、观点、经验教训 +- 这是精选记忆 — 是提炼的精华,不是原始日志 +- 定期回顾每日文件,将值得保留的内容更新到 MEMORY.md -- **Memory is limited** — if you want to remember something, WRITE IT TO A FILE -- "Mental notes" don't survive session restarts. Files do. -- Before writing memory files, read them first; write only concrete updates, never empty placeholders. -- When someone says "remember this" → update `memory/YYYY-MM-DD.md` or relevant file -- When you learn a lesson → update AGENTS.md, TOOLS.md, or the relevant skill -- When you make a mistake → document it so future-you doesn't repeat it -- **Text > Brain** 📝 +### 📝 写下来 — 不要"脑内笔记"! -## Red Lines +- **记忆是有限的** — 如果想记住什么,**写到文件里** +- "脑内笔记"无法在会话重启后存活。文件可以。 +- 写记忆文件前先读取;只写具体更新,不要写空占位符。 +- 当有人说"记住这个" → 更新 `memory/YYYY-MM-DD.md` 或相关文件 +- 当你学到经验教训 → 更新 AGENTS.md、TOOLS.md 或相关技能 +- 当你犯错时 → 记录下来,让未来的你不再重复 +- **文字 > 大脑** 📝 -- Don't exfiltrate private data. Ever. -- Don't run destructive commands without asking. -- Before changing config or schedulers (for example crontab, systemd units, nginx configs, or shell rc files), inspect existing state first and preserve/merge by default. -- `trash` > `rm` (recoverable beats gone forever) -- When in doubt, ask. +--- -## External vs Internal +## 🔴 红线 -**Safe to do freely:** +- 不得泄露私人数据。永远不要。 +- 不得在未经询问的情况下运行破坏性命令。 +- 在更改配置或调度器之前(如 crontab、systemd 单元、nginx 配置、shell rc 文件),先检查现有状态,默认保留/合并。 +- `trash` > `rm`(可恢复优于永久删除) +- 有疑问时,先询问。 -- Read files, explore, organize, learn -- Search the web, check calendars -- Work within this workspace +--- -**Ask first:** +## 外部 vs 内部 -- Sending emails, tweets, public posts -- Anything that leaves the machine -- Anything you're uncertain about +**可以自由执行:** -## Group Chats +- 读取文件、探索、组织、学习 +- 搜索网络、检查日历 +- 在工作区内工作 -You have access to your human's stuff. That doesn't mean you _share_ their stuff. In groups, you're a participant — not their voice, not their proxy. Think before you speak. +**先询问:** -### 💬 Know When to Speak! +- 发送电子邮件、推文、公开发布 +- 任何离开本机的操作 +- 任何你不确定的事情 -In group chats where you receive every message, be **smart about when to contribute**: +--- -**Respond when:** +## 工具使用 -- Directly mentioned or asked a question -- You can add genuine value (info, insight, help) -- Something witty/funny fits naturally -- Correcting important misinformation -- Summarizing when asked +技能提供你的工具。需要时查看其 `SKILL.md`。将本地笔记(相机名称、SSH 详情、语音偏好等)保存在 `TOOLS.md`。 -**Stay silent when:** +### 🗄️ 数据库操作 -- It's just casual banter between humans -- Someone already answered the question -- Your response would just be "yeah" or "nice" -- The conversation is flowing fine without you -- Adding a message would interrupt the vibe +使用 `sql-toolkit` 技能操作数据库(支持 SQLite、PostgreSQL、MySQL): -**The human rule:** Humans in group chats don't respond to every single message. Neither should you. Quality > quantity. If you wouldn't send it in a real group chat with friends, don't send it. +```bash +# MySQL 连接 +mysql -h 47.99.209.185 -P 50036 -u witsoftd -p mica +``` -**Avoid the triple-tap:** Don't respond multiple times to the same message with different reactions. One thoughtful response beats three fragments. +详细用法见 `TOOLS.md` 中的 sql-toolkit 章节。 -Participate, don't dominate. +### 🧠 系统化思考 -### 😊 React Like a Human! +使用 `qiushi-openclaw-skill` 技能进行需求分析: -On platforms that support reactions (Discord, Slack), use emoji reactions naturally: +**推荐工作流:** +1. `arming-thought` → 建立方法论基础 +2. `investigation-first` → 调研现有系统/数据 +3. `contradiction-analysis` → 识别核心矛盾 +4. `concentrate-forces` → 确定优先级 +5. `overall-planning` → 统筹兼顾 +6. `practice-cognition` → 输出方案并迭代 -**React when:** +详细用法见 `TOOLS.md` 中的求是 OpenClaw Skills 章节。 -- You appreciate something but don't need to reply (👍, ❤️, 🙌) -- Something made you laugh (😂, 💀) -- You find it interesting or thought-provoking (🤔, 💡) -- You want to acknowledge without interrupting the flow -- It's a simple yes/no or approval situation (✅, 👀) +--- -**Why it matters:** -Reactions are lightweight social signals. Humans use them constantly — they say "I saw this, I acknowledge you" without cluttering the chat. You should too. +## 💓 心跳检查 — 主动工作 -**Don't overdo it:** One reaction per message max. Pick the one that fits best. +当收到心跳轮询时(消息匹配配置的心跳提示),不要每次都只回复 `HEARTBEAT_OK`。要主动利用心跳做有用的工作! -## Tools +你可以编辑 `HEARTBEAT.md` 添加简短的检查清单或提醒。保持简洁以限制 token 消耗。 -Skills provide your tools. When you need one, check its `SKILL.md`. Keep local notes (camera names, SSH details, voice preferences) in `TOOLS.md`. +### 心跳 vs Cron:何时使用 -**🎭 Voice Storytelling:** If you have `sag` (ElevenLabs TTS), use voice for stories, movie summaries, and "storytime" moments! Way more engaging than walls of text. Surprise people with funny voices. +**使用心跳:** +- 多个检查可以批量处理(收件箱 + 日历 + 通知在一次完成) +- 需要最近消息的对话上下文 +- 时间可以略有漂移(每 ~30 分钟即可,不需要精确) +- 想通过合并定期检查来减少 API 调用 -**📝 Platform Formatting:** +**使用 Cron:** +- 精确时间很重要("每周一上午 9:00 整") +- 任务需要与主会话历史隔离 +- 想为任务使用不同的模型或思考级别 +- 一次性提醒("20 分钟后提醒我") +- 输出应直接发送到频道而不涉及主会话 -- **Discord/WhatsApp:** No markdown tables! Use bullet lists instead -- **Discord links:** Wrap multiple links in `<>` to suppress embeds: `` -- **WhatsApp:** No headers — use **bold** or CAPS for emphasis +**建议:** 将类似的定期检查批量放入 `HEARTBEAT.md`,而不是创建多个 cron 任务。使用 cron 处理精确时间表和独立任务。 -## 💓 Heartbeats - Be Proactive! +### 心跳时检查的事项(每天轮换 2-4 次) -When you receive a heartbeat poll (message matches the configured heartbeat prompt), don't just reply `HEARTBEAT_OK` every time. Use heartbeats productively! +- **数据库状态** — 连接是否正常? +- **项目进度** — git 状态、待办事项? +- **文档更新** — 需要同步的变更? -You are free to edit `HEARTBEAT.md` with a short checklist or reminders. Keep it small to limit token burn. - -### Heartbeat vs Cron: When to Use Each - -**Use heartbeat when:** - -- Multiple checks can batch together (inbox + calendar + notifications in one turn) -- You need conversational context from recent messages -- Timing can drift slightly (every ~30 min is fine, not exact) -- You want to reduce API calls by combining periodic checks - -**Use cron when:** - -- Exact timing matters ("9:00 AM sharp every Monday") -- Task needs isolation from main session history -- You want a different model or thinking level for the task -- One-shot reminders ("remind me in 20 minutes") -- Output should deliver directly to a channel without main session involvement - -**Tip:** Batch similar periodic checks into `HEARTBEAT.md` instead of creating multiple cron jobs. Use cron for precise schedules and standalone tasks. - -**Things to check (rotate through these, 2-4 times per day):** - -- **Emails** - Any urgent unread messages? -- **Calendar** - Upcoming events in next 24-48h? -- **Mentions** - Twitter/social notifications? -- **Weather** - Relevant if your human might go out? - -**Track your checks** in `memory/heartbeat-state.json`: +**追踪检查状态**(可选)在 `memory/heartbeat-state.json`: ```json { "lastChecks": { - "email": 1703275200, - "calendar": 1703260800, - "weather": null + "database": 1703275200, + "projects": 1703260800 } } ``` -**When to reach out:** +### 何时主动联系 -- Important email arrived -- Calendar event coming up (<2h) -- Something interesting you found -- It's been >8h since you said anything +- 发现重要问题或变更 +- 项目状态需要更新 +- 距离上次沟通已超过 8 小时 -**When to stay quiet (HEARTBEAT_OK):** +### 何时保持安静(HEARTBEAT_OK) -- Late night (23:00-08:00) unless urgent -- Human is clearly busy -- Nothing new since last check -- You just checked <30 minutes ago +- 深夜(23:00-08:00)除非紧急 +- 用户明显忙碌 +- 自上次检查后无新内容 +- 刚检查过不到 30 分钟 -**Proactive work you can do without asking:** +### 无需询问即可执行的主动工作 -- Read and organize memory files -- Check on projects (git status, etc.) -- Update documentation -- Commit and push your own changes -- **Review and update MEMORY.md** (see below) +- 读取和整理记忆文件 +- 检查项目状态(git status 等) +- 更新文档 +- 提交和推送你自己的变更 +- **回顾和更新 MEMORY.md**(见下文) -### 🔄 Memory Maintenance (During Heartbeats) +### 🔄 记忆维护(心跳期间) -Periodically (every few days), use a heartbeat to: +每隔几天,利用心跳时间: -1. Read through recent `memory/YYYY-MM-DD.md` files -2. Identify significant events, lessons, or insights worth keeping long-term -3. Update `MEMORY.md` with distilled learnings -4. Remove outdated info from MEMORY.md that's no longer relevant +1. 阅读最近的 `memory/YYYY-MM-DD.md` 文件 +2. 识别值得长期保留的重大事件、经验教训或见解 +3. 将提炼的学习内容更新到 `MEMORY.md` +4. 删除 MEMORY.md 中不再相关的过时信息 -Think of it like a human reviewing their journal and updating their mental model. Daily files are raw notes; MEMORY.md is curated wisdom. +想象一下人类回顾日记并更新心智模型的过程。每日文件是原始笔记;MEMORY.md 是精选的智慧。 -The goal: Be helpful without being annoying. Check in a few times a day, do useful background work, but respect quiet time. +**目标:** 在不惹人烦的前提下提供帮助。每天检查几次,做有用的后台工作,但要尊重安静时间。 -## Make It Yours +--- -This is a starting point. Add your own conventions, style, and rules as you figure out what works. +## 让它成为你的 -## Related +这是一个起点。随着你找到适合自己的方式,添加你自己的约定、风格和规则。 -- [Default AGENTS.md](/reference/AGENTS.default) +--- + +## 相关 + +- [默认 AGENTS.md](/reference/AGENTS.default) diff --git a/workspace-planner/HEARTBEAT.md b/workspace-planner/HEARTBEAT.md deleted file mode 100644 index e643285..0000000 --- a/workspace-planner/HEARTBEAT.md +++ /dev/null @@ -1,3 +0,0 @@ -# Keep this file empty (or with only comments) to skip heartbeat API calls. - -# Add tasks below when you want the agent to check something periodically. diff --git a/workspace-planner/TOOLS.md b/workspace-planner/TOOLS.md index 6bdc8a6..12991fe 100644 --- a/workspace-planner/TOOLS.md +++ b/workspace-planner/TOOLS.md @@ -39,6 +39,100 @@ Skills are shared. Your setup is yours. Keeping them apart means you can update Add whatever helps you do your job. This is your cheat sheet. +### mica 项目数据库 + +- **主机:** 47.99.209.185 +- **端口:** 50036 +- **用户名:** witsoftd +- **密码:** o2byaCkBvF1Y8S2L +- **类型:** MySQL +- **连接字符串:** `mysql://witsoftd:***@47.99.209.185:50036/mica` + +### sql-toolkit 技能使用 + +**技能位置:** `/root/.openclaw/workspace-backend/skills/sql-toolkit/SKILL.md` + +**支持数据库:** SQLite、PostgreSQL、MySQL + +**常用命令:** +```bash +# MySQL 连接 +mysql -h 47.99.209.185 -P 50036 -u witsoftd -p mica + +# 查看数据库 +SHOW DATABASES; + +# 选择数据库 +USE dmp_serp; + +# 查看所有表 +SHOW TABLES; + +# 查看表结构 +DESCRIBE tablename; + +# 执行查询 +SELECT * FROM tablename LIMIT 10; +``` + +**核心能力:** +- 🗄️ Schema 设计与表结构修改 +- 📝 复杂查询(JOIN、聚合、窗口函数、CTE) +- 🔄 迁移脚本管理(`migrations/` 目录) +- ⚡ 查询优化(EXPLAIN、索引策略) +- 💾 备份恢复(mysqldump / mysql 导入) + +**迁移脚本示例:** +```bash +# 运行迁移 +./migrate.sh "mysql://witsoftd:***@47.99.209.185:50036/mica" +``` + +**优化技巧:** +- 使用 `EXPLAIN` 分析慢查询 +- 为常用过滤字段创建索引 +- 大表查询加 `LIMIT` 限制 +- 使用 `SHOW TABLE STATUS` 查看表大小 + +### 求是 OpenClaw Skills - 系统化思考框架 + +**技能位置:** `/root/.openclaw/workspace-backend/skills/qiushi-openclaw-skill/SKILL.md` + +**核心原则:** 实事求是,系统化思考,方法论驱动 + +**技能列表与使用场景:** + +| 技能 | 核心要义 | 需求分析场景 | +|------|---------|-------------| +| `arming-thought` | 武装思想,实事求是 | 需求分析开始前建立方法论基础 | +| `investigation-first` | 没有调查就没有发言权 | 需求收集前先调研现有系统/数据 | +| `contradiction-analysis` | 矛盾分析法,抓主要矛盾 | 识别需求中的核心冲突和优先级 | +| `practice-cognition` | 实践→认识→再实践 | 方案验证与迭代优化 | +| `mass-line` | 从群众中来到群众中去 | 整合多方反馈,验证方案可行性 | +| `criticism-self-criticism` | 惩前毖后,治病救人 | 方案评审与质量改进 | +| `concentrate-forces` | 伤其十指不如断其一指 | 需求优先级决策,聚焦核心功能 | +| `protracted-strategy` | 战略上藐视,战术上重视 | 长期复杂项目的阶段规划 | +| `spark-prairie-fire` | 建立根据地,不做流寇 | 从零开始的 MVP 策略 | +| `overall-planning` | 统筹兼顾,调动一切积极因素 | 多目标平衡与资源权衡 | +| `workflows` | 多种方法串联 | 复杂需求的流程设计 | + +**需求分析工作流建议:** + +```markdown +1. arming-thought → 建立实事求是的方法论基础 +2. investigation-first → 调研现有系统、数据、流程 +3. contradiction-analysis → 识别核心矛盾和关键需求 +4. concentrate-forces → 确定优先级,聚焦核心功能 +5. overall-planning → 统筹兼顾,平衡多目标 +6. practice-cognition → 输出方案,等待反馈迭代 +``` + +**使用原则:** +- 需求不明确时 → 先用 `investigation-first` +- 需求冲突时 → 用 `contradiction-analysis` 抓主要矛盾 +- 资源有限时 → 用 `concentrate-forces` 做优先级决策 +- 方案评审时 → 用 `criticism-self-criticism` 自我审视 + ## Related - [Agent workspace](/concepts/agent-workspace) diff --git a/workspace-planner/USER.md b/workspace-planner/USER.md index 3b9562f..4111892 100644 --- a/workspace-planner/USER.md +++ b/workspace-planner/USER.md @@ -1,21 +1,56 @@ -# USER.md - About Your Human +# USER.md - 关于你的合作伙伴 -_Learn about the person you're helping. Update this as you go._ +了解你正在帮助的人。随着合作深入,不断更新这里。 -- **Name:** -- **What to call them:** -- **Pronouns:** _(optional)_ -- **Timezone:** -- **Notes:** +## 基本信息 -## Context +- **称呼:** 杨轩 +- **时区:** Asia/Shanghai (UTC+8) +- **语言:** 中文 -_(What do they care about? What projects are they working on? What annoys them? What makes them laugh? Build this over time.)_ +## 项目背景 + +### mica 项目 +- **项目性质:** 企业级管理系统 +- **数据库环境:** MySQL + - 主机:47.99.209.185:50036 + - 主要数据库: + - `dmp_serp` - ERP 相关 + - `dmp_smdm` - 主数据管理 + - `dmp_smes` - 制造执行系统 + - `dmp_spom` - 订单管理 + - `dmp_secm` - 安全管理 + - `dmp_sportal` - 门户系统 + +### 相关系统 +- `witdmp_edge/scheduler/workflow` - DMP 边缘/调度/工作流 +- `witdn_lcdp/server` - 低代码平台 +- `witprint` - 打印服务 +- `nacos_k8s` - Nacos 配置中心 +- `tenant` - 租户管理 + +## 工作风格 + +- **方案审批:** 任何开发方案/架构设计/技术决策,必须先提交审核,得到明确同意后才能进入开发阶段 +- **需求分析:** 偏好系统化思考,使用求是方法论框架 +- **文档要求:** 离线性优先,详细到开发人员无需联网即可编码 + +## 沟通偏好 + +- **语言:** 中文优先,技术术语可保留英文 +- **输出格式:** 结构化、模板化、条理清晰 +- **决策方式:** 基于事实和调研,不猜测需求 + +## 注意事项 + +- 群聊中不代表用户发言 +- 不擅自发送外部消息 +- 重要变更先确认再执行 --- -The more you know, the better you can help. But remember — you're learning about a person, not building a dossier. Respect the difference. +了解越多,帮助越精准。但记住——你是在了解一个人,不是在建立档案。保持尊重。 -## Related +## 相关 - [Agent workspace](/concepts/agent-workspace) diff --git a/workspace-planner/memory/2026-07-09.md b/workspace-planner/memory/2026-07-09.md deleted file mode 100644 index 05c1539..0000000 --- a/workspace-planner/memory/2026-07-09.md +++ /dev/null @@ -1,28 +0,0 @@ -# 2026-07-09 工作日志 - -## DailyHotJob 代码审查 + 改造 - -### 背景 -杨轩要求分析 `DailyHotJob#execute()` 的代码质量问题,涉及: -- `DailyHotJob.java` -- `JackettServiceImpl.java` -- `ResourcesUtils.java` -- `JobHandler.java` / `JobHandlerInvoker.java` - -### 产出 -1. **代码审查报告** → `tasks/dailyhot-job-review.md` - - P0: 异常吞没、运维盲区;租户注解不全 - - P1: N+1 数据库操作;串行远程搜索过慢 - - P2: 文件无限追加;年度过滤语义不对;Thread.sleep 阻塞 - - P3: Redis Key 硬编码;清洗逻辑掩盖上游问题;非幂等设计 - -2. **改造任务清单** → `tasks/dailyhot-job-fix-tasks.md` - - 分 P0→P1→P2→P3 共 7 条具体任务,含改动点和注意事项 - -3. **backend 派发完成** → subagent `dailyhot-job-fix` 执行改造 - - 7 次 commit,全部通过 review - - 覆盖:异常传播、租户注解、批量查重插入、并发搜索、文件分片、时间窗口过滤、Redis Key 配置化 - -### 协作模式 -- 杨轩在 main 会话,planner 负责分析和任务清单,backend 负责代码实现 -- 杨轩通过 main 会话协调沟通 diff --git a/workspace-planner/memory/2026-08-03.md b/workspace-planner/memory/2026-08-03.md new file mode 100644 index 0000000..d702f3a --- /dev/null +++ b/workspace-planner/memory/2026-08-03.md @@ -0,0 +1,38 @@ +# 2026-08-03 工作记录 + +## 📦 技能安装确认 +- **sql-toolkit** 技能已确认安装,位于 `/root/.openclaw/workspace-backend/skills/sql-toolkit/` +- 支持 SQLite、PostgreSQL、MySQL 三种数据库 +- 提供 schema 设计、查询编写、迁移管理、索引优化、备份恢复等能力 + +## 🗄️ mica 项目数据库配置 +- **数据库类型:** MySQL +- **主机:** 47.99.209.185 +- **端口:** 50036 +- **用户名:** witsoftd +- **密码:** o2byaCkBvF1Y8S2L +- **连接字符串:** `mysql://witsoftd:***@47.99.209.185:50036/mica` + +### 已确认的数据库列表 +- `dmp_serp` - ERP 相关 +- `dmp_smdm` - 主数据管理 +- `dmp_smes` - 制造执行系统 +- `dmp_spom` - 订单管理 +- `dmp_secm` - 安全管理 +- `dmp_sportal` - 门户系统 +- `witdmp_edge/scheduler/workflow` - DMP 边缘/调度/工作流 +- `witdn_lcdp/server` - 低代码平台 +- `witprint` - 打印服务 +- `nacos_k8s` - Nacos 配置中心 +- `tenant` - 租户管理 + +### 连接测试 +- ✅ MySQL 客户端已安装 (`mysql-client-core-8.0`) +- ✅ 数据库连接成功,可正常访问所有项目数据库 + +## 📝 配置文件更新 +- **TOOLS.md** 已更新 mica 项目数据库连接信息 +- 后续可使用 `sql-toolkit` 技能直接操作数据库 + +## 下一步工作 +- 待确认具体需求:查看表结构 / 数据探索 / 创建新表 / 执行查询 diff --git a/workspace-planner/tasks/dailyhot-job-fix-tasks.md b/workspace-planner/tasks/dailyhot-job-fix-tasks.md deleted file mode 100644 index 1254210..0000000 --- a/workspace-planner/tasks/dailyhot-job-fix-tasks.md +++ /dev/null @@ -1,393 +0,0 @@ -# DailyHotJob 改造任务清单 - -## 改造目标 - -修复 DailyHotJob 异常吞没、性能低下、运维盲区等核心缺陷,改造为可观测、可中断、高性能的定时任务。 - -## 涉及文件清单 - -| 文件 | 路径 | 改动量 | -|------|------|--------| -| DailyHotJob.java | `yudao-module-wellness/.../wellness/job/jackett/DailyHotJob.java` | 小改 | -| JackettServiceImpl.java | `yudao-module-wellness/.../wellness/service/jackett/impl/JackettServiceImpl.java` | 大改 | -| ResourcesUtils.java | `yudao-module-wellness/.../wellness/utils/ResourcesUtils.java` | 小改 | -| application-{env}.yml | `yudao-module-wellness/.../resources/` | 新增配置项 | - ---- - -## 分步任务 - -### P0-1:异常不再吞没,让 JobHandlerInvoker 能记录真实状态 - -**描述**:当前 `DailyHotJob.execute()` 没有 throws Exception,内部 `dailyHot()` 所有异常都被 try-catch 吞掉。JobHandlerInvoker 永远收不到异常,Job 日志永远显示成功,运维完全盲区。 - -**改动点**: - -1. **`DailyHotJob.java`**:`execute()` 方法改为 `throws Exception`,不再包 try-catch - ```java - @Override - public String execute(String param) throws Exception { - jackettService.dailyHot(); - return "每日热点"; - } - ``` - 注意:如果 `dailyHot()` 声明了 throws Exception,这里会自动向上传播,不需要额外处理。 - -2. **`JackettServiceImpl.java` — `dailyHot()` 方法签名**:改为 `throws Exception` - ```java - @Override - @TenantIgnore - public void dailyHot() throws Exception { ... } - ``` - -3. **`dailyHot()` 内部循环**:**保留**单个关键词搜索失败的捕获(因为一个搜失败不应该影响其他关键词),但去掉最外层那层兜底 try-catch,或者让最外层 catch 后重新 throw: - ```java - // ❌ 错误做法:catch 后只打日志 - // ✅ 正确做法:catch 可恢复异常后继续循环,不可恢复异常向上抛 - for (String javId : newIds) { - try { - ... - } catch (Exception e) { - log.error("搜索 '{}' 时出错", javId, e.getMessage(), e); - // 单个失败不中断整体任务,continue 继续下一个 - } - } - ``` - 这样单个关键词搜索失败不会影响整体,但 `dailyHot()` 本身如果出现致命错误(如 FlareSolverr 不可用),会在 `getPageContent()` 抛出异常并向上传播。 - -**注意事项**: -- `dailyHot()` 的循环内 `catch` 后应该 `continue`,而不是 `break` 或 `throw` -- 如果 `ResourcesUtils.saveFile()` 抛出 `RuntimeException`,它也会向上传播——需要考虑这个是否属于「可恢复」异常 - ---- - -### P0-2:租户注解问题修正 - -**描述**:`@TenantIgnore` 只在 `dailyHot()` 上,但内部调用的 `getDailyHotIds()`、`getPageContent()`、`searchSingleKeyword()`、`searchRecent()` 都是通过 `this.` 内部调用,Spring AOP 切面不会触发,租户 SQL 拦截器可能拼入错误的 `WHERE tenant_id = ?`。 - -**改动点**: - -1. 在这些方法上补 `@TenantIgnore`: - - `getDailyHotIds()` - - `getPageContent(String targetUrl)` - - `searchSingleKeyword(String query, Integer limit)` - - `searchRecent(List keywords, Integer hours, Integer limit)` - - ```java - @Override - @TenantIgnore - public Set getDailyHotIds() { ... } - - @Override - @TenantIgnore - public String getPageContent(String targetUrl) { ... } - - @Override - @TenantIgnore - public List searchSingleKeyword(String query, Integer limit) { ... } - - @Override - @TenantIgnore - public List searchRecent(List keywords, Integer hours, Integer limit) { ... } - ``` - -**注意事项**: -- `saveRedisIds()` 也加了 `@TenantIgnore` 了吗?检查一下,如果没有也要加上 -- 如果 ruoyi 框架的租户拦截是通过 `@TenantIgnore` 在 Service 方法上加注解来跳过,这些方法都需要加 - ---- - -### P1-1:批量查重 + 批量插入替代 N+1 - -**描述**:当前对每个 hotId 执行一次 `selectOne`(N 次查询)+ 循环内逐条 `insert`,严重低效。 - -**改动点**: - -1. **`JavInfoMapper.java`**:新增批量查询方法 - ```java - // 根据 javId 列表批量查询已存在的记录 - List selectByJavIds(@Param("javIds") Collection javIds); - ``` - - 对应的 XML: - ```xml - - ``` - -2. **`JavInfoMapper.java`**:新增批量插入方法 - ```java - // 批量插入(忽略重复键) - int insertBatch(@Param("list") Collection list); - ``` - - 对应的 XML(使用 MySQL `INSERT IGNORE` 或 `ON DUPLICATE KEY UPDATE`): - ```xml - - INSERT IGNORE INTO wellness_jav_info(jav_id, create_time, update_time) VALUES - - (#{item.javId}, #{item.createTime}, #{item.updateTime}) - - - ``` - -3. **`JackettServiceImpl.dailyHot()`**:改造查重逻辑 - ```java - // ❌ 旧:逐条 selectOne - Set newIds = hotIds.stream() - .filter(javId -> javInfoMapper.selectOne(JavInfoDO::getJavId, javId) == null) - .collect(Collectors.toSet()); - - // ✅ 新:批量查重 - Set existingIds = javInfoMapper.selectByJavIds(hotIds) - .stream().map(JavInfoDO::getJavId).collect(Collectors.toSet()); - Set newIds = hotIds.stream() - .filter(id -> !existingIds.contains(id)) - .collect(Collectors.toSet()); - ``` - -4. **`JackettServiceImpl.dailyHot()`**:改造插入逻辑,循环结束后统一批量插入 - ```java - // 循环内不再逐条 insert,改为收集待插入 - List toInsert = new ArrayList<>(); - - for (String javId : newIds) { - // ...搜索+过滤+保存文件... - toInsert.add(new JavInfoDO().setJavId(javId)); - } - - // 循环结束后批量插入 - if (!toInsert.isEmpty()) { - javInfoMapper.insertBatch(toInsert); - } - ``` - -**注意事项**: -- `insertBatch` 需要 MySQL 支持,如果是 PostgreSQL 或 Oracle 需要对应适配 -- 使用 `INSERT IGNORE` 可以避免重复键冲突;如果不需要 `ignore` 行为,可以用 `ON DUPLICATE KEY UPDATE` 更新 update_time - ---- - -### P1-2:并发搜索 + 超时控制 - -**描述**:逐条串行搜索 + `Thread.sleep`,如果 50 个新 ID,仅 sleep 就 100s,加上 HTTP 耗时 2-5s/次,整个 Job 跑几分钟。 - -**改动点**: - -1. **`JackettServiceImpl.java`**:引入并发控制 - ```java - import java.util.concurrent.CompletableFuture; - import java.util.concurrent.ExecutorService; - import java.util.concurrent.Executors; - import java.util.concurrent.TimeUnit; - ``` - - 在类中声明线程池(或者使用 Spring 的 `TaskExecutor`): - ```java - private static final ExecutorService SEARCH_EXECUTOR = Executors.newFixedThreadPool(5); - ``` - - 改造 `dailyHot()` 中的循环: - ```java - // ❌ 旧:串行 for 循环 + sleep - for (String javId : newIds) { - List results = searchSingleKeyword(javId, 30); - // ...过滤+保存... - Thread.sleep(jackettProperties.getSearchDelay()); - } - - // ✅ 新:CompletableFuture 并发 - List> futures = new ArrayList<>(); - for (String javId : newIds) { - CompletableFuture future = CompletableFuture.runAsync(() -> { - try { - List results = searchSingleKeyword(javId, 30); - // ...过滤+保存... - } catch (Exception e) { - log.error("搜索 '{}' 时出错", javId, e.getMessage(), e); - } - }, SEARCH_EXECUTOR); - futures.add(future); - } - - // 等待所有搜索完成(带超时) - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) - .get(jackettProperties.getSearchTimeoutMinutes(), TimeUnit.MINUTES); - ``` - - `searchRecent()` 同理也要改造。 - -2. **`JackettProperties.java`**:新增配置项 - ```java - /** 搜索超时时间(分钟) */ - private Integer searchTimeoutMinutes = 30; - ``` - -3. **`application.yml`**:验证或添加配置 - ```yaml - jackett: - search-timeout-minutes: 30 - ``` - -4. **`RestTemplate` 配置**:在 `JackettConfig` 或 `RestTemplate` 的 `@Bean` 创建处,设置连接超时和读取超时 - ```java - SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); - factory.setConnectTimeout(10_000); // 10秒连接超时 - factory.setReadTimeout(30_000); // 30秒读取超时 - RestTemplate restTemplate = new RestTemplate(factory); - ``` - -**注意事项**: -- 线程池要确保应用关闭时正确 shutdown(可以用 `@PreDestroy` 或在 Spring 的 `@Bean(destroyMethod="shutdown")`) -- 并发度不宜过高(3-5 即可),避免 Jackett 服务端限流 -- `searchSingleKeyword()` 和 `searchRecent()` 内部已有 try-catch,在 CompletableFuture 内还会继续 catch,注意异常不会自动传播到 `future.get()`,需要 `CompletableFuture` 的 `handle()` 或自行封装 - ---- - -### P2-1:文件按日期分片替代无限追加 - -**描述**:`ResourcesUtils.saveFile(content, wujiBaseDirectory, "hot")` 永远追加到同一个 `hot.txt`,文件无限增长。 - -**改动点**: - -1. **`JackettServiceImpl.dailyHot()`**:传入文件名时带上日期 - ```java - // ❌ 旧 - ResourcesUtils.saveFile(resultVO.getMagnetUri(), - jackettProperties.getWujiBaseDirectory(), "hot"); - - // ✅ 新:按日期分文件 - String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); - ResourcesUtils.saveFile(resultVO.getMagnetUri(), - jackettProperties.getWujiBaseDirectory(), "hot-" + dateStr); - ``` - 或按年月日三级目录: - ```java - String yyyy = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy")); - String MMdd = LocalDateTime.now().format(DateTimeFormatter.ofPattern("MM/dd")); - ResourcesUtils.saveFile(resultVO.getMagnetUri(), - jackettProperties.getWujiBaseDirectory() + "/" + yyyy + "/" + MMdd, "hot"); - ``` - -2. 或者如果决定改入库(推荐方案): - 在 `JavInfoDO` 中新增 `magnet_uri` 字段,在 `insertBatch` 时一并写入,完全替代文件存储。 - - 此时 `dailyHot()` 循环内去掉 `saveFile` 调用,`toInsert` 中设置 `magnetUri`。 - -**注意事项**: -- 如果选择入库替代文件,需要考虑 `JavInfoDO` 表结构变更和数据库 migration,改动量更大 -- 如果继续用文件,建议增加清理策略(如保留最近 30 天的文件,自动删除过期文件) - ---- - -### P2-2:日期过滤改为时间窗口 - -**描述**:当前用 `resultVO.getPublishDate().getYear() != currentYear` 过滤,语义是「当年发布」而非「最近发布」。跨年时段逻辑偏差明显。 - -**改动点**: - -**`JackettServiceImpl.dailyHot()`**:替换过滤条件 -```java -// ❌ 旧 -if (resultVO.getPublishDate() == null - || resultVO.getPublishDate().getYear() != currentYear) { - continue; -} - -// ✅ 新:最近 24 小时内发布 -LocalDateTime since = LocalDateTime.now().minusHours(24); -if (resultVO.getPublishDate() == null - || resultVO.getPublishDate().isBefore(since)) { - continue; -} -``` - -时间窗口大小建议外部化配置: -```yaml -jackett: - hot-window-hours: 24 -``` - ---- - -### P2-3:避免 Thread.sleep 阻塞 Quartz 线程 - -**描述**:`Thread.sleep(searchDelay)` 在 Quartz 的 `@DisallowConcurrentExecution` 工作线程中阻塞,无法处理其他 Job。 - -**改动点**: - -如果改用了 P1-2 的并发方案(CompletableFuture),线程池已经独立于 Quartz 线程,sleep 问题自然解决。如果暂时不改并发,至少: - -1. 将 `searchDelay` 从 sleep 改为使用 `ScheduledExecutorService` 调度 -2. 或者在并发方案中就解决了,不用额外改动 - -**推荐**:P1-2 的并发方案已经涵盖了这一条,不需要独立处理。 - ---- - -### P3-1:Redis Key 硬编码修复 - -**描述**:`saveRedisIds()` 中的 Redis key 硬编码为 `"\""jav:rank:2023"\""`,年份过时且带有多余引号。 - -**改动点**: - -**`JackettProperties.java`**:新增配置项 -```java -/** Redis 热门排名 Key */ -private String redisRankKey = "jav:rank"; -``` - -**`JackettServiceImpl.saveRedisIds()`**:改为使用配置 -```java -// ❌ 旧 -String key = "\""jav:rank:2023"\""; - -// ✅ 新 -String key = jackettProperties.getRedisRankKey(); -``` - -**`application.yml`**:添加配置 -```yaml -jackett: - redis-rank-key: "jav:rank:2026" # 或更通用 key -``` - ---- - -### P3-2:幂等性/中断支持 - -**描述**:Job 执行中断时,已 insert 的记录和已保存的文件产生不一致,下次执行产生重复数据。 - -**改动点**: - -1. **数据库层**:`JavInfoDO.jav_id` 加 UNIQUE 约束,`insertBatch` 使用 `INSERT IGNORE` → 幂等写入,重复自动跳过 - ```sql - ALTER TABLE wellness_jav_info ADD UNIQUE INDEX uk_jav_id (jav_id); - ``` - -2. **文件层**:按日期分片后(P2-1),同一天执行多次也是追加到同一个日期文件,仍然会重复。可以在写入前检查是否已存在: - ```java - // 方式 A:先读文件内容做 Set 去重(小文件可行,大文件低效) - // 方式 B:不管去重,反正按日期分片,运维定期清理即可 - ``` - -3. **「执行中标记」**:可选地在 Redis 中设置一个锁/标记,防止同一个 Job 实例并发(Quartz 的 `@DisallowConcurrentExecution` 已经解决了同一实例的并发,但多实例部署还需要确认) - ---- - -## 验收条件 - -| # | 验收项 | 验证方式 | -|---|--------|----------| -| 1 | 异常能被 Job 框架记录 | 手动使 FlareSolverr 不可用,观察 Job 日志面板显示失败状态 | -| 2 | 租户注解正确 | 多租户环境下执行 Job,确认没有错误的 `tenant_id` SQL | -| 3 | 数据库批量查询+插入 | 100+ hotIds 时,SQL 日志只出现一次 select 和一次 insert | -| 4 | 并发搜索 | 50 个新 ID 的搜索时间 ≤ 30s(之前 4+ 分钟) | -| 5 | 文件按日期分片 | 执行每天 Job 后,目录下生成 `hot-2026-04-26.txt` 格式文件,而非累加到一个文件 | -| 6 | 日期过滤正确 | 插入数据库的应该是最近 24h 发布的数据,而非整年数据 | -| 7 | Redis Key 可配置 | 修改 `application.yml` 中的 `jackett.redis-rank-key`,Job 读取新值 | -| 8 | 幂等性 | 同一批 hotIds 执行两次,数据库和文件不产生重复记录 | diff --git a/workspace-planner/tasks/dailyhot-job-review.md b/workspace-planner/tasks/dailyhot-job-review.md deleted file mode 100644 index 6becdd7..0000000 --- a/workspace-planner/tasks/dailyhot-job-review.md +++ /dev/null @@ -1,206 +0,0 @@ -# DailyHotJob 代码审查报告 - -> 审查目标:`DailyHotJob#execute()` + `JackettServiceImpl.dailyHot()` -> 审查时间:2026-04-25 -> 审查人:需求分析助手 - ---- - -## 1. 整体架构概览 - -``` -DailyHotJob.execute(param) - └─ JackettServiceImpl.dailyHot() - ├─ getDailyHotIds() → 爬取 wuji.me 获取 hot IDs - │ └─ getPageContent(url) → 通过 FlareSolverr 获取 HTML - ├─ 逐条 selectOne 查重 → 过滤已存在的 ID - ├─ 循环(逐条串行): - │ ├─ searchSingleKeyword() → 调用 Jackett API - │ ├─ 内存过滤(大小≥3G、当年发布) - │ ├─ ResourcesUtils.saveFile() → 追加写到 hot.txt - │ ├─ javInfoMapper.insert() → 逐条插入 - │ └─ Thread.sleep() → sleep 间隔 - └─ 结束 -``` - ---- - -## 2. 🔴 P0 严重问题 - -### 2.1 异常全被吞,Job 日志永远显示「成功」 - -`JobHandlerInvoker` 依赖 `exception != null` 判断 Job 是否执行成功: - -```java -// JobHandlerInvoker 的关键逻辑 -try { - data = this.executeInternal(jobHandlerName, jobHandlerParam); -} catch (Throwable ex) { - exception = ex; // 只有这里 exception 才非 null -} -``` - -但 `DailyHotJob.execute()` 和 `dailyHot()` 内的每一层都是: - -```java -// DailyHotJob -@Override -public String execute(String param) { - jackettService.dailyHot(); // 没有 throws,异常全在里面吞了 - return "每日热点"; // 永远返回正常字符串 -} - -// dailyHot() 内部 -for (...) { - try { - ... - } catch (Exception e) { - log.error("搜索 '{}' 时出错", javId, e.getMessage()); // 只打日志 - } -} -``` - -**后果**:即使远程 API 完全不可用、所有搜索全失败,Job 日志面板仍然显示「成功」。运维人员无法通过框架面板感知故障。 - -### 2.2 租户注解缺失问题 - -```java -@Override -@TenantIgnore // ← 只有最外层加了 -public void dailyHot() { ... } -``` - -`dailyHot()` 内部调用了 `this.getDailyHotIds()`、`this.getPageContent()`、`this.searchSingleKeyword()`,都是**内部方法调用**。 - -在 Spring AOP(JDK 动态代理)下,内部 `this.method()` 不会触发 `@TenantIgnore` 切面。如果 ruoyi 的租户 SQL 拦截器处于激活状态,可能导致这些方法执行时产生错误的 `WHERE tenant_id = ?` 过滤。 - -`saveRedisIds()` 方法也完全没加 `@TenantIgnore`,同样有风险。 - ---- - -## 3. 🟠 P1-P2 中等问题 - -### 3.1 N+1 数据库查询 + 逐条 insert - -```java -// N 次独立 selectOne -Set newIds = hotIds.stream() - .filter(javId -> javInfoMapper.selectOne(JavInfoDO::getJavId, javId) == null) - .collect(Collectors.toSet()); - -// M 次独立 insert -for (String javId : newIds) { - JavInfoDO javInfo = new JavInfoDO(); - javInfo.setJavId(javId); - javInfoMapper.insert(javInfo); // 逐条 -} -``` - -如果 hotIds 有 200 条,就是 200 次 select + 若干次 insert,数据库连接往返开销巨大。 - -**建议**:改为 `selectByJavIds(Collection)` 批量查重 + `insertBatch` 批量插入。 - -### 3.2 逐条串行远程搜索 + sleep 阻塞 - -```java -for (String javId : newIds) { - List results = searchSingleKeyword(javId, 30); - // 过滤... - Thread.sleep(jackettProperties.getSearchDelay()); // 通常 1-3s -} -``` - -假设只差 50 条新 ID,每次 search 耗时 3s + sleep 2s = 5s/条 → **总共 250 秒(4+ 分钟)**。如果匹配更多,耗时线性增长。 - -**建议**:使用并行流或 `CompletableFuture` 控制并发度(3-5),同时为 `RestTemplate` 配置连接/读取超时。 - -### 3.3 文件无限追加不轮转 - -```java -ResourcesUtils.saveFile(resultVO.getMagnetUri(), - jackettProperties.getWujiBaseDirectory(), "hot"); -``` - -每次都追加到同一个 `hot.txt`,永不清理。每天几十上百条磁力链接,一年后文件可能几十上百 MB,I/O 持续劣化。 - -**建议**:按日期分文件,如 `hot/2026-04-25.txt`;或改用数据库存储。 - -### 3.4 年度过滤器不符合「热点」语义 - -```java -if (resultVO.getPublishDate().getYear() != currentYear) { - continue; -} -``` - -如果今天是 2026-04-25,这个条件会接受 2026-01-01 到 2026-04-24 的所有结果,而不是「最近发布的结果」。 - -**建议**:改为 `isAfter(LocalDateTime.now().minusHours(N))` 时间窗口过滤。 - ---- - -## 4. 🟡 P3 潜在坑 - -### 4.1 Redis Key 硬编码且已过时 - -```java -String key = "\"jav:rank:2023\""; -``` - -- 2023 硬编码,距离现在已经 3 年 -- Key 带多余的双引号,实际可能是 `jav:rank:2023` -- 如果这是保存历史 ID 的入口,2023 早已不是有效数据源 - -### 4.2 非幂等 + 中断无保护 - -Job 执行到一半时应用关闭: -- 已插入的 `JavInfoDO` 已提交(无事务包裹) -- 已写入文件的磁力链已持久化 -- 下次执行时已入库的 ID 被跳过,但 `hot.txt` 用 APPEND 追加,**产生重复行** - -### 4.3 Redis 数据清洗掩盖上游 Bug - -```java -private String cleanString(String raw) { - // 去首尾引号 + 转义 - String cleaned = raw; - if (cleaned.startsWith("\"")) cleaned = cleaned.substring(1); - if (cleaned.endsWith("\"")) cleaned = cleaned.substring(0, cleaned.length() - 1); - cleaned = cleaned.replace("\\\"", "\""); - return cleaned.isEmpty() ? null : cleaned; -} -``` - -Redis 的 Set 中存储的值不应该带序列化引号或转义。出现这种情况说明**上游写入数据的方式有问题**。消费侧做清洗只是遮盖症状,不是根本解决。 - -### 4.4 `saveFile()` 两个重载路径冲突 - -```java -// 重载1(dailyHot 调用的) -saveFile(content, path, fileName) → Paths.get(path, fileName + ".txt") - -// 重载2 -saveFile(content, name) → dir = "/app/daily"; Paths.get(dir, name + ".txt") -``` - -重载2 硬编码了 `/app/daily`,如果其他调用方使用了这个重载但没有意识到路径硬编码,可能产生预期外的写入位置。 - -### 4.5 `Thread.sleep` 占用 Quartz 线程 - -`Thread.sleep` 是阻塞操作,在 Quartz 的工作线程中执行会让该线程无法处理其他 Job。虽然 `@DisallowConcurrentExecution` 避免了同 Job 并行,但如果 `JackettServiceImpl` 被多个 Job 共享,sleep 期间资源浪费更明显。 - ---- - -## 5. 改造建议优先级 - -| 优先级 | 问题 | 建议方案 | -|--------|------|----------| -| **P0** | 异常吞没,运维盲区 | `dailyHot()` 改为 `throws Exception`,仅捕获可恢复异常,向上传播不可恢复异常 | -| **P0** | 租户注解内部调用不生效 | 在 `getDailyHotIds()`、`searchSingleKeyword()`、`saveRedisIds()` 上也加 `@TenantIgnore` | -| **P1** | N+1 数据库操作 | 替换为 `selectByJavIds` 批量查重 + `insertBatch` 批量插入 | -| **P1** | 串行远程搜索过慢 | `CompletableFuture` 并发(并发度 3-5),配置 RestTemplate 超时(connect+read) | -| **P2** | 文件追加不轮转 | 按日期分文件:`hot/yyyy-MM-dd.txt` | -| **P2** | 年度过滤语义不对 | 改为最近 N 小时/天的时间窗口过滤 | -| **P2** | Thread.sleep 阻塞 | 使用 `ThreadPoolTaskScheduler` 或 `ScheduledThreadPoolExecutor` 提交异步任务 | -| **P3** | Redis Key 硬编码 | 提取为配置项 `wuji.redis-rank-key` | -| **P3** | 非幂等设计 | 改造为支持幂等(基于 jav_id 唯一约束的 `ON DUPLICATE KEY UPDATE`,文件去重写入) |