import PocketBase from 'pocketbase'; // ================= 配置区 ================= // 确保使用不带 /api 的根地址,并且端口是你后台管理的实际端口 const PB_URL = 'http://new.blv-oa.com:8000'; const ADMIN_EMAIL = '450481891@qq.com'; // 必须是超级管理员账号,不是普通用户! const ADMIN_PASSWORD = 'Momo123456'; // ========================================== const pb = new PocketBase(PB_URL); const collections = [ { name: 'tbl_system_dict', type: 'base', fields: [ { name: 'system_dict_id', type: 'text', required: true }, { name: 'dict_name', type: 'text', required: true }, { name: 'dict_word_enum', type: 'text' }, { name: 'dict_word_description', type: 'text' }, { name: 'dict_word_is_enabled', type: 'bool' }, { name: 'dict_word_sort_order', type: 'text' }, { name: 'dict_word_parent_id', type: 'text' }, { name: 'dict_word_remark', type: 'text' } ], indexes: [ 'CREATE UNIQUE INDEX idx_system_dict_id ON tbl_system_dict (system_dict_id)', 'CREATE UNIQUE INDEX idx_dict_name ON tbl_system_dict (dict_name)', 'CREATE INDEX idx_dict_word_parent_id ON tbl_system_dict (dict_word_parent_id)' ] }, { name: 'tbl_company', type: 'base', fields: [ { name: 'company_id', type: 'text', required: true }, { name: 'company_name', type: 'text' }, { name: 'company_type', type: 'text' }, { name: 'company_entity', type: 'text' }, { name: 'company_usci', type: 'text' }, { name: 'company_nationality', type: 'text' }, { name: 'company_province', type: 'text' }, { name: 'company_city', type: 'text' }, { name: 'company_postalcode', type: 'text' }, { name: 'company_add', type: 'text' }, { name: 'company_status', type: 'text' }, { name: 'company_level', type: 'text' }, { name: 'company_remark', type: 'text' } ], indexes: [ 'CREATE UNIQUE INDEX idx_company_id ON tbl_company (company_id)', 'CREATE INDEX idx_company_usci ON tbl_company (company_usci)' ] }, { name: 'tbl_user_groups', type: 'base', fields: [ { name: 'usergroups_id', type: 'text', required: true }, { name: 'usergroups_name', type: 'text' }, { name: 'usergroups_level', type: 'number' }, { name: 'usergroups_remark', type: 'text' } ], indexes: [ 'CREATE UNIQUE INDEX idx_usergroups_id ON tbl_user_groups (usergroups_id)' ] }, { name: 'tbl_users', type: 'base', fields: [ { name: 'users_id', type: 'text', required: true }, { name: 'users_name', type: 'text' }, { name: 'users_idtype', type: 'text' }, { name: 'users_id_number', type: 'text' }, { name: 'users_phone', type: 'text' }, { name: 'users_wx_openid', type: 'text' }, { name: 'users_level', type: 'text' }, { name: 'users_type', type: 'text' }, { name: 'users_status', type: 'text' }, { name: 'company_id', type: 'text' }, { name: 'users_parent_id', type: 'text' }, { name: 'users_promo_code', type: 'text' }, { name: 'users_id_pic_a', type: 'text' }, { name: 'users_id_pic_b', type: 'text' }, { name: 'users_title_picture', type: 'text' }, { name: 'users_picture', type: 'text' }, { name: 'usergroups_id', type: 'text' } ], indexes: [ 'CREATE UNIQUE INDEX idx_users_id ON tbl_users (users_id)', 'CREATE UNIQUE INDEX idx_users_phone ON tbl_users (users_phone)', 'CREATE UNIQUE INDEX idx_users_wx_openid ON tbl_users (users_wx_openid)', 'CREATE INDEX idx_users_company_id ON tbl_users (company_id)', 'CREATE INDEX idx_users_usergroups_id ON tbl_users (usergroups_id)', 'CREATE INDEX idx_users_parent_id ON tbl_users (users_parent_id)' ] } ]; async function init() { try { console.log('🔄 正在登录管理员账号...'); await pb.admins.authWithPassword(ADMIN_EMAIL, ADMIN_PASSWORD); console.log('✅ 登录成功!开始初始化表结构与索引...\n'); for (const collectionData of collections) { await createOrUpdateCollection(collectionData); } await verifyCollections(collections); console.log('\n🎉 所有表结构及索引初始化并校验完成!'); } catch (error) { console.error('❌ 初始化失败:', error.response?.data || error.message); } } // 幂等创建/更新集合 async function createOrUpdateCollection(collectionData) { console.log(`🔄 正在创建表: ${collectionData.name} ...`); const payload = { name: collectionData.name, type: collectionData.type, fields: collectionData.fields, indexes: collectionData.indexes }; try { await pb.collections.create(payload); console.log(`✅ ${collectionData.name} 表及索引创建完成。`); } catch (error) { const nameErrorCode = error.response?.data?.name?.code; if ( error.status === 400 && (nameErrorCode === 'validation_not_unique' || nameErrorCode === 'validation_collection_name_exists') ) { const existing = await pb.collections.getOne(collectionData.name); await pb.collections.update(existing.id, payload); console.log(`♻️ ${collectionData.name} 表已存在,已按最新结构更新。`); return; } throw error; } } async function verifyCollections(targetCollections) { console.log('\n🔍 开始校验表结构与索引...'); for (const target of targetCollections) { const remote = await pb.collections.getOne(target.name); const remoteFieldNames = new Set((remote.fields || []).map((field) => field.name)); const missingFields = target.fields .map((field) => field.name) .filter((fieldName) => !remoteFieldNames.has(fieldName)); const remoteIndexes = new Set(remote.indexes || []); const missingIndexes = target.indexes.filter((indexSql) => !remoteIndexes.has(indexSql)); if (missingFields.length === 0 && missingIndexes.length === 0) { console.log(`✅ ${target.name} 校验通过。`); continue; } console.log(`❌ ${target.name} 校验失败:`); if (missingFields.length > 0) { console.log(` - 缺失字段: ${missingFields.join(', ')}`); } if (missingIndexes.length > 0) { console.log(` - 缺失索引: ${missingIndexes.join(' | ')}`); } throw new Error(`${target.name} 结构与预期不一致`); } } init();