Files
Web_BAI_Manage_ApiServer/script/pocketbase.file-fields-to-attachments.js
XuJiacheng 51a90260e4 feat: 添加 PocketBase MiniApp 公司 API 文档和文件字段迁移脚本
- 新增 openapi-miniapp-company.yaml 文件,定义 tbl_company 的基础 CRUD 接口文档,包括查询、创建、更新和删除公司记录的详细描述和示例。
- 新增 pocketbase.file-fields-to-attachments.js 脚本,用于迁移 PocketBase 中的文件字段到文本字段,并处理 tbl_attachments 集合的公开规则。
2026-03-28 15:13:04 +08:00

143 lines
4.8 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);
function buildReplacementTextField(field) {
return {
name: field.name,
type: 'text',
required: !!field.required,
hidden: !!field.hidden,
presentable: typeof field.presentable === 'boolean' ? field.presentable : true,
};
}
function buildCollectionPayload(remote, fields) {
const payload = {
name: remote.name,
type: remote.type,
fields: fields,
indexes: remote.indexes || [],
listRule: remote.listRule,
viewRule: remote.viewRule,
createRule: remote.createRule,
updateRule: remote.updateRule,
deleteRule: remote.deleteRule,
};
if (remote.name === 'tbl_attachments') {
payload.listRule = '';
payload.viewRule = '';
}
return payload;
}
async function migrateCollections() {
console.log(`🔄 正在连接 PocketBase: ${PB_URL}`);
pb.authStore.save(AUTH_TOKEN, null);
console.log('✅ 已使用 POCKETBASE_AUTH_TOKEN 载入认证状态。');
const collections = await pb.collections.getFullList({ sort: 'name' });
const changed = [];
for (const remote of collections) {
const fileFields = (remote.fields || []).filter((field) => field.type === 'file');
const shouldOpenAttachments = remote.name === 'tbl_attachments' && (remote.listRule !== '' || remote.viewRule !== '');
if (!fileFields.length && !shouldOpenAttachments) {
continue;
}
console.log(`🔄 正在处理集合: ${remote.name}`);
if (remote.name === 'tbl_attachments') {
await pb.collections.update(remote.id, buildCollectionPayload(remote, remote.fields || []));
} else if (fileFields.length) {
const remainingFields = (remote.fields || []).filter((field) => field.type !== 'file');
await pb.collections.update(remote.id, buildCollectionPayload(remote, remainingFields));
const refreshed = await pb.collections.getOne(remote.name);
const replacementFields = fileFields.map((field) => buildReplacementTextField(field));
await pb.collections.update(
refreshed.id,
buildCollectionPayload(refreshed, (refreshed.fields || []).concat(replacementFields)),
);
}
changed.push({
name: remote.name,
convertedFileFields: remote.name === 'tbl_attachments'
? []
: fileFields.map((field) => field.name),
attachmentsRulesOpened: remote.name === 'tbl_attachments',
});
}
return changed;
}
async function verifyResult() {
const collections = await pb.collections.getFullList({ sort: 'name' });
const residualFileFields = [];
let attachmentsRules = null;
for (const remote of collections) {
for (const field of (remote.fields || [])) {
if (field.type === 'file' && remote.name !== 'tbl_attachments') {
residualFileFields.push(`${remote.name}.${field.name}`);
}
}
if (remote.name === 'tbl_attachments') {
attachmentsRules = {
listRule: remote.listRule,
viewRule: remote.viewRule,
};
}
}
if (residualFileFields.length) {
throw new Error(`仍存在未迁移的 file 字段: ${residualFileFields.join(', ')}`);
}
if (!attachmentsRules || attachmentsRules.listRule !== '' || attachmentsRules.viewRule !== '') {
throw new Error('tbl_attachments 的公开 list/view 规则未生效');
}
console.log('✅ 校验通过:除 tbl_attachments 外已无 file 字段。');
console.log('✅ 校验通过tbl_attachments 已开放公共 list/view。');
}
async function main() {
try {
const changed = await migrateCollections();
console.log('📝 本次更新集合:');
console.log(JSON.stringify(changed, null, 2));
await verifyResult();
console.log('🎉 文件字段迁移完成!');
} catch (error) {
console.error('❌ 文件字段迁移失败:', error.response?.data || error.message || error);
process.exitCode = 1;
}
}
main();