feat: add game library CRUD/import/export/favorites/comments, fix team creation
- Game library: add/delete games per group, JSON/CSV import/export, favorites, star ratings & comments - Fix team session creation: add creator to members array, handle null currentGroup - Fix image loading: rename SVG files from .png to .svg extensions - Add PocketBase migrations for game_comments and game_favorites collections - Remove seed data script Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((db) => {
|
||||
const collection = new Collection({
|
||||
"id": "4f73q31qelxycnu",
|
||||
"created": "2026-04-17 12:37:24.610Z",
|
||||
"updated": "2026-04-17 12:37:24.610Z",
|
||||
"name": "game_comments",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"system": false,
|
||||
"id": "gc_game",
|
||||
"name": "game",
|
||||
"type": "relation",
|
||||
"required": true,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "x5adjlc0txf16r8",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "gc_author",
|
||||
"name": "author",
|
||||
"type": "relation",
|
||||
"required": true,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "_pb_users_auth_",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "gc_content",
|
||||
"name": "content",
|
||||
"type": "text",
|
||||
"required": true,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": 1000,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "gc_rating",
|
||||
"name": "rating",
|
||||
"type": "number",
|
||||
"required": false,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"min": 1,
|
||||
"max": 5,
|
||||
"noDecimal": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"listRule": "@request.auth.id != \"\"",
|
||||
"viewRule": "@request.auth.id != \"\"",
|
||||
"createRule": "@request.auth.id != \"\"",
|
||||
"updateRule": null,
|
||||
"deleteRule": "author = @request.auth.id",
|
||||
"options": {}
|
||||
});
|
||||
|
||||
return Dao(db).saveCollection(collection);
|
||||
}, (db) => {
|
||||
const dao = new Dao(db);
|
||||
const collection = dao.findCollectionByNameOrId("4f73q31qelxycnu");
|
||||
|
||||
return dao.deleteCollection(collection);
|
||||
})
|
||||
@@ -0,0 +1,59 @@
|
||||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((db) => {
|
||||
const collection = new Collection({
|
||||
"id": "b7dbz8i2snrgw9g",
|
||||
"created": "2026-04-17 12:37:35.573Z",
|
||||
"updated": "2026-04-17 12:37:35.573Z",
|
||||
"name": "game_favorites",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"system": false,
|
||||
"id": "gf_game",
|
||||
"name": "game",
|
||||
"type": "relation",
|
||||
"required": true,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "x5adjlc0txf16r8",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"system": false,
|
||||
"id": "gf_user",
|
||||
"name": "user",
|
||||
"type": "relation",
|
||||
"required": true,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "_pb_users_auth_",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"listRule": "@request.auth.id != \"\"",
|
||||
"viewRule": "@request.auth.id != \"\"",
|
||||
"createRule": "@request.auth.id != \"\"",
|
||||
"updateRule": null,
|
||||
"deleteRule": "user = @request.auth.id",
|
||||
"options": {}
|
||||
});
|
||||
|
||||
return Dao(db).saveCollection(collection);
|
||||
}, (db) => {
|
||||
const dao = new Dao(db);
|
||||
const collection = dao.findCollectionByNameOrId("b7dbz8i2snrgw9g");
|
||||
|
||||
return dao.deleteCollection(collection);
|
||||
})
|
||||
@@ -0,0 +1,66 @@
|
||||
/// <reference path="../pb_data/types.d.ts" />
|
||||
migrate((db) => {
|
||||
const dao = new Dao(db)
|
||||
const collection = dao.findCollectionByNameOrId("x5adjlc0txf16r8")
|
||||
|
||||
collection.listRule = "group.owner = @request.auth.id || group.members.id = @request.auth.id"
|
||||
collection.viewRule = "group.owner = @request.auth.id || group.members.id = @request.auth.id"
|
||||
collection.createRule = "@request.auth.id != \"\""
|
||||
collection.updateRule = "group.owner = @request.auth.id || addedBy = @request.auth.id"
|
||||
collection.deleteRule = "group.owner = @request.auth.id || addedBy = @request.auth.id"
|
||||
|
||||
// add
|
||||
collection.schema.addField(new SchemaField({
|
||||
"system": false,
|
||||
"id": "sf_group",
|
||||
"name": "group",
|
||||
"type": "relation",
|
||||
"required": true,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "es63bkyiblpnxdf",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": null
|
||||
}
|
||||
}))
|
||||
|
||||
// add
|
||||
collection.schema.addField(new SchemaField({
|
||||
"system": false,
|
||||
"id": "sf_addedBy",
|
||||
"name": "addedBy",
|
||||
"type": "relation",
|
||||
"required": false,
|
||||
"presentable": false,
|
||||
"unique": false,
|
||||
"options": {
|
||||
"collectionId": "_pb_users_auth_",
|
||||
"cascadeDelete": false,
|
||||
"minSelect": null,
|
||||
"maxSelect": 1,
|
||||
"displayFields": null
|
||||
}
|
||||
}))
|
||||
|
||||
return dao.saveCollection(collection)
|
||||
}, (db) => {
|
||||
const dao = new Dao(db)
|
||||
const collection = dao.findCollectionByNameOrId("x5adjlc0txf16r8")
|
||||
|
||||
collection.listRule = "@request.auth.id != \"\""
|
||||
collection.viewRule = "@request.auth.id != \"\""
|
||||
collection.createRule = null
|
||||
collection.updateRule = null
|
||||
collection.deleteRule = null
|
||||
|
||||
// remove
|
||||
collection.schema.removeField("sf_group")
|
||||
|
||||
// remove
|
||||
collection.schema.removeField("sf_addedBy")
|
||||
|
||||
return dao.saveCollection(collection)
|
||||
})
|
||||
@@ -1,67 +0,0 @@
|
||||
#!/bin/bash
|
||||
# seed-games.sh - 批量导入热门游戏数据到 PocketBase
|
||||
set -e
|
||||
|
||||
PB_URL="${PB_URL:-http://192.168.1.14:8090}"
|
||||
ADMIN_EMAIL="${ADMIN_EMAIL:-admin@example.com}"
|
||||
ADMIN_PASS="${ADMIN_PASS:-admin123456}"
|
||||
|
||||
echo "获取管理员 Token..."
|
||||
TOKEN=$(curl -s -X POST "$PB_URL/api/admins/auth-with-password" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"identity\":\"$ADMIN_EMAIL\",\"password\":\"$ADMIN_PASS\"}" | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
|
||||
|
||||
echo "Token 获取成功,开始导入游戏..."
|
||||
|
||||
create_game() {
|
||||
local name="$1" platform="$2" tags="$3" count="$4"
|
||||
curl -s -X POST "$PB_URL/api/collections/games/records" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"name\":\"$name\",\"platform\":\"$platform\",\"tags\":$tags,\"popularCount\":$count}" | python3 -c "import sys,json; d=json.load(sys.stdin); print(f' ✓ {d.get(\"name\",\"ERROR\")}')"
|
||||
}
|
||||
|
||||
# PC 游戏
|
||||
create_game "League of Legends" "PC" '["MOBA","竞技","5v5"]' 10000
|
||||
create_game "Counter-Strike 2" "PC" '["FPS","射击","竞技"]' 9500
|
||||
create_game "Valorant" "PC" '["FPS","射击","战术"]' 9000
|
||||
create_game "Dota 2" "PC" '["MOBA","竞技","策略"]' 8500
|
||||
create_game "Apex Legends" "PC" '["FPS","大逃杀","吃鸡"]' 8000
|
||||
create_game "PUBG" "PC" '["大逃杀","吃鸡","射击"]' 7500
|
||||
create_game "Overwatch 2" "PC" '["FPS","英雄射击","团队"]' 7000
|
||||
create_game "Minecraft" "PC" '["沙盒","生存","建造"]' 6500
|
||||
create_game "Genshin Impact" "PC" '["RPG","开放世界","二次元"]' 6000
|
||||
create_game "Elden Ring" "PC" '["RPG","魂系","开放世界"]' 5500
|
||||
create_game "Teamfight Tactics" "PC" '["自走棋","策略","休闲"]' 5000
|
||||
create_game "Call of Duty: Warzone" "PC" '["FPS","大逃杀","射击"]' 4500
|
||||
create_game "Fortnite" "PC" '["大逃杀","建造","射击"]' 4000
|
||||
create_game "Dead by Daylight" "PC" '["恐怖","非对称","多人"]' 3500
|
||||
create_game "Among Us" "PC" '["社交","推理","休闲"]' 3000
|
||||
create_game "It Takes Two" "PC" '["合作","双人","冒险"]' 2500
|
||||
create_game "Baldurs Gate 3" "PC" '["RPG","回合制","合作"]' 2000
|
||||
|
||||
# PS5
|
||||
create_game "Helldivers 2" "PS5" '["射击","合作","PvE"]' 1800
|
||||
create_game "Final Fantasy XIV" "PS5" '["MMORPG","RPG","多人"]' 1500
|
||||
create_game "Spider-Man 2" "PS5" '["动作","冒险","开放世界"]' 1200
|
||||
create_game "God of War Ragnarok" "PS5" '["动作","冒险","单人"]' 1000
|
||||
|
||||
# Switch
|
||||
create_game "Mario Kart 8" "Switch" '["竞速","休闲","派对"]' 2000
|
||||
create_game "Zelda: TOTK" "Switch" '["冒险","开放世界","解谜"]' 1800
|
||||
create_game "Super Smash Bros" "Switch" '["格斗","派对","竞技"]' 1500
|
||||
create_game "Pokemon Scarlet" "Switch" '["RPG","收集","冒险"]' 1200
|
||||
|
||||
# Mobile
|
||||
create_game "Honor of Kings" "Mobile" '["MOBA","竞技","5v5"]' 9000
|
||||
create_game "PUBG Mobile" "Mobile" '["大逃杀","吃鸡","射击"]' 7000
|
||||
create_game "Genshin Impact" "Mobile" '["RPG","开放世界","二次元"]' 5500
|
||||
create_game "Call of Duty Mobile" "Mobile" '["FPS","射击","多人"]' 4000
|
||||
create_game "Arena of Valor" "Mobile" '["MOBA","竞技","5v5"]' 3000
|
||||
|
||||
# Xbox
|
||||
create_game "Halo Infinite" "Xbox" '["FPS","射击","竞技"]' 3000
|
||||
create_game "Forza Horizon 5" "Xbox" '["竞速","开放世界","休闲"]' 2500
|
||||
create_game "Starfield" "Xbox" '["RPG","开放世界","太空"]' 2000
|
||||
|
||||
echo "导入完成!"
|
||||
Reference in New Issue
Block a user