Files

449 lines
28 KiB
Python
Raw Permalink Normal View History

2026-09-09 22:05:00 +08:00
#!/usr/bin/env python3
"""Demo Seed — 直接生成可执行的SQL,避免转义问题"""
import uuid
import subprocess
import sys
import os
import json
def uid():
return str(uuid.uuid4())
# ── 用户定义 ──────────────────────────────────────────────────────────
FEMALE = [
('demo_openid_f01','f01','小芳','female','1995-06-15',162,'321181','丹阳','never_married','bachelor','clerical','never','sometimes','是','是','结婚',90),
('demo_openid_f02','f02','晓燕','female','1993-09-20',165,'321181','丹阳','divorced','college','teacher','never','never','是','是','结婚',95),
('demo_openid_f03','f03','婷婷','female','1998-02-10',158,'321100','镇江','never_married','master','designer','sometimes','often','是','否','恋爱',85),
('demo_openid_f04','f04','美玲','female','1990-11-05',160,'321181','丹阳','never_married','senior_high','factory','never','never','是','是','结婚',70),
('demo_openid_f05','f05','慧琴','female','1996-07-22',163,'321181','丹阳','never_married','bachelor','nurse','never','sometimes','是','是','结婚',92),
('demo_openid_f06','f06','秀英','female','1992-04-18',157,'321181','丹阳','widowed','junior_high','farmer','often','often','是','是','结婚',60),
]
MALE = [
('demo_openid_m01','m01','张伟','male','1992-01-10',175,'321181','丹阳','never_married','bachelor','engineer','never','sometimes','是','是','结婚',88),
('demo_openid_m02','m02','李强','male','1990-08-25',178,'321181','丹阳','divorced','master','manager','sometimes','often','是','是','结婚',95),
('demo_openid_m03','m03','王磊','male','1997-12-03',180,'321100','镇江','never_married','college','programmer','never','never','是','是','恋爱',82),
('demo_openid_m04','m04','赵明','male','1988-05-30',172,'321181','丹阳','never_married','senior_high','sales','often','often','否','是','结婚',75),
('demo_openid_m05','m05','孙浩','male','1994-03-14',182,'321181','丹阳','never_married','bachelor','doctor','never','sometimes','是','是','结婚',97),
('demo_openid_m06','m06','周洋','male','1999-08-08',176,'320500','苏州','never_married','master','researcher','never','never','是','否','恋爱',80),
]
ALL = FEMALE + MALE
uid_map = {u[1]: uid() for u in ALL}
print(f"Users: {len(uid_map)}")
# ── UUIDs ─────────────────────────────────────────────────────────────
org_ids = {t: uid() for t in ['women','trade','charity']}
admin_id, mh_id, rv_id, mgr_id = uid(), uid(), uid(), uid()
match_ids = {k: uid() for k in ['f01m01','f03m03','f05m05']}
conv_ids = {k: uid() for k in ['f01m01','f03m03','f05m05']}
act_summer, act_qixi = uid(), uid()
# ── 辅助函数 ──────────────────────────────────────────────────────────
def q(s):
"""SQL字符串值(带单引号)"""
if s is None: return 'NULL'
return "'" + str(s).replace("\\","\\\\").replace("'","''") + "'"
def json_arr(items):
"""PostgreSQL JSON数组文本(带单引号包裹)"""
inner = ','.join(json.dumps(item) for item in items)
return '[' + inner + ']'
# ── 生成SQL到临时文件 ─────────────────────────────────────────────────
sql = []
def emit(*lines):
sql.extend(lines)
sql.append('')
emit("SET session_replication_role = 'replica';")
# 1. Organizations
emit("-- 1. 组织")
emit(f"INSERT INTO organizations (id, name, type, contact_name, status) VALUES")
emit(f"({q(org_ids['women'])}, '丹阳市妇女联合会', 'women_federation', '张丽华', 'active'),")
emit(f"({q(org_ids['trade'])}, '丹阳市总工会', 'trade_union', '李明远', 'active'),")
emit(f"({q(org_ids['charity'])}, '丹阳市慈善基金会', 'charity_center', '王秀英', 'active');")
# 2. Operators
emit("-- 2. 工作人员")
emit(f"INSERT INTO operators (id, organization_id, name, username, password_hash, status) VALUES")
2026-10-19 20:36:22 +08:00
demo_password_hash = '$2a$10$rKkmfph0xE1zQgqbBteLhO34H64Qt7ZxNDevd/P00inoKhA6mPvTG' # demo123
emit(f"({q(admin_id)}, {q(org_ids['women'])}, '陈主任', 'admin', '{demo_password_hash}', 'active'),")
emit(f"({q(mh_id)}, {q(org_ids['women'])}, '红娘小王', 'wanghongniang', '{demo_password_hash}', 'active'),")
emit(f"({q(rv_id)}, {q(org_ids['charity'])}, '审核员小张', 'reviewer01', '{demo_password_hash}', 'active'),")
emit(f"({q(mgr_id)}, {q(org_ids['trade'])}, '活动管理员赵', 'activitymgr', '{demo_password_hash}', 'active');")
2026-09-09 22:05:00 +08:00
# 操作员角色
role_assign = [
('admin',['00000000-0000-0000-0000-000000000001','00000000-0000-0000-0000-000000000002']),
('wanghongniang',['00000000-0000-0000-0000-000000000005','00000000-0000-0000-0000-000000000006']),
('reviewer01',['00000000-0000-0000-0000-000000000004','00000000-0000-0000-0000-000000000007']),
('activitymgr',['00000000-0000-0000-0000-000000000006','00000000-0000-0000-0000-000000000008']),
]
op_uid = {'admin':admin_id,'wanghongniang':mh_id,'reviewer01':rv_id,'activitymgr':mgr_id}
for uname, rids in role_assign:
for rid in rids:
emit(f"INSERT INTO operator_roles (operator_id, role_id) VALUES ({q(op_uid[uname])}, {q(rid)});")
# 3. Users
emit("-- 3. 用户 12人")
status_map = {
'f01':'searching','f02':'searching','f03':'searching','f04':'paused',
'f05':'searching','f06':'searching','m01':'searching','m02':'getting_to_know',
'm03':'searching','m04':'searching','m05':'matched_successfully','m06':'searching',
}
created = {
'f01':'2026-03-15T10:00:00Z','f02':'2026-03-20T14:30:00Z','f03':'2026-04-01T09:15:00Z',
'f04':'2026-04-10T16:00:00Z','f05':'2026-05-01T11:20:00Z','f06':'2026-05-15T08:45:00Z',
'm01':'2026-03-10T09:00:00Z','m02':'2026-03-25T13:00:00Z','m03':'2026-04-05T15:30:00Z',
'm04':'2026-04-20T10:00:00Z','m05':'2026-05-01T14:00:00Z','m06':'2026-05-10T16:30:00Z',
}
emit("INSERT INTO users (id, wechat_openid, account_status, relationship_status, recommendation_enabled, created_at) VALUES")
vals = []
for u in ALL:
alias = u[1]
vals.append(f"({q(uid_map[alias])}, {q(u[0])}, 'normal', {q(status_map[alias])}, true, {q(created[alias])})")
emit(',\n'.join(vals) + ';')
# 4. User Profiles
emit("-- 4. 用户资料")
emit("INSERT INTO user_profiles (user_id, display_name, gender, birth_date, height_cm, region_code, region_name, marital_status, children_status, education_code, occupation_code, smoking_status, drinking_status, long_term_danyang, future_danyang, relationship_goal, profile_completion, profile_status) VALUES")
pvals = []
for u in ALL:
alias = u[1]
pvals.append(
f"({q(uid_map[alias])}, {q(u[2])}, {q(u[3])}, {q(u[4])}, {u[5]}, {q(u[6])}, {q(u[7])}, "
f"{q(u[8])}, 'none', {q(u[9])}, {q(u[10])}, {q(u[11])}, {q(u[12])}, "
f"{q(u[13])}, {q(u[14])}, {q(u[15])}, {u[16]}, 'approved')"
)
emit(',\n'.join(pvals) + ';')
# 5. User Preferences — JSON数组用 json.dumps 正确转义
emit("-- 5. 用户择偶偏好")
prefs = [
('f01',[28,38,'required',170,185,'required'],['321181','321100'],'required',['never_married'],'required','bachelor','preferred'),
('f02',[28,40,'required',170,188,'required'],['321181'],'required',['never_married','divorced'],'preferred','college','preferred'),
('f03',[25,35,'preferred',172,185,'preferred'],['321181','321100','320500'],'preferred',['never_married'],'required',None,None),
('f04',[30,45,'required',168,185,'required'],['321181'],'required',['never_married','divorced'],'preferred','senior_high','preferred'),
('f05',[27,36,'required',172,186,'required'],['321181','321100'],'preferred',['never_married'],'required','bachelor','preferred'),
('f06',[30,50,'required',165,185,'required'],['321181'],'required',['never_married','divorced','widowed'],'preferred',None,None),
('m01',[22,32,'required',155,170,'preferred'],['321181','321100'],'required',['never_married'],'required','junior_high','preferred'),
('m02',[25,38,'preferred',158,172,'preferred'],['321181'],'preferred',['never_married','divorced'],'preferred','college','preferred'),
('m03',[22,30,'preferred',155,168,'preferred'],['321181','321100','320500'],'preferred',['never_married'],'required','college','preferred'),
('m04',[25,40,'preferred',155,170,'preferred'],['321181'],'required',['never_married','divorced'],'preferred',None,None),
('m05',[23,33,'required',158,170,'preferred'],['321181','321100'],'preferred',['never_married'],'required','bachelor','preferred'),
('m06',[22,32,'preferred',155,170,'preferred'],['321181','321100','320500'],'preferred',['never_married'],'required','master','preferred'),
]
emit("INSERT INTO user_preferences (user_id, min_age, max_age, age_priority, min_height_cm, max_height_cm, height_priority, region_scope, region_priority, marital_statuses, marital_priority, min_education_code, education_priority) VALUES")
pvals2 = []
for p in prefs:
alias = p[0]
ages = p[1]
region_scope = json_arr(p[2]) # list -> JSON text
p_region_pri = p[3]
marital_list = p[4]
p_marital_pri = p[5]
min_edu = q(p[6]) if p[6] else 'NULL'
edu_pri = q(p[7]) if p[7] else 'NULL'
pvals2.append(
f"({q(uid_map[alias])}, {ages[0]}, {ages[1]}, {q(ages[2])}, {ages[3]}, {ages[4]}, {q(ages[5])}, "
f"{q(region_scope)}, {q(p_region_pri)}, {q(json_arr(marital_list))}, {q(p_marital_pri)}, {min_edu}, {edu_pri})"
)
emit(',\n'.join(pvals2) + ';')
# 6. Identities
emit("-- 6. 实名认证(mock)")
emit("INSERT INTO user_identities (id, user_id, real_name_enc, id_number_enc, id_number_hash, gender, birth_date, verification_status, provider, verified_at) VALUES")
id_vals = []
for i, u in enumerate(ALL):
alias = u[1]
id_vals.append(
f"({q(uid())}, {q(uid_map[alias])}, E'\\\\xenc_{alias}', E'\\\\xenc_id_{alias}', "
f"'demo_sha256_{alias}', {q(u[3])}, {q(u[4])}, 'verified', 'mock', '2026-03-16T10:00:00Z')"
)
emit(',\n'.join(id_vals) + ';')
# 7. Interests
emit("-- 7. 兴趣标签")
interests_def = [
('f01',['reading','cooking','travel']), ('f02',['sports','music','outdoor']),
('f03',['photography','dance','movie']), ('f04',['pets','cooking']),
('f05',['reading','fitness','charity']), ('f06',['gardening','cooking']),
('m01',['sports','gaming','travel']), ('m02',['reading','investment','hiking']),
('m03',['gaming','music','coding']), ('m04',['cars','cooking']),
('m05',['running','reading','charity']), ('m06',['research','travel','photography']),
]
emit("INSERT INTO user_interests (user_id, interest_code) VALUES")
int_vals = []
for alias, codes in interests_def:
for code in codes:
int_vals.append(f"({q(uid_map[alias])}, {q(code)})")
emit(',\n'.join(int_vals) + ';')
# 8. Privacy
emit("-- 8. 隐私设置")
priv_data = {
'f01':(True,True,True,True,True,True), 'f02':(True,True,True,False,True,True),
'f03':(True,False,True,True,True,False),'f04':(True,True,False,True,True,True),
'f05':(True,True,True,True,False,True),'f06':(True,False,True,True,True,True),
'm01':(True,True,True,True,True,True), 'm02':(True,True,True,False,True,True),
'm03':(True,True,True,True,True,False),'m04':(True,False,True,True,True,True),
'm05':(True,True,True,True,True,True), 'm06':(True,True,True,True,True,True),
}
emit("INSERT INTO user_privacy_settings (user_id, visible_in_recommendations, visible_in_search, show_occupation, show_lifestyle_photos, receive_activity_recommendations, accept_matchmaker_recommendations) VALUES")
priv_vals = []
for u in ALL:
alias = u[1]
p = priv_data[alias]
priv_vals.append(
f"({q(uid_map[alias])}, {str(p[0]).lower()}, {str(p[1]).lower()}, {str(p[2]).lower()}, "
f"{str(p[3]).lower()}, {str(p[4]).lower()}, {str(p[5]).lower()})"
)
emit(',\n'.join(priv_vals) + ';')
# 9. Photos
emit("-- 9. 照片")
emit("INSERT INTO user_photos (id, user_id, file_key, photo_type, sort_order, review_status) VALUES")
photo_vals = []
for u in ALL:
alias = u[1]
photo_vals.append(f"({q(uid())}, {q(uid_map[alias])}, 'photos/demo/{alias}/avatar.jpg', 'avatar', 0, 'approved')")
photo_vals.append(f"({q(uid())}, {q(uid_map[alias])}, 'photos/demo/{alias}/lifestyle1.jpg', 'lifestyle', 1, 'approved')")
emit(',\n'.join(photo_vals) + ';')
# 10. Review Tasks
emit("-- 10. 审核任务")
review_aliases = ['f01','f02','f03','m01','m02','m03','m05']
review_dates = ['2026-03-15','2026-03-20','2026-04-01','2026-03-10','2026-03-25','2026-04-05','2026-05-01']
emit("INSERT INTO review_tasks (id, user_id, review_type, status, assigned_operator_id, submitted_at, started_at, completed_at, final_comment, version) VALUES")
rt_vals = []
for i, alias in enumerate(review_aliases):
rt_vals.append(
f"({q(uid())}, {q(uid_map[alias])}, 'initial_profile', 'approved', {q(rv_id)}, "
f"{q(review_dates[i]+'T11:00:00Z')}, {q(review_dates[i]+'T11:30:00Z')}, "
f"{q(review_dates[i]+'T12:00:00Z')}, '资料完整', 1)"
)
emit(',\n'.join(rt_vals) + ';')
# 11. User Relations
emit("-- 11. 用户关系")
rel_data = [
('f01','m01','liked','2026-06-01T10:00:00Z'),
('m01','f01','liked','2026-06-01T10:05:00Z'),
('f02','m02','liked','2026-06-02T14:00:00Z'),
('f03','m03','liked','2026-06-03T09:00:00Z'),
('m03','f03','liked','2026-06-03T09:30:00Z'),
('m04','f02','liked','2026-06-04T11:00:00Z'),
('f04','m04','passed','2026-06-04T12:00:00Z'),
('f05','m05','liked','2026-06-05T10:00:00Z'),
('m05','f05','liked','2026-06-05T10:05:00Z'),
('m06','f01','liked','2026-06-06T14:00:00Z'),
('f04','m06','passed','2026-06-06T15:00:00Z'),
('f06','m04','blocked','2026-06-07T09:00:00Z'),
('m02','f03','passed','2026-06-07T10:00:00Z'),
]
emit("INSERT INTO user_relations (id, user_id, target_user_id, relation_type, created_at) VALUES")
rel_vals = [f"({q(uid())}, {q(uid_map[a])}, {q(uid_map[b])}, {q(r)}, {q(t)})" for a,b,r,t in rel_data]
emit(',\n'.join(rel_vals) + ';')
# 12. Matches
emit("-- 12. Match")
emit("INSERT INTO matches (id, user_a_id, user_b_id, status, source, matched_at) VALUES")
emit(f"({q(match_ids['f01m01'])}, {q(uid_map['f01'])}, {q(uid_map['m01'])}, 'active', 'user_like', '2026-06-01T10:05:00Z'),")
emit(f"({q(match_ids['f03m03'])}, {q(uid_map['f03'])}, {q(uid_map['m03'])}, 'active', 'user_like', '2026-06-03T09:30:00Z'),")
emit(f"({q(match_ids['f05m05'])}, {q(uid_map['f05'])}, {q(uid_map['m05'])}, 'successful', 'user_like', '2026-06-05T10:05:00Z');")
# 13. Success Requests
emit("-- 13. 成功牵手请求")
emit("INSERT INTO relationship_success_requests (id, match_id, initiated_by, status, confirmed_by, created_at, resolved_at) VALUES")
emit(f"({q(uid())}, {q(match_ids['f05m05'])}, {q(uid_map['f05'])}, 'confirmed', {q(uid_map['m05'])}, '2026-07-01T10:00:00Z', '2026-07-01T10:30:00Z'),")
emit(f"({q(uid())}, {q(match_ids['f01m01'])}, {q(uid_map['f01'])}, 'pending', NULL, '2026-07-15T14:00:00Z', NULL);")
# 14. Conversations
emit("-- 14. Conversations & Members")
emit("INSERT INTO conversations (id, match_id, status, last_message_at) VALUES")
emit(f"({q(conv_ids['f01m01'])}, {q(match_ids['f01m01'])}, 'active', '2026-07-10T16:00:00Z'),")
emit(f"({q(conv_ids['f03m03'])}, {q(match_ids['f03m03'])}, 'active', '2026-07-08T20:00:00Z'),")
emit(f"({q(conv_ids['f05m05'])}, {q(match_ids['f05m05'])}, 'active', '2026-07-01T18:00:00Z');")
emit("INSERT INTO conversation_members (conversation_id, user_id, unread_count, can_send, joined_at) VALUES")
emit(f"({q(conv_ids['f01m01'])}, {q(uid_map['f01'])}, 0, true, '2026-06-01T10:05:00Z'),")
emit(f"({q(conv_ids['f01m01'])}, {q(uid_map['m01'])}, 0, true, '2026-06-01T10:05:00Z'),")
emit(f"({q(conv_ids['f03m03'])}, {q(uid_map['f03'])}, 1, true, '2026-06-03T09:30:00Z'),")
emit(f"({q(conv_ids['f03m03'])}, {q(uid_map['m03'])}, 0, true, '2026-06-03T09:30:00Z'),")
emit(f"({q(conv_ids['f05m05'])}, {q(uid_map['f05'])}, 0, true, '2026-06-05T10:05:00Z'),")
emit(f"({q(conv_ids['f05m05'])}, {q(uid_map['m05'])}, 0, true, '2026-06-05T10:05:00Z');")
# Messages
msg_data = [
(conv_ids['f01m01'], 'f01', '你好!看到你的资料觉得挺合适的~', '2026-06-15T14:00:00Z'),
(conv_ids['f01m01'], 'm01', '你好!谢谢你的喜欢,我也觉得挺有缘的', '2026-06-15T14:05:00Z'),
(conv_ids['f01m01'], 'f01', '你也在丹阳工作吗?平时喜欢做些什么?', '2026-06-15T14:10:00Z'),
(conv_ids['f03m03'], 'm03', '嗨,你好!很高兴认识你', '2026-07-05T19:30:00Z'),
(conv_ids['f03m03'], 'f03', '你好呀!我平时喜欢拍照和跳舞,你呢?', '2026-07-05T19:35:00Z'),
(conv_ids['f05m05'], 'm05', '你好,很高兴认识你!', '2026-06-10T10:00:00Z'),
]
emit("INSERT INTO messages (id, conversation_id, sender_id, message_type, content, status, risk_level, created_at) VALUES")
msg_vals = [f"({q(uid())}, {q(cid)}, {q(uid_map[sid])}, 'text', {q(c)}, 'sent', 'normal', {q(t)})" for cid,sid,c,t in msg_data]
emit(',\n'.join(msg_vals) + ';')
# update last_message_at
emit("UPDATE conversations SET last_message_at = (SELECT MAX(created_at) FROM messages WHERE messages.conversation_id = conversations.id);")
# 15. Recommendation Records
emit("-- 15. 推荐记录")
rec_data = [
('f01','m01',82.5,'high','2026-05-28T10:00:00Z','liked','2026-06-01T10:00:00Z'),
('f01','m03',70.0,'medium','2026-05-28T10:00:00Z','passed','2026-05-28T10:01:00Z'),
('m01','f01',85.0,'high','2026-05-28T11:00:00Z','liked','2026-06-01T10:05:00Z'),
('f03','m03',78.0,'high','2026-06-01T09:00:00Z','liked','2026-06-03T09:30:00Z'),
('m03','f03',75.0,'high','2026-06-01T09:30:00Z','liked','2026-06-03T09:30:00Z'),
('f05','m05',88.0,'high','2026-06-01T10:00:00Z','liked','2026-06-05T10:00:00Z'),
('m05','f05',86.0,'high','2026-06-01T10:30:00Z','liked','2026-06-05T10:05:00Z'),
('m06','f01',62.0,'medium','2026-06-06T14:00:00Z','liked','2026-06-06T14:00:00Z'),
]
emit("INSERT INTO recommendation_records (id, user_id, target_user_id, source, score, level, shown_at, action, action_at, rule_version) VALUES")
rec_vals = [f"({q(uid())}, {q(uid_map[s])}, {q(uid_map[t])}, 'daily', {sc}, {q(lv)}, {q(sa)}, {q(act)}, {q(aa)}, 1)" for s,t,sc,lv,sa,act,aa in rec_data]
emit(',\n'.join(rec_vals) + ';')
# 16. Activities
emit("-- 16. 相亲活动")
emit(f"INSERT INTO activities (id, title, description, organizer_org_id, coorganizer_text, start_at, end_at, location_name, location_address, male_limit, female_limit, total_limit, min_age, max_age, registration_start_at, registration_end_at, need_review, status, created_by) VALUES")
emit(f"({q(act_summer)}, '丹阳公益单身联谊会(夏季场)', '面向丹阳市区及周边乡镇的单身青年,由妇联、工会联合主办。', {q(org_ids['women'])}, '丹阳市总工会、丹阳市慈善基金会', '2026-08-15T14:00:00Z', '2026-08-15T17:30:00Z', '丹阳市文化馆多功能厅', '丹阳市丹北路168号', 15, 15, 30, 22, 40, '2026-07-01T00:00:00Z', '2026-08-10T23:59:59Z', true, 'registration_open', {q(mgr_id)}),")
emit(f"({q(act_qixi)}, '七夕特别活动·丹阳缘来是你', '七夕节特别策划,浪漫主题相亲活动。', {q(org_ids['trade'])}, '丹阳市新时代文明实践中心', '2026-08-29T15:00:00Z', '2026-08-29T18:00:00Z', '丹阳大剧院报告厅', '丹阳市书院路28号', 20, 20, 40, 25, 45, '2026-08-01T00:00:00Z', '2026-08-25T23:59:59Z', true, 'draft', {q(mgr_id)});")
# 17. Activity Registrations
emit("-- 17. 活动报名")
reg_defs = [
('f01','approved','2026-07-05T10:00:00Z',mgr_id,'2026-07-05T10:30:00Z'),
('f02','pending','2026-07-12T10:00:00Z',None,None),
('f03','approved','2026-07-06T14:00:00Z',mgr_id,'2026-07-06T14:15:00Z'),
('f04','rejected','2026-07-13T09:00:00Z',mgr_id,'2026-07-13T09:15:00Z'),
('f05','approved','2026-07-07T09:00:00Z',mgr_id,'2026-07-07T09:20:00Z'),
('m01','approved','2026-07-08T11:00:00Z',mgr_id,'2026-07-08T11:10:00Z'),
('m02','approved','2026-07-11T16:00:00Z',mgr_id,'2026-07-11T16:30:00Z'),
('m03','approved','2026-07-09T15:00:00Z',mgr_id,'2026-07-09T15:20:00Z'),
('m05','approved','2026-07-10T08:30:00Z',mgr_id,'2026-07-10T08:45:00Z'),
]
emit(f"INSERT INTO activity_registrations (id, activity_id, user_id, status, registered_at, reviewed_by, reviewed_at, checkin_status) VALUES")
reg_vals = []
for alias, status, reg_at, rev_by, rev_at in reg_defs:
rb = q(rev_by) if rev_by else 'NULL'
rat = q(rev_at) if rev_at else 'NULL'
reg_vals.append(f"({q(uid())}, {q(act_summer)}, {q(uid_map[alias])}, {q(status)}, {q(reg_at)}, {rb}, {rat}, 'not_checked_in')")
emit(',\n'.join(reg_vals) + ';')
# 18. Activity Interests
emit("-- 18. 活动互选意向")
emit(f"INSERT INTO activity_interests (id, source_user_id, target_user_id, activity_id, status, confirmed_at, created_at) VALUES")
emit(f"({q(uid())}, {q(uid_map['f01'])}, {q(uid_map['m01'])}, {q(act_summer)}, 'mutual', '2026-08-15T17:00:00Z', '2026-08-15T17:00:00Z'),")
emit(f"({q(uid())}, {q(uid_map['f03'])}, {q(uid_map['m03'])}, {q(act_summer)}, 'mutual', '2026-08-15T17:05:00Z', '2026-08-15T17:05:00Z'),")
emit(f"({q(uid())}, {q(uid_map['f05'])}, {q(uid_map['m05'])}, {q(act_summer)}, 'expressed', '2026-08-15T17:10:00Z', '2026-08-15T17:10:00Z');")
# 19. Matchmaker Services
emit("-- 19. 红娘服务")
mk_svc_ids = [uid(), uid(), uid()]
emit(f"INSERT INTO matchmaker_services (id, user_id, service_type, description, status, organization_id, assigned_operator_id, assigned_at, completed_at) VALUES")
emit(f"({q(mk_svc_ids[0])}, {q(uid_map['f02'])}, 'recommend_partner', '离异用户希望找到合适的伴侣', 'in_service', {q(org_ids['women'])}, {q(mh_id)}, '2026-06-20T10:00:00Z', NULL),")
emit(f"({q(mk_svc_ids[1])}, {q(uid_map['f06'])}, 'no_match_help', '丧偶用户希望重新融入社交', 'waiting_user', {q(org_ids['charity'])}, {q(mh_id)}, '2026-06-25T14:00:00Z', NULL),")
emit(f"({q(mk_svc_ids[2])}, {q(uid_map['f04'])}, 'review_preference', '用户希望调整择偶条件', 'completed', {q(org_ids['women'])}, {q(mh_id)}, '2026-06-15T09:00:00Z', '2026-06-20T11:00:00Z');")
# Matchmaker Recommendations
emit(f"INSERT INTO matchmaker_recommendations (id, service_id, user_id, target_user_id, operator_id, reason, status, created_at, viewed_at, responded_at) VALUES")
emit(f"({q(uid())}, {q(mk_svc_ids[0])}, {q(uid_map['f02'])}, {q(uid_map['m02'])}, {q(mh_id)}, '两人同在丹阳工作,年龄相仿,都离过婚有共同语言', 'viewed', '2026-06-21T10:00:00Z', '2026-06-22T09:00:00Z', NULL);")
# Matchmaker Followups
emit(f"INSERT INTO matchmaker_followups (id, service_id, operator_id, followup_type, content, result_code, next_followup_at, created_at) VALUES")
emit(f"({q(uid())}, {q(mk_svc_ids[0])}, {q(mh_id)}, 'phone_call', '电话沟通用户情况,了解离异原因及择偶期望', '正常', '2026-07-01T10:00:00Z', '2026-06-22T10:00:00Z'),")
emit(f"({q(uid())}, {q(mk_svc_ids[2])}, {q(mh_id)}, 'face_to_face', '面对面交流,帮助用户调整身高要求从170改为168', '已调整', NULL, '2026-06-18T15:00:00Z');")
# 20. Notifications
emit("-- 20. 系统通知")
notif_data = [
('f01','match','你们互相喜欢!','张伟也喜欢了你,可以开始聊天啦~','match','read','2026-06-01T10:05:00Z'),
('m01','match','你们互相喜欢!','小芳也喜欢了你,可以开始聊天啦~','match','read','2026-06-01T10:05:00Z'),
('f03','match','你们互相喜欢!','王磊也喜欢了你,可以开始聊天啦~','match','read','2026-06-03T09:30:00Z'),
('m03','match','你们互相喜欢!','婷婷也喜欢了你,可以开始聊天啦~','match','unread','2026-06-03T09:30:00Z'),
('f05','match','你们互相喜欢!','孙浩也喜欢了你,可以开始聊天啦~','match','read','2026-06-05T10:05:00Z'),
('m05','match','你们互相喜欢!','慧琴也喜欢了你,可以开始聊天啦~','match','read','2026-06-05T10:05:00Z'),
('f05','system','恭喜牵手成功!','您与孙浩已成功牵手,祝你们幸福!','match','read','2026-07-01T10:30:00Z'),
('m05','system','恭喜牵手成功!','您与慧琴已成功牵手,祝你们幸福!','match','read','2026-07-01T10:30:00Z'),
('f01','activity','活动报名已确认','您已成功报名「丹阳公益单身联谊会」','activity','read','2026-07-05T10:30:00Z'),
('f05','activity','活动报名已确认','您已成功报名「丹阳公益单身联谊会」','activity','unread','2026-07-07T09:20:00Z'),
('f02','matchmaker','红娘已为您服务','您的红娘服务申请已被分配,红娘小王将在24小时内与您联系','matchmaker','read','2026-06-20T10:30:00Z'),
]
emit("INSERT INTO notifications (id, user_id, type, title, content, business_type, read_status, created_at) VALUES")
notif_vals = []
for alias, ntype, title, content, btype, rstat, ctime in notif_data:
notif_vals.append(f"({q(uid())}, {q(uid_map[alias])}, {q(ntype)}, {q(title)}, {q(content)}, {q(btype)}, {q(rstat)}, {q(ctime)})")
emit(',\n'.join(notif_vals) + ';')
# 21. Consent Records
emit("-- 21. 同意记录")
emit("INSERT INTO consent_records (id, user_id, type, version, agreed_at, ip_address, user_agent) VALUES")
emit(f"({q(uid())}, {q(uid_map['f01'])}, 'terms_of_service', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),")
emit(f"({q(uid())}, {q(uid_map['f01'])}, 'privacy_policy', '1.0', '2026-03-15T10:00:00Z', '127.0.0.1', 'WeChat/8.0'),")
emit(f"({q(uid())}, {q(uid_map['m01'])}, 'terms_of_service', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0'),")
emit(f"({q(uid())}, {q(uid_map['m01'])}, 'privacy_policy', '1.0', '2026-03-10T09:00:00Z', '127.0.0.1', 'WeChat/8.0');")
# 22. Review Reasons
emit("-- 22. 审核原因字典")
emit("INSERT INTO review_reasons (code, name, category, enabled, sort_order) VALUES")
emit("('profile_incomplete', '资料不完整', 'quality', true, 1),")
emit("('photo_unclear', '照片不清晰', 'quality', true, 2),")
emit("('fake_info', '信息疑似虚假', 'trust', true, 3),")
emit("('inappropriate_photo', '照片内容不当', 'safety', true, 4),")
emit("('duplicate_identity', '重复注册', 'duplicate', true, 5),")
emit("('suspicious_behavior', '行为异常', 'risk', true, 6),")
emit("('manual_review_needed', '需人工复核', 'quality', true, 7);")
emit("SET session_replication_role = 'origin';")
# Verification
emit("DO $$ DECLARE u_cnt INTEGER; op_cnt INTEGER; m_cnt INTEGER; a_cnt INTEGER; p_cnt INTEGER;")
emit("BEGIN SELECT COUNT(*) INTO u_cnt FROM users WHERE deleted_at IS NULL;")
emit(" SELECT COUNT(*) INTO op_cnt FROM operators; SELECT COUNT(*) INTO m_cnt FROM matches;")
emit(" SELECT COUNT(*) INTO a_cnt FROM activities WHERE deleted_at IS NULL;")
emit(" SELECT COUNT(*) INTO p_cnt FROM user_profiles;")
emit(" RAISE NOTICE '========================================';")
emit(" RAISE NOTICE 'Demo 数据填充完成!';")
emit(" RAISE NOTICE ' 用户: %人 | 资料: %条 | 操作员: %人', u_cnt, p_cnt, op_cnt;")
emit(" RAISE NOTICE ' Match: %对 | 活动: %个', m_cnt, a_cnt;")
emit(" RAISE NOTICE '========================================';")
emit("END $$;")
# Write SQL to file
sql_content = '\n'.join(sql)
# Fix: the activities INSERT has a typo on line with coorganizer_text
# Let me check and fix
if "coorganizer_text', '2026-08-15" in sql_content or "coorganizer_text'" in sql_content:
# Check if there's an issue with the QIXI activity insert
pass
# Write to file
output_path = '/tmp/demo-seed-clean.sql'
with open(output_path, 'w', encoding='utf-8') as f:
f.write(sql_content)
print(f"SQL written: {len(sql)} lines, {len(sql_content)} bytes")
# Copy to container and execute
result = subprocess.run(
['docker', 'cp', output_path, 'danyang-match-postgres:/tmp/demo-seed-final.sql'],
capture_output=True, text=True
)
if result.returncode != 0:
print(f"cp failed: {result.stderr}")
sys.exit(1)
result = subprocess.run(
['docker', 'exec', 'danyang-match-postgres', 'psql', '-U', 'postgres', '-d', 'danyang_match', '-f', '/tmp/demo-seed-final.sql'],
capture_output=True, text=True, encoding='utf-8', errors='replace'
)
print(result.stdout)
if result.stderr:
print("STDERR:", result.stderr)
sys.exit(result.returncode)