Files
Web_BAI_Manage_ApiServer/script/pocketbase.dictionary.js
XuJiacheng cd0373be3c feat: 添加系统刷新令牌请求和用户统计响应的 OpenAPI 规范
feat: 添加微信认证相关的 OpenAPI 规范,包括用户信息、登录请求和个人资料请求

feat: 添加 is_delete 字段迁移脚本,支持在集合中添加软删除字段

feat: 添加软删除规则应用脚本,确保所有相关集合的查询规则包含软删除条件

feat: 添加购物车和订单业务 ID 自动生成的迁移脚本,确保字段类型和自动生成规则正确
2026-04-07 20:02:10 +08:00

213 lines
7.4 KiB
JavaScript
Raw 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 || '';
const SOFT_DELETE_RULE = 'is_delete = 0';
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: SOFT_DELETE_RULE,
viewRule: SOFT_DELETE_RULE,
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' },
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true },
],
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();