Files
Web_BAI_Manage_ApiServer/script/pocketbase.dictionary.js
XuJiacheng e9fe1165e3 feat: 规范化PocketBase数据库文档与原生API访问
- 将数据库文档拆分为按collection命名的标准文件,统一格式
- 补充tbl_company、tbl_system_dict等表的原生访问规则
- 新增users_tag、document_create等字段
- 优化用户资料更新接口,支持非必填字段
- 添加公司原生API测试脚本
- 归档本次变更至OpenSpec
2026-03-29 16:21:34 +08:00

211 lines
7.2 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createRequire } from 'module';
import PocketBase from 'pocketbase';
const require = createRequire(import.meta.url);
let runtimeConfig = {};
try {
runtimeConfig = require('../pocket-base/bai_api_pb_hooks/bai_api_shared/config/runtime.js');
} catch (_error) {
runtimeConfig = {};
}
const PB_URL = (process.env.PB_URL || 'https://bai-api.blv-oa.com/pb').replace(/\/+$/, '');
const AUTH_TOKEN = process.env.POCKETBASE_AUTH_TOKEN || runtimeConfig.POCKETBASE_AUTH_TOKEN || '';
if (!AUTH_TOKEN) {
console.error('❌ 缺少 POCKETBASE_AUTH_TOKEN无法执行字典建表。');
process.exit(1);
}
const pb = new PocketBase(PB_URL);
const collectionData = {
name: 'tbl_system_dict',
type: 'base',
listRule: '',
viewRule: '',
createRule: '(@request.auth.users_idtype = "ManagePlatform" || @request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB")',
updateRule: '(@request.auth.users_idtype = "ManagePlatform" || @request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB")',
deleteRule: '(@request.auth.users_idtype = "ManagePlatform" || @request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB")',
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_image', 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)',
],
};
function normalizeFieldPayload(field, existingField) {
const payload = existingField
? Object.assign({}, existingField)
: {
name: field.name,
type: field.type,
};
if (existingField && existingField.id) {
payload.id = existingField.id;
}
payload.name = field.name;
payload.type = field.type;
if (typeof field.required !== 'undefined') {
payload.required = field.required;
}
return payload;
}
function buildCollectionPayload(target, existingCollection) {
if (!existingCollection) {
return {
name: target.name,
type: target.type,
listRule: target.listRule,
viewRule: target.viewRule,
createRule: target.createRule,
updateRule: target.updateRule,
deleteRule: target.deleteRule,
fields: target.fields.map((field) => normalizeFieldPayload(field, null)),
indexes: target.indexes,
};
}
const targetFieldMap = new Map(target.fields.map((field) => [field.name, field]));
const fields = (existingCollection.fields || []).map((existingField) => {
const nextField = targetFieldMap.get(existingField.name);
if (!nextField) {
return existingField;
}
targetFieldMap.delete(existingField.name);
return normalizeFieldPayload(nextField, existingField);
});
for (const field of targetFieldMap.values()) {
fields.push(normalizeFieldPayload(field, null));
}
return {
name: target.name,
type: target.type,
listRule: target.listRule,
viewRule: target.viewRule,
createRule: target.createRule,
updateRule: target.updateRule,
deleteRule: target.deleteRule,
fields: fields,
indexes: target.indexes,
};
}
function normalizeFieldList(fields) {
return (fields || []).map((field) => ({
name: field.name,
type: field.type,
required: !!field.required,
}));
}
async function createOrUpdateCollection(target) {
console.log(`🔄 正在处理表: ${target.name} ...`);
try {
const existing = await pb.collections.getOne(target.name);
await pb.collections.update(existing.id, buildCollectionPayload(target, existing));
console.log(`♻️ ${target.name} 已存在,已按最新结构更新。`);
} catch (error) {
if (error.status === 404) {
await pb.collections.create(buildCollectionPayload(target, null));
console.log(`${target.name} 创建完成。`);
return;
}
console.error(`❌ 处理集合 ${target.name} 失败:`, {
status: error.status,
message: error.message,
response: error.response?.data,
});
throw error;
}
}
async function verifyCollection(target) {
console.log('\n🔍 开始校验字典表结构与索引...');
const remote = await pb.collections.getOne(target.name);
const remoteFields = normalizeFieldList(remote.fields);
const targetFields = normalizeFieldList(target.fields);
const remoteFieldMap = new Map(remoteFields.map((field) => [field.name, field.type]));
const remoteRequiredMap = new Map(remoteFields.map((field) => [field.name, field.required]));
const missingFields = [];
const mismatchedTypes = [];
const mismatchedRequired = [];
for (const field of targetFields) {
if (!remoteFieldMap.has(field.name)) {
missingFields.push(field.name);
continue;
}
if (remoteFieldMap.get(field.name) !== field.type) {
mismatchedTypes.push(`${field.name}:${remoteFieldMap.get(field.name)}!=${field.type}`);
}
if (remoteRequiredMap.get(field.name) !== !!field.required) {
mismatchedRequired.push(`${field.name}:${remoteRequiredMap.get(field.name)}!=${!!field.required}`);
}
}
const remoteIndexes = new Set(remote.indexes || []);
const missingIndexes = target.indexes.filter((indexSql) => !remoteIndexes.has(indexSql));
if (!missingFields.length && !mismatchedTypes.length && !mismatchedRequired.length && !missingIndexes.length) {
console.log(`${target.name} 校验通过。`);
return;
}
if (missingFields.length) {
console.log(` - 缺失字段: ${missingFields.join(', ')}`);
}
if (mismatchedTypes.length) {
console.log(` - 字段类型不匹配: ${mismatchedTypes.join(', ')}`);
}
if (mismatchedRequired.length) {
console.log(` - 字段必填属性不匹配: ${mismatchedRequired.join(', ')}`);
}
if (missingIndexes.length) {
console.log(` - 缺失索引: ${missingIndexes.join(' | ')}`);
}
throw new Error(`${target.name} 结构与预期不一致`);
}
async function init() {
try {
console.log(`🔄 正在连接 PocketBase: ${PB_URL}`);
pb.authStore.save(AUTH_TOKEN, null);
console.log('✅ 已使用 POCKETBASE_AUTH_TOKEN 载入认证状态。');
await createOrUpdateCollection(collectionData);
await verifyCollection(collectionData);
console.log('\n🎉 字典表结构初始化并校验完成!');
} catch (error) {
console.error('❌ 初始化失败:', error.response?.data || error.message);
process.exitCode = 1;
}
}
init();