init.sql 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. -- 灵越智报 v2.0 数据库初始化脚本
  2. -- PostgreSQL 15+
  3. -- 注意: ID 使用 VARCHAR(36) 以兼容 MyBatis-Plus 的 ASSIGN_UUID 策略
  4. -- 创建数据库(如果不存在)
  5. -- CREATE DATABASE lingyue_zhibao;
  6. -- 连接到数据库
  7. -- \c lingyue_zhibao;
  8. -- 启用UUID扩展
  9. CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
  10. -- ============================================
  11. -- 1. 用户表 (users)
  12. -- ============================================
  13. CREATE TABLE IF NOT EXISTS users (
  14. id VARCHAR(36) PRIMARY KEY,
  15. username VARCHAR(50) UNIQUE NOT NULL,
  16. email VARCHAR(100) UNIQUE NOT NULL,
  17. password_hash VARCHAR(255) NOT NULL,
  18. avatar_url VARCHAR(500),
  19. role VARCHAR(20) NOT NULL DEFAULT 'user', -- admin/user/guest
  20. preferences JSONB DEFAULT '{}',
  21. last_login_at TIMESTAMP,
  22. create_by VARCHAR(36),
  23. create_by_name VARCHAR(100),
  24. create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  25. update_by VARCHAR(36),
  26. update_by_name VARCHAR(100),
  27. update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  28. );
  29. CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
  30. CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
  31. -- ============================================
  32. -- 2. 文档表 (documents)
  33. -- ============================================
  34. CREATE TABLE IF NOT EXISTS documents (
  35. id VARCHAR(36) PRIMARY KEY,
  36. user_id VARCHAR(36) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  37. name VARCHAR(255) NOT NULL,
  38. type VARCHAR(20) NOT NULL, -- pdf/word/image/markdown/other
  39. status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending/uploading/parsing/completed/failed
  40. file_size BIGINT,
  41. file_url VARCHAR(500),
  42. thumbnail_url VARCHAR(500),
  43. parsed_text TEXT,
  44. parse_status VARCHAR(20), -- pending/parsing/completed/failed
  45. parse_progress INTEGER DEFAULT 0, -- 0-100
  46. parse_error TEXT,
  47. parse_started_at TIMESTAMP,
  48. parse_completed_at TIMESTAMP,
  49. metadata JSONB DEFAULT '{}', -- pageCount, ocrConfidence, layoutStructure等
  50. create_by VARCHAR(36),
  51. create_by_name VARCHAR(100),
  52. create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  53. update_by VARCHAR(36),
  54. update_by_name VARCHAR(100),
  55. update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  56. );
  57. CREATE INDEX IF NOT EXISTS idx_documents_user_id ON documents(user_id);
  58. CREATE INDEX IF NOT EXISTS idx_documents_status ON documents(status);
  59. CREATE INDEX IF NOT EXISTS idx_documents_type ON documents(type);
  60. CREATE INDEX IF NOT EXISTS idx_documents_created_at ON documents(create_time DESC);
  61. CREATE INDEX IF NOT EXISTS idx_documents_metadata ON documents USING GIN(metadata);
  62. CREATE INDEX IF NOT EXISTS idx_documents_parsed_text ON documents USING GIN(to_tsvector('english', parsed_text)); -- 全文搜索
  63. -- ============================================
  64. -- 3. 要素表 (elements)
  65. -- ============================================
  66. CREATE TABLE IF NOT EXISTS elements (
  67. id VARCHAR(36) PRIMARY KEY,
  68. document_id VARCHAR(36) NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
  69. user_id VARCHAR(36) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  70. type VARCHAR(20) NOT NULL, -- amount/company/person/location/date/other
  71. label VARCHAR(100) NOT NULL,
  72. value TEXT NOT NULL,
  73. position JSONB, -- {page, x, y, width, height}
  74. confidence DECIMAL(3,2), -- 0.00-1.00
  75. extraction_method VARCHAR(20), -- ai/regex/rule/manual
  76. graph_node_id VARCHAR(36), -- 关联的图节点ID
  77. metadata JSONB DEFAULT '{}',
  78. create_by VARCHAR(36),
  79. create_by_name VARCHAR(100),
  80. create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  81. update_by VARCHAR(36),
  82. update_by_name VARCHAR(100),
  83. update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  84. );
  85. CREATE INDEX IF NOT EXISTS idx_elements_document_id ON elements(document_id);
  86. CREATE INDEX IF NOT EXISTS idx_elements_user_id ON elements(user_id);
  87. CREATE INDEX IF NOT EXISTS idx_elements_type ON elements(type);
  88. CREATE INDEX IF NOT EXISTS idx_elements_graph_node_id ON elements(graph_node_id);
  89. CREATE INDEX IF NOT EXISTS idx_elements_position ON elements USING GIN(position);
  90. -- ============================================
  91. -- 4. 批注表 (annotations)
  92. -- ============================================
  93. CREATE TABLE IF NOT EXISTS annotations (
  94. id VARCHAR(36) PRIMARY KEY,
  95. document_id VARCHAR(36) NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
  96. user_id VARCHAR(36) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  97. text TEXT NOT NULL,
  98. position JSONB NOT NULL, -- {page, start: {x, y}, end: {x, y}}
  99. type VARCHAR(20) NOT NULL, -- highlight/strikethrough/suggestion
  100. suggestion TEXT,
  101. ai_generated BOOLEAN DEFAULT FALSE,
  102. confidence DECIMAL(3,2),
  103. status VARCHAR(20) DEFAULT 'pending', -- pending/accepted/rejected
  104. create_by VARCHAR(36),
  105. create_by_name VARCHAR(100),
  106. create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  107. update_by VARCHAR(36),
  108. update_by_name VARCHAR(100),
  109. update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  110. );
  111. CREATE INDEX IF NOT EXISTS idx_annotations_document_id ON annotations(document_id);
  112. CREATE INDEX IF NOT EXISTS idx_annotations_user_id ON annotations(user_id);
  113. CREATE INDEX IF NOT EXISTS idx_annotations_type ON annotations(type);
  114. CREATE INDEX IF NOT EXISTS idx_annotations_status ON annotations(status);
  115. -- ============================================
  116. -- 5. 关系网络表 (graphs)
  117. -- ============================================
  118. CREATE TABLE IF NOT EXISTS graphs (
  119. id VARCHAR(36) PRIMARY KEY,
  120. document_id VARCHAR(36) NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
  121. user_id VARCHAR(36) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  122. name VARCHAR(255) NOT NULL,
  123. nodes JSONB NOT NULL DEFAULT '[]', -- GraphNode数组
  124. edges JSONB NOT NULL DEFAULT '[]', -- GraphEdge数组
  125. calculation_result JSONB,
  126. calculation_status VARCHAR(20), -- pending/completed/failed
  127. metadata JSONB DEFAULT '{}',
  128. create_by VARCHAR(36),
  129. create_by_name VARCHAR(100),
  130. create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  131. update_by VARCHAR(36),
  132. update_by_name VARCHAR(100),
  133. update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  134. );
  135. CREATE INDEX IF NOT EXISTS idx_graphs_document_id ON graphs(document_id);
  136. CREATE INDEX IF NOT EXISTS idx_graphs_user_id ON graphs(user_id);
  137. CREATE INDEX IF NOT EXISTS idx_graphs_nodes ON graphs USING GIN(nodes);
  138. CREATE INDEX IF NOT EXISTS idx_graphs_edges ON graphs USING GIN(edges);
  139. -- ============================================
  140. -- 6. 解析任务表 (parse_tasks)
  141. -- ============================================
  142. CREATE TABLE IF NOT EXISTS parse_tasks (
  143. id VARCHAR(36) PRIMARY KEY,
  144. document_id VARCHAR(36) NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
  145. status VARCHAR(20) NOT NULL DEFAULT 'pending', -- pending/processing/completed/failed
  146. progress INTEGER DEFAULT 0, -- 0-100
  147. current_step VARCHAR(100),
  148. error_message TEXT,
  149. options JSONB DEFAULT '{}', -- 解析选项
  150. started_at TIMESTAMP,
  151. completed_at TIMESTAMP,
  152. create_by VARCHAR(36),
  153. create_by_name VARCHAR(100),
  154. create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  155. update_by VARCHAR(36),
  156. update_by_name VARCHAR(100),
  157. update_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  158. );
  159. CREATE INDEX IF NOT EXISTS idx_parse_tasks_document_id ON parse_tasks(document_id);
  160. CREATE INDEX IF NOT EXISTS idx_parse_tasks_status ON parse_tasks(status);
  161. -- ============================================
  162. -- 7. 会话表 (sessions)
  163. -- ============================================
  164. CREATE TABLE IF NOT EXISTS sessions (
  165. id VARCHAR(36) PRIMARY KEY,
  166. user_id VARCHAR(36) NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  167. token_hash VARCHAR(255) NOT NULL UNIQUE,
  168. refresh_token_hash VARCHAR(255) NOT NULL UNIQUE,
  169. expires_at TIMESTAMP NOT NULL,
  170. ip_address VARCHAR(45),
  171. user_agent TEXT,
  172. create_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  173. last_used_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  174. );
  175. CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);
  176. CREATE INDEX IF NOT EXISTS idx_sessions_token_hash ON sessions(token_hash);
  177. CREATE INDEX IF NOT EXISTS idx_sessions_expires_at ON sessions(expires_at);
  178. -- ============================================
  179. -- 创建更新时间触发器函数
  180. -- ============================================
  181. CREATE OR REPLACE FUNCTION update_update_time_column()
  182. RETURNS TRIGGER AS $$
  183. BEGIN
  184. NEW.update_time = CURRENT_TIMESTAMP;
  185. RETURN NEW;
  186. END;
  187. $$ language 'plpgsql';
  188. -- 为所有表创建更新时间触发器
  189. DROP TRIGGER IF EXISTS update_users_updated_at ON users;
  190. CREATE TRIGGER update_users_update_time BEFORE UPDATE ON users
  191. FOR EACH ROW EXECUTE FUNCTION update_update_time_column();
  192. DROP TRIGGER IF EXISTS update_documents_updated_at ON documents;
  193. CREATE TRIGGER update_documents_update_time BEFORE UPDATE ON documents
  194. FOR EACH ROW EXECUTE FUNCTION update_update_time_column();
  195. DROP TRIGGER IF EXISTS update_elements_updated_at ON elements;
  196. CREATE TRIGGER update_elements_update_time BEFORE UPDATE ON elements
  197. FOR EACH ROW EXECUTE FUNCTION update_update_time_column();
  198. DROP TRIGGER IF EXISTS update_annotations_updated_at ON annotations;
  199. CREATE TRIGGER update_annotations_update_time BEFORE UPDATE ON annotations
  200. FOR EACH ROW EXECUTE FUNCTION update_update_time_column();
  201. DROP TRIGGER IF EXISTS update_graphs_updated_at ON graphs;
  202. CREATE TRIGGER update_graphs_update_time BEFORE UPDATE ON graphs
  203. FOR EACH ROW EXECUTE FUNCTION update_update_time_column();
  204. DROP TRIGGER IF EXISTS update_parse_tasks_updated_at ON parse_tasks;
  205. CREATE TRIGGER update_parse_tasks_update_time BEFORE UPDATE ON parse_tasks
  206. FOR EACH ROW EXECUTE FUNCTION update_update_time_column();
  207. DROP TRIGGER IF EXISTS update_sessions_updated_at ON sessions;
  208. CREATE TRIGGER update_sessions_update_time BEFORE UPDATE ON sessions
  209. FOR EACH ROW EXECUTE FUNCTION update_update_time_column();