chore: 初始化仓库

中华文明全图鉴——文物全图系统(PC Web 地图 + NestJS API + 管理后台)。
含三大 IP(文物南迁北归 / 国宝海外回归 / 博物馆手艺人)、AI 文物对话、
文物地图与详情、以及 demo-video-kit 演示视频生成工具。
This commit is contained in:
selfrelease
2026-06-13 20:55:44 +08:00
commit 2d847e154f
161 changed files with 22629 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
// 把文物图片下载到本地(apps/web/public/artifacts),并把数据库 image_url 指向本地路径。
// 服务器直连不了 Wikimedia,但浏览器可以,所以用 Playwright 真实浏览器下载。
import { chromium } from "playwright";
import { Pool } from "pg";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const PUBLIC_DIR = path.resolve(__dirname, "../../apps/web/public/artifacts");
fs.mkdirSync(PUBLIC_DIR, { recursive: true });
const pool = new Pool({
connectionString:
process.env.DATABASE_URL ?? "postgresql://postgres@localhost:5432/wenwumap",
});
const extOf = (ct) =>
ct?.includes("png")
? "png"
: ct?.includes("svg")
? "svg"
: ct?.includes("webp")
? "webp"
: "jpg";
const main = async () => {
const { rows } = await pool.query(
"SELECT id, image_url FROM artifacts WHERE image_url LIKE 'http%' ORDER BY unified_map_id"
);
console.log(`待下载:${rows.length}`);
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage();
let ok = 0;
let failed = 0;
for (const { id, image_url } of rows) {
try {
const resp = await page.goto(image_url, { timeout: 30000, waitUntil: "commit" });
if (!resp || !resp.ok()) throw new Error(`HTTP ${resp ? resp.status() : "?"}`);
const ct = resp.headers()["content-type"] ?? "";
if (!ct.startsWith("image/")) throw new Error(`非图片:${ct}`);
const buf = await resp.body();
const ext = extOf(ct);
const file = `${id}.${ext}`;
fs.writeFileSync(path.join(PUBLIC_DIR, file), buf);
const localPath = `/artifacts/${file}`;
await pool.query("UPDATE artifacts SET image_url = $1 WHERE id = $2", [localPath, id]);
ok++;
console.log(`${id} -> ${localPath} (${(buf.length / 1024).toFixed(0)}KB)`);
} catch (e) {
failed++;
console.log(`${id} 失败:${e.message.split("\n")[0]}(保留原链接)`);
}
}
await browser.close();
await pool.end();
console.log(`完成:成功 ${ok},失败 ${failed}`);
};
main().catch((e) => {
console.error(e);
process.exit(1);
});
+225
View File
@@ -0,0 +1,225 @@
-- 启用 PostGIS 扩展
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS postgis;
-- 枚举类型
CREATE TYPE artifact_category AS ENUM (
'bronze','painting_calligraphy','porcelain','jade','gold_silver',
'lacquer','textile','stone_carving','wood_carving','dunhuang','ancient_book','other'
);
CREATE TYPE artifact_level AS ENUM ('level_1','level_2','level_3','general','unknown');
CREATE TYPE artifact_status AS ENUM ('at_home','away','in_transit','unknown');
CREATE TYPE location_type AS ENUM ('domestic','overseas','unknown','in_transit');
CREATE TYPE location_precision AS ENUM ('exact_room','exact_building','city','country','region');
CREATE TYPE display_status AS ENUM ('on_display','in_storage','loaned','repairing','touring','unknown');
CREATE TYPE source_type AS ENUM ('institution_feed','manual_entry','user_report','expert_verify','public_source');
CREATE TYPE publish_status AS ENUM ('draft','pending','published','archived','rejected');
CREATE TYPE tag_value_type AS ENUM ('single','multiple','boolean','text','number');
-- users
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
username VARCHAR(100) UNIQUE,
phone VARCHAR(30),
email VARCHAR(255),
password_hash VARCHAR(255),
nickname VARCHAR(100),
avatar_url TEXT,
user_type VARCHAR(30) NOT NULL DEFAULT 'public',
institution_id UUID,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- roles
CREATE TABLE roles (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(50) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- permissions
CREATE TABLE permissions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(100) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
module VARCHAR(50) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- user_roles
CREATE TABLE user_roles (
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role_id UUID NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
PRIMARY KEY (user_id, role_id)
);
-- institutions
CREATE TABLE institutions (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(255) NOT NULL,
short_name VARCHAR(100),
code VARCHAR(100) UNIQUE,
institution_type VARCHAR(50) NOT NULL DEFAULT 'museum',
country VARCHAR(100) NOT NULL DEFAULT '中国',
province VARCHAR(100),
city VARCHAR(100),
address TEXT,
location geography(Point, 4326),
official_website TEXT,
description TEXT,
is_verified BOOLEAN NOT NULL DEFAULT FALSE,
publish_status publish_status NOT NULL DEFAULT 'draft',
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_institutions_location_gist ON institutions USING GIST(location);
CREATE INDEX idx_institutions_name ON institutions(name);
CREATE INDEX idx_institutions_country_city ON institutions(country, city);
-- artifacts
CREATE TABLE artifacts (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
unified_map_id VARCHAR(50) UNIQUE,
name VARCHAR(255) NOT NULL,
alternative_names TEXT[] DEFAULT '{}',
category artifact_category NOT NULL DEFAULT 'other',
dynasty VARCHAR(100),
level artifact_level NOT NULL DEFAULT 'unknown',
material VARCHAR(255),
dimensions VARCHAR(255),
current_status artifact_status NOT NULL DEFAULT 'unknown',
home_institution_id UUID REFERENCES institutions(id),
summary TEXT,
story_hook VARCHAR(255),
persona_quote VARCHAR(255),
publish_status publish_status NOT NULL DEFAULT 'draft',
created_by UUID REFERENCES users(id),
updated_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_artifacts_name ON artifacts(name);
CREATE INDEX idx_artifacts_category ON artifacts(category);
CREATE INDEX idx_artifacts_dynasty ON artifacts(dynasty);
CREATE INDEX idx_artifacts_status ON artifacts(current_status);
CREATE INDEX idx_artifacts_home_institution ON artifacts(home_institution_id);
CREATE INDEX idx_artifacts_publish_status ON artifacts(publish_status);
-- artifact_locations
CREATE TABLE artifact_locations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
artifact_id UUID NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE,
location_type location_type NOT NULL DEFAULT 'unknown',
institution_id UUID REFERENCES institutions(id),
precise_location geography(Point, 4326),
public_location geography(Point, 4326),
fuzzy_area geography(Polygon, 4326),
precision location_precision NOT NULL DEFAULT 'city',
floor_plan_ref VARCHAR(255),
room_name VARCHAR(255),
cabinet_no VARCHAR(100),
display_status display_status NOT NULL DEFAULT 'unknown',
source_type source_type NOT NULL DEFAULT 'manual_entry',
source_description TEXT,
discoverer_user_id UUID REFERENCES users(id),
is_current BOOLEAN NOT NULL DEFAULT FALSE,
verified_at TIMESTAMPTZ,
valid_from TIMESTAMPTZ,
valid_until TIMESTAMPTZ,
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_artifact_locations_artifact_id ON artifact_locations(artifact_id);
CREATE INDEX idx_artifact_locations_institution_id ON artifact_locations(institution_id);
CREATE INDEX idx_artifact_locations_public_location_gist ON artifact_locations USING GIST(public_location);
CREATE INDEX idx_artifact_locations_precise_location_gist ON artifact_locations USING GIST(precise_location);
CREATE INDEX idx_artifact_locations_fuzzy_area_gist ON artifact_locations USING GIST(fuzzy_area);
CREATE INDEX idx_artifact_locations_current ON artifact_locations(artifact_id, is_current);
-- tag_categories
CREATE TABLE tag_categories (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(100) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
description TEXT,
sort_order INT NOT NULL DEFAULT 0,
is_system BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- tags
CREATE TABLE tags (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
category_id UUID NOT NULL REFERENCES tag_categories(id),
code VARCHAR(100) UNIQUE NOT NULL,
name VARCHAR(100) NOT NULL,
value_type tag_value_type NOT NULL DEFAULT 'single',
description TEXT,
color VARCHAR(20),
icon VARCHAR(100),
is_system BOOLEAN NOT NULL DEFAULT FALSE,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
sort_order INT NOT NULL DEFAULT 0,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- artifact_tags
CREATE TABLE artifact_tags (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
artifact_id UUID NOT NULL REFERENCES artifacts(id) ON DELETE CASCADE,
tag_id UUID NOT NULL REFERENCES tags(id),
value_text TEXT,
value_number NUMERIC,
confidence NUMERIC(5,2),
source_type source_type NOT NULL DEFAULT 'manual_entry',
review_status VARCHAR(30) NOT NULL DEFAULT 'approved',
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE UNIQUE INDEX idx_artifact_tags_unique ON artifact_tags(artifact_id, tag_id, COALESCE(value_text, ''));
CREATE INDEX idx_artifact_tags_artifact_id ON artifact_tags(artifact_id);
CREATE INDEX idx_artifact_tags_tag_id ON artifact_tags(tag_id);
-- digital_assets
CREATE TABLE digital_assets (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
artifact_id UUID REFERENCES artifacts(id) ON DELETE CASCADE,
institution_id UUID REFERENCES institutions(id),
asset_type VARCHAR(50) NOT NULL DEFAULT 'image',
title VARCHAR(255),
url TEXT NOT NULL,
thumbnail_url TEXT,
mime_type VARCHAR(100),
size_bytes BIGINT,
copyright_owner VARCHAR(255),
license_scope TEXT,
sort_order INT NOT NULL DEFAULT 0,
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_digital_assets_artifact_id ON digital_assets(artifact_id);
-- operation_logs
CREATE TABLE operation_logs (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
operator_id UUID REFERENCES users(id),
operator_role VARCHAR(50),
action VARCHAR(100) NOT NULL,
target_type VARCHAR(100) NOT NULL,
target_id UUID,
before_data JSONB,
after_data JSONB,
ip_address VARCHAR(50),
user_agent TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_operation_logs_operator_id ON operation_logs(operator_id);
CREATE INDEX idx_operation_logs_target ON operation_logs(target_type, target_id);
CREATE INDEX idx_operation_logs_created_at ON operation_logs(created_at DESC);
@@ -0,0 +1,2 @@
-- 为文物增加封面图字段(著名文物使用实拍图,其余前端用统一示意图占位)
ALTER TABLE artifacts ADD COLUMN IF NOT EXISTS image_url TEXT;
@@ -0,0 +1,28 @@
-- 三大 IP 支撑:文物回归状态 + 叙事路线(南迁之路 / 回归之路)
-- 回归状态:domestic 国内传承 / lost_overseas 流失海外 / repatriated 已回归 / in_transit 在途
ALTER TABLE artifacts ADD COLUMN IF NOT EXISTS repatriation_status VARCHAR(30) NOT NULL DEFAULT 'domestic';
-- 叙事路线(南迁、回归等)
CREATE TABLE IF NOT EXISTS narrative_routes (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
code VARCHAR(50) UNIQUE NOT NULL,
title VARCHAR(255) NOT NULL,
type VARCHAR(30) NOT NULL, -- migration(南迁)| repatriation(回归)
color VARCHAR(20),
summary TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 路线途经点(按 seq 顺序连线)
CREATE TABLE IF NOT EXISTS route_stops (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
route_id UUID NOT NULL REFERENCES narrative_routes(id) ON DELETE CASCADE,
seq INT NOT NULL,
name VARCHAR(255) NOT NULL,
lng DOUBLE PRECISION NOT NULL,
lat DOUBLE PRECISION NOT NULL,
year_label VARCHAR(50),
event TEXT
);
CREATE INDEX IF NOT EXISTS idx_route_stops_route ON route_stops(route_id, seq);
@@ -0,0 +1,2 @@
-- 回归路线与具体文物关联(每件回归国宝一条专属路线)
ALTER TABLE narrative_routes ADD COLUMN IF NOT EXISTS artifact_id UUID REFERENCES artifacts(id);
+21
View File
@@ -0,0 +1,21 @@
{
"name": "@wenwumap/db",
"version": "0.1.0",
"private": true,
"scripts": {
"migrate": "tsx src/migrate-cli.ts",
"seed": "tsx src/seed-cli.ts",
"images": "node download-images.mjs",
"type-check": "tsc --noEmit"
},
"dependencies": {
"dotenv": "^16.4.5",
"pg": "^8.12.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"@types/pg": "^8.11.6",
"tsx": "^4.22.4",
"typescript": "^5.5.3"
}
}
+76
View File
@@ -0,0 +1,76 @@
// 校对本地已下载的文物图片:识别真实图片类型、规范扩展名,并把 DB image_url 指向本地路径。
import { Pool } from "pg";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const PUBLIC_DIR = path.resolve(__dirname, "../../apps/web/public/artifacts");
const pool = new Pool({
connectionString:
process.env.DATABASE_URL ?? "postgresql://postgres@localhost:5432/wenwumap",
});
function detectExt(buf) {
if (buf.length < 12) return null;
if (buf[0] === 0xff && buf[1] === 0xd8) return "jpg";
if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) return "png";
if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46) return "gif";
if (buf.slice(0, 4).toString() === "RIFF" && buf.slice(8, 12).toString() === "WEBP") return "webp";
if (buf.slice(0, 5).toString().includes("<svg") || buf.slice(0, 5).toString().includes("<?xml")) return "svg";
return null;
}
const main = async () => {
if (!fs.existsSync(PUBLIC_DIR)) {
console.log("无本地图片目录");
return;
}
const files = fs.readdirSync(PUBLIC_DIR);
const { rows } = await pool.query(
"SELECT id, image_url FROM artifacts WHERE image_url IS NOT NULL ORDER BY unified_map_id"
);
let ok = 0;
let bad = 0;
for (const { id } of rows) {
const match = files.find((f) => f.startsWith(id));
if (!match) continue;
const full = path.join(PUBLIC_DIR, match);
const stat = fs.statSync(full);
if (stat.size < 1024) {
fs.rmSync(full);
bad++;
continue;
}
const buf = fs.readFileSync(full).subarray(0, 16);
const ext = detectExt(buf);
if (!ext) {
bad++;
console.log(`${id} 非有效图片,跳过`);
continue;
}
const desired = `${id}.${ext}`;
if (match !== desired) {
fs.renameSync(full, path.join(PUBLIC_DIR, desired));
// 清理同 id 其它残留
files
.filter((f) => f.startsWith(id) && f !== desired && f !== match)
.forEach((f) => fs.rmSync(path.join(PUBLIC_DIR, f), { force: true }));
}
await pool.query("UPDATE artifacts SET image_url = $1 WHERE id = $2", [
`/artifacts/${desired}`,
id,
]);
ok++;
console.log(`${id} -> /artifacts/${desired}`);
}
await pool.end();
console.log(`校对完成:本地化 ${ok},无效 ${bad}`);
};
main().catch((e) => {
console.error(e);
process.exit(1);
});
+7
View File
@@ -0,0 +1,7 @@
INSERT INTO roles (code, name, description) VALUES
('admin', '管理员', '全局管理、权限、审计、系统配置'),
('institution_user', '机构用户', '管理本机构文物、位置、标签、资产'),
('editor', '内容编辑', '管理故事、角色卡、标签、内容模板'),
('expert', '专家审核', '审核海外线索、校验史实'),
('public_user', '注册用户', '收藏、分享、纠错、海外线索提交')
ON CONFLICT (code) DO NOTHING;
+23
View File
@@ -0,0 +1,23 @@
INSERT INTO tag_categories (code, name, description, sort_order, is_system) VALUES
('basic_attribute', '基础属性', '门类、年代、级别、材质、功能、尺寸规模', 1, true),
('circulation_experience','流转经历', '流失状态、回归状态、南迁北归、修复、外借、争议事件', 2, true),
('emotional_attribute', '情感属性', '情绪主调、适合年龄、体验时长、互动类型', 3, true),
('content_derivation', '内容衍生标签', '触发故事、有声、研学、视频、3D 模板', 4, true)
ON CONFLICT (code) DO NOTHING;
INSERT INTO tags (category_id, code, name, value_type, is_system, sort_order) VALUES
((SELECT id FROM tag_categories WHERE code='basic_attribute'), 'category_tag', '门类', 'single', true, 1),
((SELECT id FROM tag_categories WHERE code='basic_attribute'), 'dynasty_tag', '年代', 'text', true, 2),
((SELECT id FROM tag_categories WHERE code='basic_attribute'), 'level_tag', '级别', 'single', true, 3),
((SELECT id FROM tag_categories WHERE code='basic_attribute'), 'material_tag', '材质', 'multiple', true, 4),
((SELECT id FROM tag_categories WHERE code='basic_attribute'), 'function_tag', '功能', 'multiple', true, 5),
((SELECT id FROM tag_categories WHERE code='circulation_experience'), 'lost_status_tag', '流失状态', 'single', true, 1),
((SELECT id FROM tag_categories WHERE code='circulation_experience'), 'return_status_tag','回归状态', 'single', true, 2),
((SELECT id FROM tag_categories WHERE code='circulation_experience'), 'south_migration', '南迁北归', 'boolean',true, 3),
((SELECT id FROM tag_categories WHERE code='circulation_experience'), 'repair_experience','修复经历', 'boolean',true, 4),
((SELECT id FROM tag_categories WHERE code='circulation_experience'), 'digitized', '数字化经历','boolean',true, 5),
((SELECT id FROM tag_categories WHERE code='emotional_attribute'), 'emotion_tone', '情绪主调', 'single', true, 1),
((SELECT id FROM tag_categories WHERE code='emotional_attribute'), 'suitable_age', '适合年龄', 'single', true, 2)
ON CONFLICT (code) DO NOTHING;
@@ -0,0 +1,24 @@
INSERT INTO institutions (id, name, short_name, institution_type, country, province, city, address,
location, is_verified, publish_status) VALUES
(
'a0000000-0000-0000-0000-000000000001',
'故宫博物院', '故宫', 'museum', '中国', '北京市', '北京',
'北京市东城区景山前街4号',
ST_SetSRID(ST_MakePoint(116.3972, 39.9163), 4326)::geography,
true, 'published'
),
(
'a0000000-0000-0000-0000-000000000002',
'国家博物馆', '国博', 'museum', '中国', '北京市', '北京',
'北京市东城区东长安街16号',
ST_SetSRID(ST_MakePoint(116.4074, 39.9052), 4326)::geography,
true, 'published'
),
(
'a0000000-0000-0000-0000-000000000003',
'上海博物馆', '上博', 'museum', '中国', '上海市', '上海',
'上海市黄浦区人民大道201号',
ST_SetSRID(ST_MakePoint(121.4737, 31.2293), 4326)::geography,
true, 'published'
)
ON CONFLICT (id) DO NOTHING;
+60
View File
@@ -0,0 +1,60 @@
INSERT INTO artifacts (id, unified_map_id, name, category, dynasty, level, material,
current_status, home_institution_id, summary, story_hook, persona_quote, publish_status)
VALUES
(
'b0000000-0000-0000-0000-000000000001',
'CN-2026-000001', '千里江山图', 'painting_calligraphy', '北宋', 'level_1',
'绢本设色', 'at_home',
'a0000000-0000-0000-0000-000000000001',
'北宋青年画家王希孟创作的青绿山水长卷,纵51.5厘米,横1191.5厘米。',
'18岁天才少年留下的唯一作品',
'我只画了一次,但你们看了一千年。',
'published'
),
(
'b0000000-0000-0000-0000-000000000002',
'CN-2026-000002', '清明上河图', 'painting_calligraphy', '北宋', 'level_1',
'绢本淡设色', 'at_home',
'a0000000-0000-0000-0000-000000000001',
'北宋画家张择端所作,生动记录了北宋都城汴京的繁华景象。',
'一幅画藏着整个北宋汴京的烟火气',
'画里每个人都有故事,你看懂了几个?',
'published'
),
(
'b0000000-0000-0000-0000-000000000003',
'CN-2026-000003', '司母戊鼎', 'bronze', '商代', 'level_1',
'青铜', 'at_home',
'a0000000-0000-0000-0000-000000000002',
'商王祖庚或祖甲为祭祀母亲戊而铸造,是迄今已发现的最重青铜器。',
'三千年前的青铜巨物,至今仍无人能复刻其铸造工艺',
'我沉了三千年,终于等到你来看我。',
'published'
)
ON CONFLICT (id) DO NOTHING;
INSERT INTO artifact_locations (id, artifact_id, location_type, institution_id,
public_location, precision, display_status, source_type, is_current, verified_at)
VALUES
(
'c0000000-0000-0000-0000-000000000001',
'b0000000-0000-0000-0000-000000000001',
'domestic', 'a0000000-0000-0000-0000-000000000001',
ST_SetSRID(ST_MakePoint(116.3972, 39.9163), 4326)::geography,
'exact_building', 'in_storage', 'institution_feed', true, NOW()
),
(
'c0000000-0000-0000-0000-000000000002',
'b0000000-0000-0000-0000-000000000002',
'domestic', 'a0000000-0000-0000-0000-000000000001',
ST_SetSRID(ST_MakePoint(116.3972, 39.9163), 4326)::geography,
'exact_building', 'on_display', 'institution_feed', true, NOW()
),
(
'c0000000-0000-0000-0000-000000000003',
'b0000000-0000-0000-0000-000000000003',
'domestic', 'a0000000-0000-0000-0000-000000000002',
ST_SetSRID(ST_MakePoint(116.4074, 39.9052), 4326)::geography,
'exact_building', 'on_display', 'institution_feed', true, NOW()
)
ON CONFLICT (id) DO NOTHING;
@@ -0,0 +1,14 @@
INSERT INTO institutions (id, name, short_name, institution_type, country, province, city, address, location, is_verified, publish_status) VALUES
('a0000000-0000-0000-0000-000000000004','陕西历史博物馆','陕历博','museum','中国','陕西省','西安','陕西省西安市雁塔区小寨东路91号',ST_SetSRID(ST_MakePoint(108.9398,34.3416),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000005','南京博物院','南博','museum','中国','江苏省','南京','江苏省南京市玄武区中山东路321号',ST_SetSRID(ST_MakePoint(118.7969,32.0603),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000006','浙江省博物馆','浙博','museum','中国','浙江省','杭州','浙江省杭州市西湖区孤山路25号',ST_SetSRID(ST_MakePoint(120.1551,30.2541),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000007','成都博物馆','成博','museum','中国','四川省','成都','四川省成都市青羊区小河街1号',ST_SetSRID(ST_MakePoint(104.0665,30.6623),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000008','湖北省博物馆','鄂博','museum','中国','湖北省','武汉','湖北省武汉市武昌区东湖路156号',ST_SetSRID(ST_MakePoint(114.3743,30.5531),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000009','湖南博物院','湘博','museum','中国','湖南省','长沙','湖南省长沙市开福区东风路50号',ST_SetSRID(ST_MakePoint(112.9838,28.2082),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000010','广东省博物馆','粤博','museum','中国','广东省','广州','广东省广州市天河区珠江新城珠江东路2号',ST_SetSRID(ST_MakePoint(113.3244,23.1191),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000011','甘肃省博物馆','甘博','museum','中国','甘肃省','兰州','甘肃省兰州市七里河区西津西路3号',ST_SetSRID(ST_MakePoint(103.7243,36.0611),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000012','敦煌研究院','敦煌','research_institute','中国','甘肃省','敦煌','甘肃省酒泉市敦煌市莫高窟',ST_SetSRID(ST_MakePoint(94.8065,40.0421),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000013','山西博物院','晋博','museum','中国','山西省','太原','山西省太原市万柏林区滨河西路13号',ST_SetSRID(ST_MakePoint(112.5089,37.8706),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000014','辽宁省博物馆','辽博','museum','中国','辽宁省','沈阳','辽宁省沈阳市浑南区智慧三街157号',ST_SetSRID(ST_MakePoint(123.5015,41.7557),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000015','台北故宫博物院','台北故宫','museum','中国','台湾省','台北','台湾省台北市士林区至善路二段221号',ST_SetSRID(ST_MakePoint(121.5484,25.1022),4326)::geography,true,'published')
ON CONFLICT (id) DO NOTHING;
+149
View File
@@ -0,0 +1,149 @@
DELETE FROM artifact_locations WHERE artifact_id IN (
'b0000000-0000-0000-0000-000000000004',
'b0000000-0000-0000-0000-000000000005',
'b0000000-0000-0000-0000-000000000006',
'b0000000-0000-0000-0000-000000000007',
'b0000000-0000-0000-0000-000000000008',
'b0000000-0000-0000-0000-000000000009',
'b0000000-0000-0000-0000-000000000010',
'b0000000-0000-0000-0000-000000000011',
'b0000000-0000-0000-0000-000000000012',
'b0000000-0000-0000-0000-000000000013',
'b0000000-0000-0000-0000-000000000014',
'b0000000-0000-0000-0000-000000000015',
'b0000000-0000-0000-0000-000000000016',
'b0000000-0000-0000-0000-000000000017',
'b0000000-0000-0000-0000-000000000018',
'b0000000-0000-0000-0000-000000000019',
'b0000000-0000-0000-0000-000000000020',
'b0000000-0000-0000-0000-000000000021',
'b0000000-0000-0000-0000-000000000022',
'b0000000-0000-0000-0000-000000000023',
'b0000000-0000-0000-0000-000000000024',
'b0000000-0000-0000-0000-000000000025',
'b0000000-0000-0000-0000-000000000026',
'b0000000-0000-0000-0000-000000000027',
'b0000000-0000-0000-0000-000000000028',
'b0000000-0000-0000-0000-000000000029',
'b0000000-0000-0000-0000-000000000030',
'b0000000-0000-0000-0000-000000000031',
'b0000000-0000-0000-0000-000000000032',
'b0000000-0000-0000-0000-000000000033',
'b0000000-0000-0000-0000-000000000034',
'b0000000-0000-0000-0000-000000000035',
'b0000000-0000-0000-0000-000000000036',
'b0000000-0000-0000-0000-000000000037',
'b0000000-0000-0000-0000-000000000038',
'b0000000-0000-0000-0000-000000000039',
'b0000000-0000-0000-0000-000000000040',
'b0000000-0000-0000-0000-000000000041',
'b0000000-0000-0000-0000-000000000042',
'b0000000-0000-0000-0000-000000000043',
'b0000000-0000-0000-0000-000000000044',
'b0000000-0000-0000-0000-000000000045',
'b0000000-0000-0000-0000-000000000046',
'b0000000-0000-0000-0000-000000000047',
'b0000000-0000-0000-0000-000000000048',
'b0000000-0000-0000-0000-000000000049',
'b0000000-0000-0000-0000-000000000050'
);
INSERT INTO artifacts (id,unified_map_id,name,category,dynasty,level,material,current_status,home_institution_id,summary,story_hook,persona_quote,publish_status) VALUES
('b0000000-0000-0000-0000-000000000004','CN-2026-000004','四羊方尊','bronze','商代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000002','商代晚期青铜礼器,以四羊造型闻名于世。','四只羊头托起的青铜奇迹','我身上有四只羊,但从未被吃掉。','published'),
('b0000000-0000-0000-0000-000000000005','CN-2026-000005','越王勾践剑','bronze','春秋','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000008','春秋晚期越国青铜剑,出土时仍锋利无比。','两千年后依然能吹毛断发','我躺在土里两千年,拔出来还能削苹果。','published'),
('b0000000-0000-0000-0000-000000000006','CN-2026-000006','曾侯乙编钟','bronze','战国','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000008','战国早期大型礼乐重器,全套64件,音域跨五个半八度。','一套钟就是整个交响乐团','敲我一下,你能听到战国的回声。','published'),
('b0000000-0000-0000-0000-000000000007','CN-2026-000007','铜车马','bronze','秦代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000004','秦始皇陵出土大型彩绘铜车马,按真实比例二分之一铸造。','始皇帝的御用车驾','我载着始皇帝,一站就是两千年。','published'),
('b0000000-0000-0000-0000-000000000008','CN-2026-000008','马踏飞燕','bronze','汉代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000011','东汉青铜器,奔马三足腾空、一足踏飞燕,展现极致动态平衡。','三足腾空,一脚踏风','我跑得太快,燕子都追不上我。','published'),
('b0000000-0000-0000-0000-000000000009','CN-2026-000009','素纱襌衣','textile','汉代','level_1','蚕丝','at_home','a0000000-0000-0000-0000-000000000009','西汉丝织衣物,重量仅49克,是迄今最薄最轻的古代服饰。','薄如蝉翼,轻若烟雾','我不到一两重,却裹住了整个汉代的温度。','published'),
('b0000000-0000-0000-0000-000000000010','CN-2026-000010','皿方罍','bronze','商代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000009','商代晚期青铜酒器,器盖与器身曾分藏两岸,2014年完罍归湘。','器盖分离九十年,一朝归湘','我的盖子在外漂泊了九十年,终于回家了。','published'),
('b0000000-0000-0000-0000-000000000011','CN-2026-000011','T形帛画','painting_calligraphy','汉代','level_1','','at_home','a0000000-0000-0000-0000-000000000009','马王堆一号汉墓出土,描绘天界、人间与冥界的宇宙图景。','两千年前的升天说明书','我铺在她的棺盖上,送她去另一个世界。','published'),
('b0000000-0000-0000-0000-000000000012','CN-2026-000012','大盂鼎','bronze','西周','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000002','西周早期青铜礼器,内壁铸有291字铭文,记录周王训诰。','内壁291字,是西周最早的法典','我肚子里的字,比现在的合同还严谨。','published'),
('b0000000-0000-0000-0000-000000000013','CN-2026-000013','虢季子白盘','bronze','西周','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000002','西周晚期青铜器,盘内底部铸有111字铭文,记录受赏史实。','一盘清水,洗尽三千年风尘','我曾是洗手盘,现在洗的是历史。','published'),
('b0000000-0000-0000-0000-000000000014','CN-2026-000014','莲鹤方壶','bronze','春秋','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000001','春秋中期青铜酒器,壶盖上立鹤展翅,被誉为春秋精神象征。','壶顶一只鹤,飞出了春秋的自由','我头顶的鹤,比孔子还早出生几十年。','published'),
('b0000000-0000-0000-0000-000000000015','CN-2026-000015','人物龙凤帛画','painting_calligraphy','战国','level_2','','at_home','a0000000-0000-0000-0000-000000000009','战国中晚期帛画,描绘墓主人在龙凤引导下升天的情景。','龙凤引路,走向战国的天界','龙凤接我去的地方,你们现在还想去。','published'),
('b0000000-0000-0000-0000-000000000016','CN-2026-000016','马王堆帛书医方','ancient_book','汉代','level_1','','at_home','a0000000-0000-0000-0000-000000000009','马王堆三号墓出土医学帛书,涵盖脉法、方剂、导引。','两千年前的中医处方','我的药方,比你们的体检报告还准。','published'),
('b0000000-0000-0000-0000-000000000017','CN-2026-000017','长信宫灯','bronze','汉代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000002','西汉青铜灯具,宫女跪坐持灯,灯罩可开合,极具环保理念。','两千年前的环保台灯','我手里这盏灯,照了两千年,还没烧完油。','published'),
('b0000000-0000-0000-0000-000000000018','CN-2026-000018','错金银云纹铜犀尊','bronze','汉代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000002','西汉青铜酒器,犀牛造型,全身错金银云纹,栩栩如生。','一只犀牛驮着西汉的云纹','我是一只犀牛,但我比真的犀牛还贵。','published'),
('b0000000-0000-0000-0000-000000000019','CN-2026-000019','击鼓说唱俑','other','汉代','level_2','','at_home','a0000000-0000-0000-0000-000000000002','东汉陶俑,艺人击鼓说唱的瞬间被凝固,神态诙谐生动。','两千年前的脱口秀演员','我说唱了两千年,票一直卖得很好。','published'),
('b0000000-0000-0000-0000-000000000020','CN-2026-000020','韩熙载夜宴图','painting_calligraphy','五代','level_1','绢本','at_home','a0000000-0000-0000-0000-000000000001','五代十国顾闳中绘,描绘南唐大臣韩熙载夜宴宾客的场景。','一场宴席,藏着亡国之君的猜忌','我画里的每个人,都在演一出戏。','published'),
('b0000000-0000-0000-0000-000000000021','CN-2026-000021','簪花仕女图','painting_calligraphy','唐代','level_1','绢本','at_home','a0000000-0000-0000-0000-000000000014','唐代周昉绘,描绘宫中贵妇簪花游园的闲适情景,人物丰腴。','大唐最美的女人都在这幅画里','她们比我胖,但比我贵多了。','published'),
('b0000000-0000-0000-0000-000000000022','CN-2026-000022','步辇图','painting_calligraphy','唐代','level_1','绢本','at_home','a0000000-0000-0000-0000-000000000001','唐代阎立本绘,记录吐蕃使者禄东赞朝见唐太宗的历史场景。','一次会面,奠定汉藏千年纽带','我见证了文成公主出嫁前的谈判。','published'),
('b0000000-0000-0000-0000-000000000023','CN-2026-000023','秋风纨扇图','painting_calligraphy','明代','level_2','纸本','at_home','a0000000-0000-0000-0000-000000000003','明代唐寅绘,以班婕妤秋扇见捐的典故,寄托文人失意情怀。','一把扇子扇出江南才子的失意','我被画在扇子上,却从没被打开过。','published'),
('b0000000-0000-0000-0000-000000000024','CN-2026-000024','溪山行旅图','painting_calligraphy','北宋','level_1','绢本','at_home','a0000000-0000-0000-0000-000000000015','北宋范宽绘,巨峰矗立、飞瀑直下,被誉为宋画第一。','一座山,撑起了整个北宋的气象','我画的山,比真的山还重。','published'),
('b0000000-0000-0000-0000-000000000025','CN-2026-000025','富春山居图','painting_calligraphy','元代','level_1','纸本','at_home','a0000000-0000-0000-0000-000000000006','元代黄公望绘,以富春江山水为题,被誉为山水画之冠。','一幅画,被火烧成了两半','我被火烧成两半,现在分居两岸。','published'),
('b0000000-0000-0000-0000-000000000026','CN-2026-000026','汉宫春晓图','painting_calligraphy','明代','level_1','绢本','at_home','a0000000-0000-0000-0000-000000000015','明代仇英绘,描绘初春时节汉宫嫔妃的生活场景,人物众多。','一场春晓,画尽后宫的繁华与寂寥','我画了一百多个女人,但没有一个是我的。','published'),
('b0000000-0000-0000-0000-000000000027','CN-2026-000027','寒食帖','painting_calligraphy','北宋','level_1','纸本','at_home','a0000000-0000-0000-0000-000000000015','北宋苏轼书,被誉为天下第三行书,书写被贬黄州的辛酸。','天下第三行书,写尽男人的委屈','我的字越丑,后人越觉得珍贵。','published'),
('b0000000-0000-0000-0000-000000000028','CN-2026-000028','汝窑天青釉洗','porcelain','北宋','level_1','','at_home','a0000000-0000-0000-0000-000000000015','北宋汝窑瓷器,釉色如雨后初晴的天空,存世不足百件。','雨过天青云破处,此般颜色','我烧坏了九百九十九个,才出了这一个。','published'),
('b0000000-0000-0000-0000-000000000029','CN-2026-000029','定窑白釉刻花盘','porcelain','北宋','level_2','','at_home','a0000000-0000-0000-0000-000000000003','北宋定窑瓷器,白釉刻花,线条流畅,被誉为白瓷之冠。','白瓷之冠,一刀一刻皆是风雅','我白得发光,但不是打了美白针。','published'),
('b0000000-0000-0000-0000-000000000030','CN-2026-000030','哥窑青釉鱼耳炉','porcelain','北宋','level_2','','at_home','a0000000-0000-0000-0000-000000000001','宋代哥窑瓷器,釉面布满金丝铁线开片,鱼耳造型典雅。','金丝铁线,是瓷器上的岁月皱纹','我身上的裂缝,比你们的皱纹还值钱。','published'),
('b0000000-0000-0000-0000-000000000031','CN-2026-000031','钧窑玫瑰紫釉花盆','porcelain','北宋','level_2','','at_home','a0000000-0000-0000-0000-000000000001','宋代钧窑瓷器,釉色如晚霞般绚烂,窑变天成,不可复制。','入窑一色,出窑万彩','我进窑时是素的,出来时就变了。','published'),
('b0000000-0000-0000-0000-000000000032','CN-2026-000032','青花萧何月下追韩信图梅瓶','porcelain','元代','level_1','','at_home','a0000000-0000-0000-0000-000000000005','元代青花瓷器,绘有萧何月下追韩信的历史故事,人物生动。','一个瓶子,装下了元代整段历史','我身上的画,比连环画还精彩。','published'),
('b0000000-0000-0000-0000-000000000033','CN-2026-000033','斗彩鸡缸杯','porcelain','明代','level_1','','at_home','a0000000-0000-0000-0000-000000000001','明成化斗彩瓷器,绘子母鸡图,小巧玲珑,为皇帝御用酒杯。','一个小杯子,拍卖价能买一栋楼','我只是一只杯子,但我比你的房子贵。','published'),
('b0000000-0000-0000-0000-000000000034','CN-2026-000034','各种釉彩大瓶','porcelain','清代','level_1','','at_home','a0000000-0000-0000-0000-000000000001','清乾隆瓷器,集历代釉彩于一身,工艺繁复,被称为瓷母。','集万千釉彩于一身,是乾隆的炫技','我身上有十七种釉彩,乾隆大概很闲。','published'),
('b0000000-0000-0000-0000-000000000035','CN-2026-000035','翠玉白菜','jade','清代','level_2','翠玉','at_home','a0000000-0000-0000-0000-000000000015','清代玉雕,利用翡翠天然色泽雕成白菜与昆虫,巧夺天工。','一棵白菜,雕出清宫最温润的时光','我是一棵白菜,但比真的白菜贵一百万倍。','published'),
('b0000000-0000-0000-0000-000000000036','CN-2026-000036','大禹治水图玉山','jade','清代','level_1','和田玉','at_home','a0000000-0000-0000-0000-000000000001','清代最大玉雕,重逾万斤,描绘禹王治水的壮观场景。','一座玉山,刻下了大禹治水的史诗','我重五吨,从新疆走了四年才到北京。','published'),
('b0000000-0000-0000-0000-000000000037','CN-2026-000037','红山文化玉龙','jade','新石器','level_1','岫玉','at_home','a0000000-0000-0000-0000-000000000002','红山文化玉龙,是目前所知形体最大、最完整的龙形玉器。','五千年前的第一条玉龙','我是最古老的龙,比秦朝还早四千年。','published'),
('b0000000-0000-0000-0000-000000000038','CN-2026-000038','金缕玉衣','jade','汉代','level_1','玉片金丝','at_home','a0000000-0000-0000-0000-000000000002','汉代王侯葬玉,以金丝编缀玉片而成,工程浩繁。','两千年前的金属盔甲','我穿在死人身上,但你们都想穿我。','published'),
('b0000000-0000-0000-0000-000000000039','CN-2026-000039','昭陵六骏石刻','stone_carving','唐代','level_1','','at_home','a0000000-0000-0000-0000-000000000004','唐太宗昭陵陵寝的六幅骏马浮雕,记录了征战生涯中的六匹战马。','六匹石马,驮着大唐的疆土','我们驮过李世民,现在只驮着历史。','published'),
('b0000000-0000-0000-0000-000000000040','CN-2026-000040','三星堆青铜大立人','bronze','商代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000007','三星堆出土,高262厘米,是世界上现存最高的青铜人像。','古蜀国的神王,手捧失传的神物','我站在这里三千年,等的就是你来问我。','published'),
('b0000000-0000-0000-0000-000000000041','CN-2026-000041','三星堆黄金面罩','gold_silver','商代','level_1','黄金','at_home','a0000000-0000-0000-0000-000000000007','三星堆出土的黄金面罩,包覆青铜人面像,工艺精湛神秘。','黄金面罩,遮住了古蜀国的秘密','我的脸是黄金做的,谁说不是神仙。','published'),
('b0000000-0000-0000-0000-000000000042','CN-2026-000042','金沙太阳神鸟金箔','gold_silver','商代','level_1','黄金','at_home','a0000000-0000-0000-0000-000000000007','金沙遗址出土,四只神鸟围绕太阳飞翔,已成为中国文化遗产标志。','中国文化遗产的标志图案','我已经飞了三千年,还没有累。','published'),
('b0000000-0000-0000-0000-000000000043','CN-2026-000043','法门寺地宫金银器','gold_silver','唐代','level_1','金银','at_home','a0000000-0000-0000-0000-000000000004','法门寺地宫出土的唐代金银器群,见证了皇室供奉佛骨的礼制。','大唐皇室最虔诚的供奉','我埋在地下一千年,替大唐祈过福。','published'),
('b0000000-0000-0000-0000-000000000044','CN-2026-000044','海昏侯刘贺金饼','gold_silver','汉代','level_2','黄金','at_home','a0000000-0000-0000-0000-000000000002','海昏侯墓出土的汉代金饼,是西汉皇室财富的实物见证。','一个皇帝的黄金零花钱','我只是刘贺的零花钱,但比你的房产证值钱。','published'),
('b0000000-0000-0000-0000-000000000045','CN-2026-000045','永乐大典残卷','ancient_book','明代','level_1','','at_home','a0000000-0000-0000-0000-000000000002','明代大型类书,成祖朱棣敕修,原书22877卷,现仅存约400卷。','史上最大的百科全书','我原来有两万多卷,现在只剩下四百来卷。','published'),
('b0000000-0000-0000-0000-000000000046','CN-2026-000046','敦煌飞天壁画','dunhuang','唐代','level_1','矿物颜料','at_home','a0000000-0000-0000-0000-000000000012','莫高窟唐代壁画,飞天形象优美,是敦煌艺术的最高代表。','千年飞天,永远在空中飞翔','我飞了一千三百年,从来没有落地。','published'),
('b0000000-0000-0000-0000-000000000047','CN-2026-000047','莫高窟彩塑菩萨像','dunhuang','唐代','level_1','彩泥','at_home','a0000000-0000-0000-0000-000000000012','莫高窟唐代彩塑,菩萨神态慈悲,色彩历经千年仍鲜艳。','千年彩塑,慈悲永驻','我微笑了一千年,笑容从未褪色。','published'),
('b0000000-0000-0000-0000-000000000048','CN-2026-000048','南越王玉角杯','jade','汉代','level_1','','at_home','a0000000-0000-0000-0000-000000000010','南越王墓出土的玉雕角杯,是目前发现最大的汉代玉杯。','南越王的玉制酒杯','我是南越王喝酒的杯子,但从未被喝脏过。','published'),
('b0000000-0000-0000-0000-000000000049','CN-2026-000049','晋祠宋代彩塑侍女像','stone_carving','北宋','level_1','彩泥','at_home','a0000000-0000-0000-0000-000000000013','山西晋祠宋代彩塑群,侍女像神态各异、栩栩如生。','宋代最美的侍女群像','我们站在这里一千年,从来没有累过。','published'),
('b0000000-0000-0000-0000-000000000050','CN-2026-000050','秦始皇陵铠甲俑','other','秦代','level_1','','at_home','a0000000-0000-0000-0000-000000000004','秦始皇陵出土的铠甲陶俑,工艺精细,甲片清晰可数。','始皇帝的百万雄师','我是始皇帝的士兵,从来没有退过一步。','published')
ON CONFLICT (id) DO NOTHING;
INSERT INTO artifact_locations (id,artifact_id,location_type,institution_id,public_location,precision,display_status,source_type,is_current,verified_at) VALUES
('c0000000-0000-0000-0000-000000000004','b0000000-0000-0000-0000-000000000004','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000005','b0000000-0000-0000-0000-000000000005','domestic','a0000000-0000-0000-0000-000000000008',ST_SetSRID(ST_MakePoint(114.3743,30.5531),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000006','b0000000-0000-0000-0000-000000000006','domestic','a0000000-0000-0000-0000-000000000008',ST_SetSRID(ST_MakePoint(114.3743,30.5531),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000007','b0000000-0000-0000-0000-000000000007','domestic','a0000000-0000-0000-0000-000000000004',ST_SetSRID(ST_MakePoint(108.9398,34.3416),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000008','b0000000-0000-0000-0000-000000000008','domestic','a0000000-0000-0000-0000-000000000011',ST_SetSRID(ST_MakePoint(103.7243,36.0611),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000009','b0000000-0000-0000-0000-000000000009','domestic','a0000000-0000-0000-0000-000000000009',ST_SetSRID(ST_MakePoint(112.9838,28.2082),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000010','b0000000-0000-0000-0000-000000000010','domestic','a0000000-0000-0000-0000-000000000009',ST_SetSRID(ST_MakePoint(112.9838,28.2082),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000011','b0000000-0000-0000-0000-000000000011','domestic','a0000000-0000-0000-0000-000000000009',ST_SetSRID(ST_MakePoint(112.9838,28.2082),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000012','b0000000-0000-0000-0000-000000000012','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000013','b0000000-0000-0000-0000-000000000013','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000014','b0000000-0000-0000-0000-000000000014','domestic','a0000000-0000-0000-0000-000000000001',ST_SetSRID(ST_MakePoint(116.3972,39.9163),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000015','b0000000-0000-0000-0000-000000000015','domestic','a0000000-0000-0000-0000-000000000009',ST_SetSRID(ST_MakePoint(112.9838,28.2082),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000016','b0000000-0000-0000-0000-000000000016','domestic','a0000000-0000-0000-0000-000000000009',ST_SetSRID(ST_MakePoint(112.9838,28.2082),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000017','b0000000-0000-0000-0000-000000000017','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000018','b0000000-0000-0000-0000-000000000018','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000019','b0000000-0000-0000-0000-000000000019','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000020','b0000000-0000-0000-0000-000000000020','domestic','a0000000-0000-0000-0000-000000000001',ST_SetSRID(ST_MakePoint(116.3972,39.9163),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000021','b0000000-0000-0000-0000-000000000021','domestic','a0000000-0000-0000-0000-000000000014',ST_SetSRID(ST_MakePoint(123.5015,41.7557),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000022','b0000000-0000-0000-0000-000000000022','domestic','a0000000-0000-0000-0000-000000000001',ST_SetSRID(ST_MakePoint(116.3972,39.9163),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000023','b0000000-0000-0000-0000-000000000023','domestic','a0000000-0000-0000-0000-000000000003',ST_SetSRID(ST_MakePoint(121.4737,31.2293),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000024','b0000000-0000-0000-0000-000000000024','domestic','a0000000-0000-0000-0000-000000000015',ST_SetSRID(ST_MakePoint(121.5484,25.1022),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000025','b0000000-0000-0000-0000-000000000025','domestic','a0000000-0000-0000-0000-000000000006',ST_SetSRID(ST_MakePoint(120.1551,30.2541),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000026','b0000000-0000-0000-0000-000000000026','domestic','a0000000-0000-0000-0000-000000000015',ST_SetSRID(ST_MakePoint(121.5484,25.1022),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000027','b0000000-0000-0000-0000-000000000027','domestic','a0000000-0000-0000-0000-000000000015',ST_SetSRID(ST_MakePoint(121.5484,25.1022),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000028','b0000000-0000-0000-0000-000000000028','domestic','a0000000-0000-0000-0000-000000000015',ST_SetSRID(ST_MakePoint(121.5484,25.1022),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000029','b0000000-0000-0000-0000-000000000029','domestic','a0000000-0000-0000-0000-000000000003',ST_SetSRID(ST_MakePoint(121.4737,31.2293),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000030','b0000000-0000-0000-0000-000000000030','domestic','a0000000-0000-0000-0000-000000000001',ST_SetSRID(ST_MakePoint(116.3972,39.9163),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000031','b0000000-0000-0000-0000-000000000031','domestic','a0000000-0000-0000-0000-000000000001',ST_SetSRID(ST_MakePoint(116.3972,39.9163),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000032','b0000000-0000-0000-0000-000000000032','domestic','a0000000-0000-0000-0000-000000000005',ST_SetSRID(ST_MakePoint(118.7969,32.0603),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000033','b0000000-0000-0000-0000-000000000033','domestic','a0000000-0000-0000-0000-000000000001',ST_SetSRID(ST_MakePoint(116.3972,39.9163),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000034','b0000000-0000-0000-0000-000000000034','domestic','a0000000-0000-0000-0000-000000000001',ST_SetSRID(ST_MakePoint(116.3972,39.9163),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000035','b0000000-0000-0000-0000-000000000035','domestic','a0000000-0000-0000-0000-000000000015',ST_SetSRID(ST_MakePoint(121.5484,25.1022),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000036','b0000000-0000-0000-0000-000000000036','domestic','a0000000-0000-0000-0000-000000000001',ST_SetSRID(ST_MakePoint(116.3972,39.9163),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000037','b0000000-0000-0000-0000-000000000037','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000038','b0000000-0000-0000-0000-000000000038','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000039','b0000000-0000-0000-0000-000000000039','domestic','a0000000-0000-0000-0000-000000000004',ST_SetSRID(ST_MakePoint(108.9398,34.3416),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000040','b0000000-0000-0000-0000-000000000040','domestic','a0000000-0000-0000-0000-000000000007',ST_SetSRID(ST_MakePoint(104.0665,30.6623),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000041','b0000000-0000-0000-0000-000000000041','domestic','a0000000-0000-0000-0000-000000000007',ST_SetSRID(ST_MakePoint(104.0665,30.6623),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000042','b0000000-0000-0000-0000-000000000042','domestic','a0000000-0000-0000-0000-000000000007',ST_SetSRID(ST_MakePoint(104.0665,30.6623),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000043','b0000000-0000-0000-0000-000000000043','domestic','a0000000-0000-0000-0000-000000000004',ST_SetSRID(ST_MakePoint(108.9398,34.3416),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000044','b0000000-0000-0000-0000-000000000044','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000045','b0000000-0000-0000-0000-000000000045','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000046','b0000000-0000-0000-0000-000000000046','domestic','a0000000-0000-0000-0000-000000000012',ST_SetSRID(ST_MakePoint(94.8065,40.0421),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000047','b0000000-0000-0000-0000-000000000047','domestic','a0000000-0000-0000-0000-000000000012',ST_SetSRID(ST_MakePoint(94.8065,40.0421),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000048','b0000000-0000-0000-0000-000000000048','domestic','a0000000-0000-0000-0000-000000000010',ST_SetSRID(ST_MakePoint(113.3244,23.1191),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000049','b0000000-0000-0000-0000-000000000049','domestic','a0000000-0000-0000-0000-000000000013',ST_SetSRID(ST_MakePoint(112.5089,37.8706),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000050','b0000000-0000-0000-0000-000000000050','domestic','a0000000-0000-0000-0000-000000000004',ST_SetSRID(ST_MakePoint(108.9398,34.3416),4326)::geography,'exact_building','on_display','institution_feed',true,NOW())
ON CONFLICT (id) DO NOTHING;
+115
View File
@@ -0,0 +1,115 @@
-- 大英博物馆(British Museum)及其所藏中国文物(流失海外)
-- 机构 ID: a0000000-...-000000000016
-- 文物 ID: b0000000-...-000000000051 ~ 000000000057
-- 位置 ID: c0000000-...-000000000051 ~ 000000000057
-- 幂等:先清理本批位置数据
DELETE FROM artifact_locations WHERE artifact_id IN (
'b0000000-0000-0000-0000-000000000051',
'b0000000-0000-0000-0000-000000000052',
'b0000000-0000-0000-0000-000000000053',
'b0000000-0000-0000-0000-000000000054',
'b0000000-0000-0000-0000-000000000055',
'b0000000-0000-0000-0000-000000000056',
'b0000000-0000-0000-0000-000000000057'
);
-- 机构:大英博物馆(伦敦)
INSERT INTO institutions (id, name, short_name, institution_type, country, province, city, address, location, is_verified, publish_status) VALUES
(
'a0000000-0000-0000-0000-000000000016',
'大英博物馆', '大英博物馆', 'museum', '英国', '大伦敦', '伦敦',
'Great Russell St, London WC1B 3DG, United Kingdom',
ST_SetSRID(ST_MakePoint(-0.1270, 51.5194), 4326)::geography,
true, 'published'
)
ON CONFLICT (id) DO NOTHING;
-- 文物(current_status = 'away' 表示流失海外)
INSERT INTO artifacts (id, unified_map_id, name, category, dynasty, level, material,
current_status, home_institution_id, summary, story_hook, persona_quote, publish_status)
VALUES
(
'b0000000-0000-0000-0000-000000000051',
'GB-2026-000001', '女史箴图(唐摹本)', 'painting_calligraphy', '唐代', 'level_1',
'绢本设色', 'away',
'a0000000-0000-0000-0000-000000000016',
'东晋顾恺之《女史箴图》现存最早摹本,唐代摹绘,是中国早期人物画的巅峰之作,1900年后流入大英博物馆。',
'中国绘画的“祖本”,却躺在异国的展柜里',
'我画的是宫廷的规矩,如今却被规矩地裱在伦敦。',
'published'
),
(
'b0000000-0000-0000-0000-000000000052',
'GB-2026-000002', '敦煌《金刚经》', 'ancient_book', '唐代', 'level_1',
'纸本雕版印刷', 'away',
'a0000000-0000-0000-0000-000000000016',
'公元868年雕版印刷,是世界上现存最早的有明确纪年的印刷书籍,出自敦煌藏经洞,由斯坦因带走。',
'世界上第一本有“出版日期”的印刷书',
'我比古登堡早了近六百年,却离家万里。',
'published'
),
(
'b0000000-0000-0000-0000-000000000053',
'GB-2026-000003', '大维德花瓶(元青花云龙纹象耳瓶)', 'porcelain', '元代', 'level_1',
'青花瓷', 'away',
'a0000000-0000-0000-0000-000000000016',
'至正十一年(1351年)烧制的一对元青花象耳瓶,带有确切纪年题记,是元青花断代的标准器,属大维德爵士旧藏。',
'一对花瓶,重写了整部元青花的历史',
'我身上的那行字,定义了什么叫“真正的元青花”。',
'published'
),
(
'b0000000-0000-0000-0000-000000000054',
'GB-2026-000004', '康侯簋', 'bronze', '西周', 'level_1',
'青铜', 'away',
'a0000000-0000-0000-0000-000000000016',
'西周早期青铜礼器,内壁铸有铭文,记录周王封康侯于卫的史实,是研究西周分封制度的重要实物。',
'一件青铜器,记下了周王分封诸侯的瞬间',
'我肚子里的铭文,是三千年前的一纸任命书。',
'published'
),
(
'b0000000-0000-0000-0000-000000000055',
'GB-2026-000005', '敦煌引路菩萨图', 'dunhuang', '唐代', 'level_1',
'绢本设色', 'away',
'a0000000-0000-0000-0000-000000000016',
'唐末五代敦煌绢画,描绘引路菩萨手持幡幢引导亡灵往生净土,色彩富丽,出自莫高窟藏经洞。',
'一位菩萨,提着灯笼为亡魂引路',
'我本该在莫高窟为人引路,如今却在异乡迷了路。',
'published'
),
(
'b0000000-0000-0000-0000-000000000056',
'GB-2026-000006', '邢窑白釉双龙耳瓶', 'porcelain', '唐代', 'level_2',
'白釉瓷', 'away',
'a0000000-0000-0000-0000-000000000016',
'唐代邢窑白瓷代表作,器型饱满、釉色洁白,双龙耳衔口,体现“南青北白”中北方白瓷的最高水准。',
'“类银类雪”的大唐白瓷',
'我白得像雪,却被收在伦敦灰蒙蒙的天空下。',
'published'
),
(
'b0000000-0000-0000-0000-000000000057',
'GB-2026-000007', '辽三彩罗汉像', 'stone_carving', '五代', 'level_1',
'三彩陶', 'away',
'a0000000-0000-0000-0000-000000000016',
'河北易县出土的等身三彩罗汉坐像之一,面容写实、神态沉静,是中国古代雕塑写实主义的巅峰,约二十世纪初流散海外。',
'一尊会“呼吸”的罗汉,流落四海',
'我打坐了千年,睁眼时却已不在故土。',
'published'
)
ON CONFLICT (id) DO NOTHING;
-- 位置(location_type = 'overseas',坐标为大英博物馆)
INSERT INTO artifact_locations (id, artifact_id, location_type, institution_id,
public_location, precision, display_status, source_type, is_current, verified_at)
VALUES
('c0000000-0000-0000-0000-000000000051','b0000000-0000-0000-0000-000000000051','overseas','a0000000-0000-0000-0000-000000000016',ST_SetSRID(ST_MakePoint(-0.1270,51.5194),4326)::geography,'exact_building','in_storage','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000052','b0000000-0000-0000-0000-000000000052','overseas','a0000000-0000-0000-0000-000000000016',ST_SetSRID(ST_MakePoint(-0.1270,51.5194),4326)::geography,'exact_building','in_storage','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000053','b0000000-0000-0000-0000-000000000053','overseas','a0000000-0000-0000-0000-000000000016',ST_SetSRID(ST_MakePoint(-0.1270,51.5194),4326)::geography,'exact_building','on_display','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000054','b0000000-0000-0000-0000-000000000054','overseas','a0000000-0000-0000-0000-000000000016',ST_SetSRID(ST_MakePoint(-0.1270,51.5194),4326)::geography,'exact_building','on_display','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000055','b0000000-0000-0000-0000-000000000055','overseas','a0000000-0000-0000-0000-000000000016',ST_SetSRID(ST_MakePoint(-0.1270,51.5194),4326)::geography,'exact_building','in_storage','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000056','b0000000-0000-0000-0000-000000000056','overseas','a0000000-0000-0000-0000-000000000016',ST_SetSRID(ST_MakePoint(-0.1270,51.5194),4326)::geography,'exact_building','on_display','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000057','b0000000-0000-0000-0000-000000000057','overseas','a0000000-0000-0000-0000-000000000016',ST_SetSRID(ST_MakePoint(-0.1270,51.5194),4326)::geography,'exact_building','on_display','public_source',true,NOW())
ON CONFLICT (id) DO NOTHING;
+19
View File
@@ -0,0 +1,19 @@
-- 扩充地区:新增 10 个国内省市机构 + 4 个海外机构
-- 机构 ID: a0000000-...-000000000017 ~ 000000000030
INSERT INTO institutions (id, name, short_name, institution_type, country, province, city, address, location, is_verified, publish_status) VALUES
('a0000000-0000-0000-0000-000000000017','河南博物院','豫博','museum','中国','河南省','郑州','河南省郑州市金水区农业路8号',ST_SetSRID(ST_MakePoint(113.6766,34.7657),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000018','重庆中国三峡博物馆','三峡博','museum','中国','重庆市','重庆','重庆市渝中区人民路236号',ST_SetSRID(ST_MakePoint(106.5516,29.5647),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000019','新疆维吾尔自治区博物馆','新疆博','museum','中国','新疆维吾尔自治区','乌鲁木齐','新疆乌鲁木齐市沙依巴克区西北路581号',ST_SetSRID(ST_MakePoint(87.6005,43.8256),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000020','西藏博物馆','藏博','museum','中国','西藏自治区','拉萨','西藏拉萨市城关区罗布林卡路19号',ST_SetSRID(ST_MakePoint(91.1145,29.6500),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000021','内蒙古博物院','蒙博','museum','中国','内蒙古自治区','呼和浩特','内蒙古呼和浩特市新城区新华东街27号',ST_SetSRID(ST_MakePoint(111.7519,40.8516),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000022','山东博物馆','鲁博','museum','中国','山东省','济南','山东省济南市历下区经十路11899号',ST_SetSRID(ST_MakePoint(117.0790,36.6740),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000023','福建博物院','闽博','museum','中国','福建省','福州','福建省福州市鼓楼区湖头街96号',ST_SetSRID(ST_MakePoint(119.3100,26.0960),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000024','安徽博物院','皖博','museum','中国','安徽省','合肥','安徽省合肥市蜀山区怀宁路268号',ST_SetSRID(ST_MakePoint(117.2460,31.8669),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000025','黑龙江省博物馆','龙博','museum','中国','黑龙江省','哈尔滨','黑龙江省哈尔滨市南岗区红军街50号',ST_SetSRID(ST_MakePoint(126.6300,45.7600),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000026','云南省博物馆','滇博','museum','中国','云南省','昆明','云南省昆明市官渡区广福路6393号',ST_SetSRID(ST_MakePoint(102.8330,24.8800),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000027','大都会艺术博物馆','大都会','museum','美国','纽约州','纽约','1000 5th Ave, New York, NY 10028, USA',ST_SetSRID(ST_MakePoint(-73.9632,40.7794),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000028','卢浮宫','卢浮宫','museum','法国','法兰西岛','巴黎','Rue de Rivoli, 75001 Paris, France',ST_SetSRID(ST_MakePoint(2.3376,48.8606),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000029','东京国立博物馆','东博','museum','日本','东京都','东京','〒110-8712 東京都台東区上野公園13-9',ST_SetSRID(ST_MakePoint(139.7760,35.7188),4326)::geography,true,'published'),
('a0000000-0000-0000-0000-000000000030','弗利尔美术馆','弗利尔','museum','美国','华盛顿特区','华盛顿','Jefferson Dr at 12th St SW, Washington, DC 20560, USA',ST_SetSRID(ST_MakePoint(-77.0277,38.8880),4326)::geography,true,'published')
ON CONFLICT (id) DO NOTHING;
+81
View File
@@ -0,0 +1,81 @@
-- 扩充文物数量:新增 26 件文物(覆盖新地区 + 海外馆藏),并为著名文物设置实拍封面图
-- 文物 ID: b0000000-...-000000000058 ~ 000000000083
DELETE FROM artifact_locations WHERE artifact_id IN (
'b0000000-0000-0000-0000-000000000058','b0000000-0000-0000-0000-000000000059','b0000000-0000-0000-0000-000000000060',
'b0000000-0000-0000-0000-000000000061','b0000000-0000-0000-0000-000000000062','b0000000-0000-0000-0000-000000000063',
'b0000000-0000-0000-0000-000000000064','b0000000-0000-0000-0000-000000000065','b0000000-0000-0000-0000-000000000066',
'b0000000-0000-0000-0000-000000000067','b0000000-0000-0000-0000-000000000068','b0000000-0000-0000-0000-000000000069',
'b0000000-0000-0000-0000-000000000070','b0000000-0000-0000-0000-000000000071','b0000000-0000-0000-0000-000000000072',
'b0000000-0000-0000-0000-000000000073','b0000000-0000-0000-0000-000000000074','b0000000-0000-0000-0000-000000000075',
'b0000000-0000-0000-0000-000000000076','b0000000-0000-0000-0000-000000000077','b0000000-0000-0000-0000-000000000078',
'b0000000-0000-0000-0000-000000000079','b0000000-0000-0000-0000-000000000080','b0000000-0000-0000-0000-000000000081',
'b0000000-0000-0000-0000-000000000082','b0000000-0000-0000-0000-000000000083'
);
INSERT INTO artifacts (id,unified_map_id,name,category,dynasty,level,material,current_status,home_institution_id,summary,story_hook,persona_quote,publish_status) VALUES
('b0000000-0000-0000-0000-000000000058','CN-2026-000058','妇好鸮尊','bronze','商代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000017','商代王后妇好墓出土的青铜酒器,作猫头鹰造型,威武又憨态可掬。','中国最早女将军的萌系战神','我是猫头鹰,但我替一位女将军守了三千年。','published'),
('b0000000-0000-0000-0000-000000000059','CN-2026-000059','云纹铜禁','bronze','春秋','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000017','春秋时期失蜡法铸造的青铜禁,镂空云纹繁复,是中国最早的失蜡法实物之一。','两千多年前的“3D打印”青铜器','我身上的云纹,是古人用蜡一点点失出来的。','published'),
('b0000000-0000-0000-0000-000000000060','CN-2026-000060','贾湖骨笛','other','新石器','level_1','鹤骨','at_home','a0000000-0000-0000-0000-000000000017','距今约8000年的七孔骨笛,用鹤类尺骨制成,是世界上最早可吹奏的乐器之一。','八千年前的一缕笛声','我用一只仙鹤的腿骨,吹响了华夏第一支旋律。','published'),
('b0000000-0000-0000-0000-000000000061','CN-2026-000061','乌杨汉阙','stone_carving','汉代','level_1','','at_home','a0000000-0000-0000-0000-000000000018','东汉时期的双子母石阙,是目前保存最完整的汉阙之一,堪称汉代建筑的活化石。','屹立两千年的汉代“石头大门”','我是一道门,门后的人早已离去,我却还守着。','published'),
('b0000000-0000-0000-0000-000000000062','CN-2026-000062','五星出东方利中国锦护臂','textile','汉代','level_1','蜀锦','at_home','a0000000-0000-0000-0000-000000000019','尼雅遗址出土的汉代织锦护臂,织有“五星出东方利中国”八字,被誉为20世纪中国考古最重要发现之一。','一块织锦上写着穿越千年的祝福','我身上八个字,等了两千年才被你们读懂。','published'),
('b0000000-0000-0000-0000-000000000063','CN-2026-000063','伏羲女娲图','painting_calligraphy','唐代','level_2','绢本','at_home','a0000000-0000-0000-0000-000000000019','吐鲁番阿斯塔那墓出土的唐代绢画,描绘伏羲女娲交尾、手持规矩,象征天地秩序。','一幅画里藏着中国版的“创世神话”','我们手里的规和矩,丈量着整个天地。','published'),
('b0000000-0000-0000-0000-000000000064','CN-2026-000064','卡若文化双体陶罐','other','新石器','level_1','','at_home','a0000000-0000-0000-0000-000000000020','西藏昌都卡若遗址出土的双体陶罐,造型奇特对称,是史前高原文明的代表作。','雪域高原上最早的陶器杰作','我站在世界屋脊,烧成于四五千年前的篝火旁。','published'),
('b0000000-0000-0000-0000-000000000065','CN-2026-000065','匈奴鹰顶金冠饰','gold_silver','战国','level_1','黄金','at_home','a0000000-0000-0000-0000-000000000021','内蒙古鄂尔多斯出土的战国匈奴金冠,顶立展翅雄鹰,是目前唯一的匈奴贵族金冠。','草原之王头顶的黄金雄鹰','我是匈奴单于的王冠,鹰在我顶上俯瞰草原。','published'),
('b0000000-0000-0000-0000-000000000066','CN-2026-000066','蛋壳黑陶高柄杯','other','新石器','level_1','黑陶','at_home','a0000000-0000-0000-0000-000000000022','龙山文化黑陶杯,器壁薄如蛋壳,最薄处不足0.2毫米,代表史前制陶巅峰。','四千年前薄如蛋壳的“黑科技”','我薄得能透光,却比你们的瓷杯早了两千年。','published'),
('b0000000-0000-0000-0000-000000000067','CN-2026-000067','鲁国大玉璧','jade','战国','level_1','','at_home','a0000000-0000-0000-0000-000000000022','战国时期鲁国玉璧,直径逾30厘米,是目前战国玉璧中最大的一件。','战国第一大玉璧','我是一轮玉做的圆月,照过整个战国。','published'),
('b0000000-0000-0000-0000-000000000068','CN-2026-000068','德化窑白釉观音坐像','porcelain','明代','level_1','白瓷','at_home','a0000000-0000-0000-0000-000000000023','明代何朝宗制德化白瓷观音,釉色温润如象牙,被誉为“中国白”的极致。','被称作“中国白”的温润之美','我白得像凝脂,连观音的衣褶都在流动。','published'),
('b0000000-0000-0000-0000-000000000069','CN-2026-000069','铸客大鼎','bronze','战国','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000024','战国楚国青铜圆鼎,重逾400公斤,是已知东周时期最大最重的青铜圆鼎。','楚国的“天下第一大鼎”','我是楚人的重器,扛起过一个王国的体面。','published'),
('b0000000-0000-0000-0000-000000000070','CN-2026-000070','金代铜坐龙','bronze','金代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000025','金上京遗址出土的铜坐龙,集龙、麒麟、狮、犬于一身,是金代皇室的御用饰件。','女真王朝的“四不像”神龙','我坐着不动,却镇住了大金王朝的气运。','published'),
('b0000000-0000-0000-0000-000000000071','CN-2026-000071','牛虎铜案','bronze','战国','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000026','古滇国青铜祭祀礼器,大牛背负案面、腹下立小牛、尾端猛虎咬噬,构思奇绝。','一头牛背上的生死博弈','我是一头牛,背上摆祭品,身后还咬着一只虎。','published'),
('b0000000-0000-0000-0000-000000000072','CN-2026-000072','四牛鎏金骑士铜贮贝器','bronze','汉代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000026','西汉古滇国储存海贝的礼器,盖上立四牛与鎏金骑士,记录滇人社会风貌。','古滇人的“黄金存钱罐”','我肚子里装的是海贝,那是滇国人的钱。','published'),
('b0000000-0000-0000-0000-000000000073','CN-2026-000073','药师经变壁画','dunhuang','元代','level_1','壁画','away','a0000000-0000-0000-0000-000000000027','原属山西广胜寺的元代巨幅壁画,二十世纪二十年代被整体剥离售出,现存大都会艺术博物馆。','一整面元代古寺的墙,漂洋过海','我本是一面庙墙,如今挂在异国的展厅里。','published'),
('b0000000-0000-0000-0000-000000000074','CN-2026-000074','唐代石雕菩萨立像','stone_carving','唐代','level_1','','away','a0000000-0000-0000-0000-000000000027','唐代汉白玉菩萨立像,体态丰腴、衣纹流畅,二十世纪初流散海外,现藏大都会。','盛唐的雍容,留在了纽约','我曾立在古寺的佛龛里,如今面对的是异乡的人潮。','published'),
('b0000000-0000-0000-0000-000000000075','CN-2026-000075','清乾隆粉彩镂空瓶','porcelain','清代','level_2','粉彩瓷','away','a0000000-0000-0000-0000-000000000028','清乾隆景德镇粉彩镂空转心瓶,工艺繁复华美,现藏巴黎卢浮宫东方艺术收藏。','乾隆的炫技之作,落在塞纳河畔','我转起来时,整个乾隆盛世都在旋转。','published'),
('b0000000-0000-0000-0000-000000000076','CN-2026-000076','潇湘卧游图','painting_calligraphy','南宋','level_1','纸本','away','a0000000-0000-0000-0000-000000000029','南宋李氏所作山水长卷,被视为南宋文人画典范,现藏东京国立博物馆,列为日本国宝。','南宋文人的卧游山水,藏在东京','我是一卷可以躺着神游的山水,却游到了海的另一边。','published'),
('b0000000-0000-0000-0000-000000000077','CN-2026-000077','红白芙蓉图','painting_calligraphy','南宋','level_1','绢本','away','a0000000-0000-0000-0000-000000000029','南宋画家李迪所绘花卉双幅,设色精妙,被列为日本国宝,现藏东京国立博物馆。','南宋画院最娇艳的两朵芙蓉','我开在南宋的绢上,被人小心地呵护了八百年。','published'),
('b0000000-0000-0000-0000-000000000078','CN-2026-000078','洛神赋图(宋摹本)','painting_calligraphy','东晋','level_1','绢本','away','a0000000-0000-0000-0000-000000000030','顾恺之《洛神赋图》宋代摹本,描绘曹植与洛神的浪漫相遇,现藏华盛顿弗利尔美术馆。','一段人神之恋,画在了千年绢上','我画的是一场注定别离的相遇,如今也漂泊在外。','published'),
('b0000000-0000-0000-0000-000000000079','CN-2026-000079','三星堆青铜神树','bronze','商代','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000007','三星堆出土青铜神树,高近4米,枝头立神鸟,被视为古蜀人沟通天地的“通天神树”。','古蜀人通往天界的青铜天梯','我是一棵青铜的树,枝头停着古蜀人的太阳鸟。','published'),
('b0000000-0000-0000-0000-000000000080','CN-2026-000080','良渚玉琮王','jade','新石器','level_1','','at_home','a0000000-0000-0000-0000-000000000006','良渚文化玉琮之王,重达6.5公斤,刻有精细神人兽面纹,是良渚文明的最高象征。','五千年前玉上的“神徽”密码','我外方内圆,刻着良渚先民心中的神。','published'),
('b0000000-0000-0000-0000-000000000081','CN-2026-000081','鎏金舞马衔杯纹银壶','gold_silver','唐代','level_1','银鎏金','at_home','a0000000-0000-0000-0000-000000000004','唐代何家村窖藏出土银壶,壶身錾刻衔杯舞马,印证了唐玄宗舞马祝寿的盛景。','一匹会跳舞、会敬酒的大唐骏马','我身上的马儿衔着酒杯,为唐明皇贺寿起舞。','published'),
('b0000000-0000-0000-0000-000000000082','CN-2026-000082','葡萄花鸟纹银香囊','gold_silver','唐代','level_2','','at_home','a0000000-0000-0000-0000-000000000004','唐代何家村出土银香囊,内置陀螺仪式平衡环,无论如何转动香盂始终水平不洒。','一千年前的“陀螺仪”黑科技','我怎么滚动,里面的香都不会洒出来。','published'),
('b0000000-0000-0000-0000-000000000083','CN-2026-000083','妇好玉凤','jade','商代','level_2','','at_home','a0000000-0000-0000-0000-000000000002','妇好墓出土的商代玉凤,是目前所见最早的玉凤造型之一,线条灵动飘逸。','三千年前飞起的第一只玉凤','我是最早的那只凤,比所有传说都要老。','published')
ON CONFLICT (id) DO NOTHING;
INSERT INTO artifact_locations (id,artifact_id,location_type,institution_id,public_location,precision,display_status,source_type,is_current,verified_at) VALUES
('c0000000-0000-0000-0000-000000000058','b0000000-0000-0000-0000-000000000058','domestic','a0000000-0000-0000-0000-000000000017',ST_SetSRID(ST_MakePoint(113.6766,34.7657),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000059','b0000000-0000-0000-0000-000000000059','domestic','a0000000-0000-0000-0000-000000000017',ST_SetSRID(ST_MakePoint(113.6766,34.7657),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000060','b0000000-0000-0000-0000-000000000060','domestic','a0000000-0000-0000-0000-000000000017',ST_SetSRID(ST_MakePoint(113.6766,34.7657),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000061','b0000000-0000-0000-0000-000000000061','domestic','a0000000-0000-0000-0000-000000000018',ST_SetSRID(ST_MakePoint(106.5516,29.5647),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000062','b0000000-0000-0000-0000-000000000062','domestic','a0000000-0000-0000-0000-000000000019',ST_SetSRID(ST_MakePoint(87.6005,43.8256),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000063','b0000000-0000-0000-0000-000000000063','domestic','a0000000-0000-0000-0000-000000000019',ST_SetSRID(ST_MakePoint(87.6005,43.8256),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000064','b0000000-0000-0000-0000-000000000064','domestic','a0000000-0000-0000-0000-000000000020',ST_SetSRID(ST_MakePoint(91.1145,29.6500),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000065','b0000000-0000-0000-0000-000000000065','domestic','a0000000-0000-0000-0000-000000000021',ST_SetSRID(ST_MakePoint(111.7519,40.8516),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000066','b0000000-0000-0000-0000-000000000066','domestic','a0000000-0000-0000-0000-000000000022',ST_SetSRID(ST_MakePoint(117.0790,36.6740),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000067','b0000000-0000-0000-0000-000000000067','domestic','a0000000-0000-0000-0000-000000000022',ST_SetSRID(ST_MakePoint(117.0790,36.6740),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000068','b0000000-0000-0000-0000-000000000068','domestic','a0000000-0000-0000-0000-000000000023',ST_SetSRID(ST_MakePoint(119.3100,26.0960),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000069','b0000000-0000-0000-0000-000000000069','domestic','a0000000-0000-0000-0000-000000000024',ST_SetSRID(ST_MakePoint(117.2460,31.8669),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000070','b0000000-0000-0000-0000-000000000070','domestic','a0000000-0000-0000-0000-000000000025',ST_SetSRID(ST_MakePoint(126.6300,45.7600),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000071','b0000000-0000-0000-0000-000000000071','domestic','a0000000-0000-0000-0000-000000000026',ST_SetSRID(ST_MakePoint(102.8330,24.8800),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000072','b0000000-0000-0000-0000-000000000072','domestic','a0000000-0000-0000-0000-000000000026',ST_SetSRID(ST_MakePoint(102.8330,24.8800),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000073','b0000000-0000-0000-0000-000000000073','overseas','a0000000-0000-0000-0000-000000000027',ST_SetSRID(ST_MakePoint(-73.9632,40.7794),4326)::geography,'exact_building','on_display','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000074','b0000000-0000-0000-0000-000000000074','overseas','a0000000-0000-0000-0000-000000000027',ST_SetSRID(ST_MakePoint(-73.9632,40.7794),4326)::geography,'exact_building','on_display','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000075','b0000000-0000-0000-0000-000000000075','overseas','a0000000-0000-0000-0000-000000000028',ST_SetSRID(ST_MakePoint(2.3376,48.8606),4326)::geography,'exact_building','on_display','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000076','b0000000-0000-0000-0000-000000000076','overseas','a0000000-0000-0000-0000-000000000029',ST_SetSRID(ST_MakePoint(139.7760,35.7188),4326)::geography,'exact_building','in_storage','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000077','b0000000-0000-0000-0000-000000000077','overseas','a0000000-0000-0000-0000-000000000029',ST_SetSRID(ST_MakePoint(139.7760,35.7188),4326)::geography,'exact_building','in_storage','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000078','b0000000-0000-0000-0000-000000000078','overseas','a0000000-0000-0000-0000-000000000030',ST_SetSRID(ST_MakePoint(-77.0277,38.8880),4326)::geography,'exact_building','in_storage','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000079','b0000000-0000-0000-0000-000000000079','domestic','a0000000-0000-0000-0000-000000000007',ST_SetSRID(ST_MakePoint(104.0665,30.6623),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000080','b0000000-0000-0000-0000-000000000080','domestic','a0000000-0000-0000-0000-000000000006',ST_SetSRID(ST_MakePoint(120.1551,30.2541),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000081','b0000000-0000-0000-0000-000000000081','domestic','a0000000-0000-0000-0000-000000000004',ST_SetSRID(ST_MakePoint(108.9398,34.3416),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000082','b0000000-0000-0000-0000-000000000082','domestic','a0000000-0000-0000-0000-000000000004',ST_SetSRID(ST_MakePoint(108.9398,34.3416),4326)::geography,'exact_building','on_display','institution_feed',true,NOW()),
('c0000000-0000-0000-0000-000000000083','b0000000-0000-0000-0000-000000000083','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','institution_feed',true,NOW())
ON CONFLICT (id) DO NOTHING;
-- 为著名文物设置实拍封面图(Wikimedia Commons 公有领域,前端加载失败时自动回退到统一示意图)
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Along_the_River_During_the_Qingming_Festival_%28Qing_Court_Version%29.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000002';
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Houmuwu_ding.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000003';
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Flying_Horse_of_Gansu.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000008';
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Changxin_Palace_Lamp.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000017';
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Jadeite_Cabbage.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000035';
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Gu_Kaizhi_002.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000051';
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/David_Vases.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000053';
+12
View File
@@ -0,0 +1,12 @@
-- 为更多著名文物补充封面图(Wikimedia Commons 公有领域,best-effort
-- 经由后端图片代理加载,文件名不存在时前端自动回退到统一示意图)
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Dwelling_in_the_Fuchun_Mountains.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000025' AND image_url IS NULL;
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Sword_of_Goujian.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000005' AND image_url IS NULL;
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Bianzhong_of_Marquis_Yi_of_Zeng.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000006' AND image_url IS NULL;
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Four_sheep_square_zun.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000004' AND image_url IS NULL;
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Hongshan_Jade_Dragon.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000037' AND image_url IS NULL;
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Bronze_Standing_Figure_Sanxingdui.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000040' AND image_url IS NULL;
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Golden_Sun_Bird.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000042' AND image_url IS NULL;
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Jade_burial_suit.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000038' AND image_url IS NULL;
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Lianhefanghu.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000014' AND image_url IS NULL;
UPDATE artifacts SET image_url = 'https://commons.wikimedia.org/wiki/Special:FilePath/Terracotta_Army.jpg?width=1200' WHERE id = 'b0000000-0000-0000-0000-000000000050' AND image_url IS NULL;
+19
View File
@@ -0,0 +1,19 @@
-- 文物本地图片路径(图片文件位于 apps/web/public/artifacts/,由 download/reconcile 脚本生成)
-- 本 seed 在 009/010 之后执行,将 image_url 覆盖为本地路径
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000002.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000002';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000003.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000003';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000004.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000004';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000005.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000005';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000006.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000006';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000008.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000008';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000014.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000014';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000017.png' WHERE id = 'b0000000-0000-0000-0000-000000000017';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000025.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000025';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000035.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000035';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000037.png' WHERE id = 'b0000000-0000-0000-0000-000000000037';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000038.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000038';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000040.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000040';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000042.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000042';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000050.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000050';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000051.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000051';
UPDATE artifacts SET image_url = '/artifacts/b0000000-0000-0000-0000-000000000053.jpg' WHERE id = 'b0000000-0000-0000-0000-000000000053';
+41
View File
@@ -0,0 +1,41 @@
-- 三大 IP 数据(示意性 MVP 数据)
-- 1) 回归状态
-- 海外机构(大英 016、大都会 027、卢浮宫 028、东博 029、弗利尔 030)所藏 → 流失海外
UPDATE artifacts SET repatriation_status = 'lost_overseas'
WHERE id IN (
SELECT a.id FROM artifacts a
JOIN artifact_locations al ON a.id = al.artifact_id AND al.is_current = true
WHERE al.location_type = 'overseas'
);
-- 已回归代表:皿方罍(b...010,2014 完罍归湘)
UPDATE artifacts SET repatriation_status = 'repatriated' WHERE id = 'b0000000-0000-0000-0000-000000000010';
-- 2) 叙事路线:故宫文物南迁之路(migration)
DELETE FROM route_stops WHERE route_id IN (SELECT id FROM narrative_routes WHERE code IN ('nanqian','huigui'));
DELETE FROM narrative_routes WHERE code IN ('nanqian','huigui');
INSERT INTO narrative_routes (id, code, title, type, color, summary) VALUES
('d0000000-0000-0000-0000-000000000001','nanqian','故宫文物南迁之路','migration','#e0b15a',
'1933—1947 年,故宫等机构为避战火,将上万箱文物分路南迁、西迁,辗转上海、南京、宝鸡、汉中、成都、峨眉、重庆等地,行程逾万里,历经十余年,国宝几无损失,被誉为人类文明守护史上的奇迹。'),
('d0000000-0000-0000-0000-000000000002','huigui','国宝回归之路','repatriation','#3f9e6a',
'从流失海外到重返故土——以皿方罍为代表,器身与器盖分离近一个世纪,2014 年器盖由海外回归、与器身在湖南合体,"完罍归湘",成为国宝回归的标志性事件。')
ON CONFLICT (code) DO NOTHING;
INSERT INTO route_stops (route_id, seq, name, lng, lat, year_label, event) VALUES
('d0000000-0000-0000-0000-000000000001',1,'北京·紫禁城',116.3972,39.9163,'1933','13427 箱文物分批南迁起运'),
('d0000000-0000-0000-0000-000000000001',2,'上海',121.4737,31.2293,'1933—1936','暂存法租界与天主堂街库房'),
('d0000000-0000-0000-0000-000000000001',3,'南京·朝天宫',118.7780,32.0300,'1936—1937','迁入朝天宫库房,旋因战事再迁'),
('d0000000-0000-0000-0000-000000000001',4,'宝鸡',107.1444,34.3693,'1937—1938','北路西迁,翻越秦岭'),
('d0000000-0000-0000-0000-000000000001',5,'汉中',107.0238,33.0678,'1938','转运途中遭遇空袭与塌方'),
('d0000000-0000-0000-0000-000000000001',6,'成都',104.0665,30.6623,'1938','中路文物暂存'),
('d0000000-0000-0000-0000-000000000001',7,'峨眉',103.4844,29.6010,'1939—1946','南路文物存于峨眉,安然度过战火'),
('d0000000-0000-0000-0000-000000000001',8,'重庆',106.5516,29.5647,'1938—1946','中路文物存于巴县、乐山一带'),
('d0000000-0000-0000-0000-000000000001',9,'南京(回迁)',118.7780,32.0300,'1947','抗战胜利后文物东归南京');
INSERT INTO route_stops (route_id, seq, name, lng, lat, year_label, event) VALUES
('d0000000-0000-0000-0000-000000000002',1,'海外(流失)',2.3376,48.8606,'1920s','器盖流散海外,辗转于私人藏家与拍卖行'),
('d0000000-0000-0000-0000-000000000002',2,'纽约',-73.9632,40.7794,'2014','现身纽约拍卖,国内多方紧急斡旋'),
('d0000000-0000-0000-0000-000000000002',3,'香港',114.1694,22.3193,'2014','达成洽购协议,护送入境'),
('d0000000-0000-0000-0000-000000000002',4,'北京',116.4074,39.9052,'2014','回归交接仪式'),
('d0000000-0000-0000-0000-000000000002',5,'长沙·湖南博物院',112.9838,28.2082,'2014','器身器盖合体,完罍归湘');
+80
View File
@@ -0,0 +1,80 @@
-- 国宝回归(每件文物一条专属回归路线)+ 南迁北归改名
-- 1) 南迁路线改名为「文物南迁北归之路」
UPDATE narrative_routes SET title = '文物南迁北归之路' WHERE code = 'nanqian';
-- 2) 新增机构:保利艺术博物馆(北京)
INSERT INTO institutions (id, name, short_name, institution_type, country, province, city, address, location, is_verified, publish_status) VALUES
('a0000000-0000-0000-0000-000000000031','保利艺术博物馆','保利博物馆','museum','中国','北京市','北京','北京市东城区东直门内大街朝阳门北大街1号新保利大厦',ST_SetSRID(ST_MakePoint(116.4340,39.9380),4326)::geography,true,'published')
ON CONFLICT (id) DO NOTHING;
-- 3) 新增回归国宝文物
DELETE FROM artifact_locations WHERE artifact_id IN (
'b0000000-0000-0000-0000-000000000084','b0000000-0000-0000-0000-000000000085',
'b0000000-0000-0000-0000-000000000086','b0000000-0000-0000-0000-000000000087'
);
INSERT INTO artifacts (id,unified_map_id,name,category,dynasty,level,material,current_status,home_institution_id,summary,story_hook,persona_quote,publish_status) VALUES
('b0000000-0000-0000-0000-000000000084','CN-2026-000084','圆明园十二生肖兽首·牛首','gold_silver','清代','level_1','','at_home','a0000000-0000-0000-0000-000000000031','圆明园海晏堂十二生肖水力钟兽首之一,1860 年英法联军劫掠后流失海外,2000 年由保利集团于香港拍卖竞得回归。','圆明园喷泉上的青铜牛,漂泊一个半世纪后回家','我本是皇家水钟的报时神兽,流落百年终于归来。','published'),
('b0000000-0000-0000-0000-000000000085','CN-2026-000085','圆明园十二生肖兽首·马首','gold_silver','清代','level_1','','at_home','a0000000-0000-0000-0000-000000000031','圆明园兽首之马首,2007 年现身拍卖,何鸿燊出资购回并于 2019—2020 年捐赠国家,最终回归圆明园。','一尊马首,牵动整个民族的回家之愿','我等了一百六十年,终于又听见了故园的风。','published'),
('b0000000-0000-0000-0000-000000000086','CN-2026-000086','青铜虎鎣','bronze','西周','level_1','青铜','at_home','a0000000-0000-0000-0000-000000000002','西周晚期青铜盉,因虎形装饰得名"虎鎣",1860 年流失英国,2018 年于英国拍卖后由买家捐赠中国,入藏国家博物馆。','一只青铜小虎,跨越重洋回到祖先的土地','我身上的虎纹,记得三千年前的火光。','published'),
('b0000000-0000-0000-0000-000000000087','CN-2026-000087','王处直墓彩绘散乐浮雕','stone_carving','五代','level_1','汉白玉','at_home','a0000000-0000-0000-0000-000000000002','五代王处直墓汉白玉彩绘浮雕,1994 年被盗流失海外,2000 年于美国被追索回归,入藏中国国家博物馆。','一面被盗凿走的乐舞墙,从纽约被追回故土','我刻着一支千年的乐队,曾被生生凿下墙壁。','published')
ON CONFLICT (id) DO NOTHING;
UPDATE artifacts SET repatriation_status = 'repatriated'
WHERE id IN (
'b0000000-0000-0000-0000-000000000010',
'b0000000-0000-0000-0000-000000000084',
'b0000000-0000-0000-0000-000000000085',
'b0000000-0000-0000-0000-000000000086',
'b0000000-0000-0000-0000-000000000087'
);
INSERT INTO artifact_locations (id,artifact_id,location_type,institution_id,public_location,precision,display_status,source_type,is_current,verified_at) VALUES
('c0000000-0000-0000-0000-000000000084','b0000000-0000-0000-0000-000000000084','domestic','a0000000-0000-0000-0000-000000000031',ST_SetSRID(ST_MakePoint(116.4340,39.9380),4326)::geography,'exact_building','on_display','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000085','b0000000-0000-0000-0000-000000000085','domestic','a0000000-0000-0000-0000-000000000031',ST_SetSRID(ST_MakePoint(116.4340,39.9380),4326)::geography,'exact_building','on_display','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000086','b0000000-0000-0000-0000-000000000086','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','public_source',true,NOW()),
('c0000000-0000-0000-0000-000000000087','b0000000-0000-0000-0000-000000000087','domestic','a0000000-0000-0000-0000-000000000002',ST_SetSRID(ST_MakePoint(116.4074,39.9052),4326)::geography,'exact_building','on_display','public_source',true,NOW())
ON CONFLICT (id) DO NOTHING;
-- 4) 每件回归国宝的专属路线
DELETE FROM route_stops WHERE route_id IN (
SELECT id FROM narrative_routes WHERE code IN ('huigui','huigui-mpl','huigui-niushou','huigui-mashou','huigui-huying','huigui-wangchuzhi')
);
DELETE FROM narrative_routes WHERE code IN ('huigui','huigui-mpl','huigui-niushou','huigui-mashou','huigui-huying','huigui-wangchuzhi');
INSERT INTO narrative_routes (id, code, title, type, color, artifact_id, summary) VALUES
('d0000000-0000-0000-0000-000000000002','huigui-mpl','皿方罍·完罍归湘','repatriation','#3f9e6a','b0000000-0000-0000-0000-000000000010','器盖与器身分离近一个世纪,2014 年器盖由海外回归,与器身在湖南合体。'),
('d0000000-0000-0000-0000-000000000003','huigui-niushou','圆明园牛首·百年归途','repatriation','#3f9e6a','b0000000-0000-0000-0000-000000000084','1860 年流失,2000 年保利于香港竞得回归。'),
('d0000000-0000-0000-0000-000000000004','huigui-mashou','圆明园马首·游子归园','repatriation','#3f9e6a','b0000000-0000-0000-0000-000000000085','2007 年购回,2020 年捐赠并回归圆明园。'),
('d0000000-0000-0000-0000-000000000005','huigui-huying','青铜虎鎣·虎归东方','repatriation','#3f9e6a','b0000000-0000-0000-0000-000000000086','1860 年流失英国,2018 年捐赠回归国博。'),
('d0000000-0000-0000-0000-000000000006','huigui-wangchuzhi','王处直墓浮雕·乐归故里','repatriation','#3f9e6a','b0000000-0000-0000-0000-000000000087','1994 年被盗,2000 年自美国追索回归。')
ON CONFLICT (code) DO NOTHING;
INSERT INTO route_stops (route_id, seq, name, lng, lat, year_label, event) VALUES
-- 皿方罍
('d0000000-0000-0000-0000-000000000002',1,'海外(流失)',2.3376,48.8606,'1920s','器盖流散海外,辗转私人藏家'),
('d0000000-0000-0000-0000-000000000002',2,'纽约',-73.9632,40.7794,'2014','现身纽约拍卖,国内紧急斡旋'),
('d0000000-0000-0000-0000-000000000002',3,'香港',114.1694,22.3193,'2014','达成洽购,护送入境'),
('d0000000-0000-0000-0000-000000000002',4,'北京',116.4074,39.9052,'2014','回归交接'),
('d0000000-0000-0000-0000-000000000002',5,'长沙·湖南博物院',112.9838,28.2082,'2014','器身器盖合体,完罍归湘'),
-- 牛首
('d0000000-0000-0000-0000-000000000003',1,'北京·圆明园',116.2980,40.0080,'1860','英法联军劫掠,兽首流失'),
('d0000000-0000-0000-0000-000000000003',2,'海外',-0.1276,51.5074,'1860—1999','辗转欧美藏家与拍卖行'),
('d0000000-0000-0000-0000-000000000003',3,'香港',114.1694,22.3193,'2000','保利集团拍卖竞得'),
('d0000000-0000-0000-0000-000000000003',4,'北京·保利艺术博物馆',116.4340,39.9380,'2000','入藏保利,向公众展出'),
-- 马首
('d0000000-0000-0000-0000-000000000004',1,'北京·圆明园',116.2980,40.0080,'1860','随海晏堂兽首一同流失'),
('d0000000-0000-0000-0000-000000000004',2,'海外',114.1694,22.3193,'1860—2006','流散港台与海外'),
('d0000000-0000-0000-0000-000000000004',3,'香港',114.1694,22.3193,'2007','何鸿燊出资购回'),
('d0000000-0000-0000-0000-000000000004',4,'北京·圆明园',116.2980,40.0080,'2020','捐赠国家,回归圆明园'),
-- 虎鎣
('d0000000-0000-0000-0000-000000000005',1,'北京·圆明园',116.2980,40.0080,'1860','英军劫掠后带往英国'),
('d0000000-0000-0000-0000-000000000005',2,'英国·肯特',1.0789,51.2802,'1860—2018','存于英国家族逾一个半世纪'),
('d0000000-0000-0000-0000-000000000005',3,'伦敦',-0.1276,51.5074,'2018','现身拍卖,买家捐赠中国'),
('d0000000-0000-0000-0000-000000000005',4,'北京·国家博物馆',116.4074,39.9052,'2018','入藏国博'),
-- 王处直墓浮雕
('d0000000-0000-0000-0000-000000000006',1,'河北·曲阳',114.7000,38.6200,'1994','王处直墓被盗,浮雕被凿走'),
('d0000000-0000-0000-0000-000000000006',2,'美国',-73.9632,40.7794,'1994—2000','流入美国艺术市场'),
('d0000000-0000-0000-0000-000000000006',3,'纽约',-73.9632,40.7794,'2000','中方跨国追索,拍卖叫停'),
('d0000000-0000-0000-0000-000000000006',4,'北京·国家博物馆',116.4074,39.9052,'2000','成功回归,入藏国博');
+18
View File
@@ -0,0 +1,18 @@
-- 补全「文物南迁北归之路」:南迁(去程)+ 北归(回程,东归南京、北返北京)
UPDATE narrative_routes SET title = '文物南迁北归之路', summary =
'1933—1950 年代,故宫等机构为避战火,将上万箱文物分路南迁西运,辗转上海、南京、宝鸡、汉中、成都、峨眉、重庆等地;抗战胜利后文物东归南京,新中国成立后部分文物北返故宫,行程逾万里、历时十余年而几无损失,被誉为人类文明守护史上的奇迹。'
WHERE code = 'nanqian';
DELETE FROM route_stops WHERE route_id = (SELECT id FROM narrative_routes WHERE code = 'nanqian');
INSERT INTO route_stops (route_id, seq, name, lng, lat, year_label, event) VALUES
((SELECT id FROM narrative_routes WHERE code='nanqian'),1,'北京·紫禁城(起运)',116.3972,39.9163,'1933','13427 箱文物分批南迁起运'),
((SELECT id FROM narrative_routes WHERE code='nanqian'),2,'上海',121.4737,31.2293,'1933—1936','暂存法租界库房'),
((SELECT id FROM narrative_routes WHERE code='nanqian'),3,'南京·朝天宫',118.7780,32.0300,'1936—1937','迁入朝天宫库房,旋因战事再迁'),
((SELECT id FROM narrative_routes WHERE code='nanqian'),4,'宝鸡',107.1444,34.3693,'1937—1938','北路西迁,翻越秦岭'),
((SELECT id FROM narrative_routes WHERE code='nanqian'),5,'汉中',107.0238,33.0678,'1938','转运途中遭遇空袭与塌方'),
((SELECT id FROM narrative_routes WHERE code='nanqian'),6,'成都',104.0665,30.6623,'1938','中路文物暂存'),
((SELECT id FROM narrative_routes WHERE code='nanqian'),7,'峨眉',103.4844,29.6010,'1939—1946','南路文物存于峨眉,安然度过战火'),
((SELECT id FROM narrative_routes WHERE code='nanqian'),8,'重庆',106.5516,29.5647,'1938—1946','中路文物存于巴县、乐山一带'),
((SELECT id FROM narrative_routes WHERE code='nanqian'),9,'南京(东归集中)',118.7780,32.0300,'1947','抗战胜利后各路文物复员东归、集中南京'),
((SELECT id FROM narrative_routes WHERE code='nanqian'),10,'北京·紫禁城(北归)',116.3972,39.9163,'1950s','部分文物陆续北返故宫,南迁北归画上句点');
+3
View File
@@ -0,0 +1,3 @@
export { runMigrations } from "./migrate";
export { runSeeds } from "./seed";
export { getPool } from "./pool";
+8
View File
@@ -0,0 +1,8 @@
import { runMigrations } from "./migrate";
runMigrations()
.then(() => process.exit(0))
.catch((err) => {
console.error("[migration] 失败:", err);
process.exit(1);
});
+40
View File
@@ -0,0 +1,40 @@
import * as fs from "fs";
import * as path from "path";
import { getPool } from "./pool";
export async function runMigrations(): Promise<void> {
const pool = getPool();
const migrationsDir = path.resolve(__dirname, "../migrations");
const files = fs
.readdirSync(migrationsDir)
.filter((f) => f.endsWith(".sql"))
.sort();
await pool.query(`
CREATE TABLE IF NOT EXISTS _migrations (
id SERIAL PRIMARY KEY,
filename VARCHAR(255) UNIQUE NOT NULL,
applied_at TIMESTAMPTZ DEFAULT NOW()
)
`);
for (const file of files) {
const row = await pool.query(
"SELECT id FROM _migrations WHERE filename = $1",
[file]
);
if (row.rows.length > 0) {
console.log(`[migration] skip ${file} (already applied)`);
continue;
}
const sql = fs.readFileSync(path.join(migrationsDir, file), "utf-8");
console.log(`[migration] apply ${file}`);
await pool.query(sql);
await pool.query("INSERT INTO _migrations (filename) VALUES ($1)", [file]);
console.log(`[migration] done ${file}`);
}
console.log("[migration] all migrations complete");
await pool.end();
}
+16
View File
@@ -0,0 +1,16 @@
import { Pool } from "pg";
import * as dotenv from "dotenv";
import * as path from "path";
dotenv.config({ path: path.resolve(__dirname, "../../../.env") });
let pool: Pool | null = null;
export function getPool(): Pool {
if (!pool) {
const url = process.env["DATABASE_URL"];
if (!url) throw new Error("DATABASE_URL 未设置");
pool = new Pool({ connectionString: url });
}
return pool;
}
+8
View File
@@ -0,0 +1,8 @@
import { runSeeds } from "./seed";
runSeeds()
.then(() => process.exit(0))
.catch((err) => {
console.error("[seed] 失败:", err);
process.exit(1);
});
+23
View File
@@ -0,0 +1,23 @@
import * as fs from "fs";
import * as path from "path";
import { getPool } from "./pool";
export async function runSeeds(): Promise<void> {
const pool = getPool();
const seedsDir = path.resolve(__dirname, "../seeds");
const files = fs
.readdirSync(seedsDir)
.filter((f) => f.endsWith(".sql"))
.sort();
for (const file of files) {
const sql = fs.readFileSync(path.join(seedsDir, file), "utf-8");
console.log(`[seed] apply ${file}`);
await pool.query(sql);
console.log(`[seed] done ${file}`);
}
console.log("[seed] all seeds complete");
await pool.end();
}
+12
View File
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "CommonJS",
"moduleResolution": "node",
"lib": ["ES2022"],
"types": ["node"],
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "@wenwumap/shared",
"version": "0.1.0",
"private": true,
"main": "./src/index.ts",
"types": "./src/index.ts",
"scripts": {
"type-check": "tsc --noEmit",
"lint": "eslint src --ext .ts"
},
"devDependencies": {
"typescript": "^5.5.3"
}
}
+104
View File
@@ -0,0 +1,104 @@
// 文物门类
export const ArtifactCategory = {
bronze: "bronze",
painting_calligraphy: "painting_calligraphy",
porcelain: "porcelain",
jade: "jade",
gold_silver: "gold_silver",
lacquer: "lacquer",
textile: "textile",
stone_carving: "stone_carving",
wood_carving: "wood_carving",
dunhuang: "dunhuang",
ancient_book: "ancient_book",
other: "other",
} as const;
export type ArtifactCategory = (typeof ArtifactCategory)[keyof typeof ArtifactCategory];
// 文物级别
export const ArtifactLevel = {
level_1: "level_1",
level_2: "level_2",
level_3: "level_3",
general: "general",
unknown: "unknown",
} as const;
export type ArtifactLevel = (typeof ArtifactLevel)[keyof typeof ArtifactLevel];
// 文物当前状态
export const ArtifactStatus = {
at_home: "at_home",
away: "away",
in_transit: "in_transit",
unknown: "unknown",
} as const;
export type ArtifactStatus = (typeof ArtifactStatus)[keyof typeof ArtifactStatus];
// 位置类型
export const LocationType = {
domestic: "domestic",
overseas: "overseas",
unknown: "unknown",
in_transit: "in_transit",
} as const;
export type LocationType = (typeof LocationType)[keyof typeof LocationType];
// 坐标精度
export const LocationPrecision = {
exact_room: "exact_room",
exact_building: "exact_building",
city: "city",
country: "country",
region: "region",
} as const;
export type LocationPrecision = (typeof LocationPrecision)[keyof typeof LocationPrecision];
// 展出状态
export const DisplayStatus = {
on_display: "on_display",
in_storage: "in_storage",
loaned: "loaned",
repairing: "repairing",
touring: "touring",
unknown: "unknown",
} as const;
export type DisplayStatus = (typeof DisplayStatus)[keyof typeof DisplayStatus];
// 数据来源类型
export const SourceType = {
institution_feed: "institution_feed",
manual_entry: "manual_entry",
user_report: "user_report",
expert_verify: "expert_verify",
public_source: "public_source",
} as const;
export type SourceType = (typeof SourceType)[keyof typeof SourceType];
// 发布状态
export const PublishStatus = {
draft: "draft",
pending: "pending",
published: "published",
archived: "archived",
rejected: "rejected",
} as const;
export type PublishStatus = (typeof PublishStatus)[keyof typeof PublishStatus];
// 标签值类型
export const TagValueType = {
single: "single",
multiple: "multiple",
boolean: "boolean",
text: "text",
number: "number",
} as const;
export type TagValueType = (typeof TagValueType)[keyof typeof TagValueType];
// 地图视图模式
export const MapView = {
all: "all",
at_home: "at_home",
away: "away",
south_migration: "south_migration",
} as const;
export type MapView = (typeof MapView)[keyof typeof MapView];
+2
View File
@@ -0,0 +1,2 @@
export * from "./enums";
export * from "./types";
+185
View File
@@ -0,0 +1,185 @@
import type {
ArtifactCategory,
ArtifactLevel,
ArtifactStatus,
DisplayStatus,
LocationPrecision,
LocationType,
PublishStatus,
SourceType,
TagValueType,
} from "./enums";
// 通用 API 响应
export interface ApiResponse<T> {
success: true;
data: T;
request_id: string;
}
export interface ApiError {
success: false;
error: {
code: string;
message: string;
details?: unknown[];
};
request_id: string;
}
// 分页
export interface Pagination {
page: number;
page_size: number;
total: number;
total_pages: number;
}
export interface PaginatedResult<T> {
items: T[];
pagination: Pagination;
}
// 坐标
export interface GeoPoint {
lng: number;
lat: number;
}
// 地图统计
export interface MapSummary {
total_artifacts: number;
domestic_count: number;
overseas_count: number;
on_display_count: number;
in_storage_count: number;
loaned_count: number;
unknown_location_count: number;
}
// 地图点位
export interface MapPoint {
id: string;
type: "artifact";
artifact_id: string;
name: string;
category: ArtifactCategory;
dynasty: string | null;
level: ArtifactLevel;
current_status: ArtifactStatus;
display_status: DisplayStatus;
precision: LocationPrecision;
coordinates: [number, number];
story_hook: string | null;
persona_quote: string | null;
institution: {
id: string;
name: string;
} | null;
}
export interface MapCluster {
id: string;
type: "cluster";
count: number;
coordinates: [number, number];
}
export interface MapPointsResult {
points: MapPoint[];
clusters: MapCluster[];
}
// 机构
export interface Institution {
id: string;
name: string;
short_name: string | null;
institution_type: string;
country: string;
province: string | null;
city: string | null;
address: string | null;
location: GeoPoint | null;
official_website: string | null;
description: string | null;
is_verified: boolean;
publish_status: PublishStatus;
created_at: string;
updated_at: string;
}
// 文物(列表卡片)
export interface ArtifactCard {
id: string;
unified_map_id: string;
name: string;
category: ArtifactCategory;
dynasty: string | null;
level: ArtifactLevel;
current_status: ArtifactStatus;
story_hook: string | null;
persona_quote: string | null;
institution: {
id: string;
name: string;
} | null;
current_location: {
display_status: DisplayStatus;
location_type: LocationType;
precision: LocationPrecision;
source_type: SourceType;
verified_at: string | null;
} | null;
cover_image: string | null;
}
// 文物(详情页)
export interface ArtifactDetail extends ArtifactCard {
alternative_names: string[];
material: string | null;
dimensions: string | null;
summary: string | null;
home_institution_id: string | null;
publish_status: PublishStatus;
tags: ArtifactTag[];
assets: DigitalAsset[];
}
// 文物标签
export interface ArtifactTag {
id: string;
tag_id: string;
tag_name: string;
tag_category: string;
value_text: string | null;
source_type: SourceType;
review_status: "pending" | "approved" | "rejected";
}
// 标签
export interface Tag {
id: string;
category_id: string;
code: string;
name: string;
value_type: TagValueType;
description: string | null;
color: string | null;
icon: string | null;
is_active: boolean;
sort_order: number;
}
// 数字资产
export interface DigitalAsset {
id: string;
asset_type: "image" | "audio" | "video" | "model_3d" | "document";
title: string | null;
url: string;
thumbnail_url: string | null;
mime_type: string | null;
size_bytes: number | null;
copyright_owner: string | null;
sort_order: number;
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": ["src"]
}