feat: 添加 SDK 权限管理页面和产品功能字段迁移脚本
- 新增 SDK 权限管理页面,包含角色管理、用户授权和集合权限配置功能。 - 实现字段迁移脚本,向 tbl_product_list 集合添加 prod_list_function 字段,类型为 json。
This commit is contained in:
149
script/add-product-function-field.js
Normal file
149
script/add-product-function-field.js
Normal file
@@ -0,0 +1,149 @@
|
||||
import { createRequire } from 'module';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import PocketBase from 'pocketbase';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
let runtimeConfig = {};
|
||||
try {
|
||||
runtimeConfig = require('../pocket-base/bai_api_pb_hooks/bai_api_shared/config/runtime.js');
|
||||
} catch (_error) {
|
||||
runtimeConfig = {};
|
||||
}
|
||||
|
||||
function readEnvFile(filePath) {
|
||||
if (!fs.existsSync(filePath)) return {};
|
||||
|
||||
const content = fs.readFileSync(filePath, 'utf8');
|
||||
const result = {};
|
||||
|
||||
for (const rawLine of content.split(/\r?\n/)) {
|
||||
const line = rawLine.trim();
|
||||
if (!line || line.startsWith('#')) continue;
|
||||
|
||||
const index = line.indexOf('=');
|
||||
if (index === -1) continue;
|
||||
|
||||
const key = line.slice(0, index).trim();
|
||||
const value = line.slice(index + 1).trim();
|
||||
result[key] = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const backendEnv = readEnvFile(path.resolve(__dirname, '..', 'back-end', '.env'));
|
||||
const pbUrl = String(
|
||||
process.env.PB_URL
|
||||
|| backendEnv.POCKETBASE_API_URL
|
||||
|| runtimeConfig.POCKETBASE_API_URL
|
||||
|| 'http://127.0.0.1:8090'
|
||||
).replace(/\/+$/, '');
|
||||
const authToken = process.env.POCKETBASE_AUTH_TOKEN || runtimeConfig.POCKETBASE_AUTH_TOKEN || '';
|
||||
|
||||
if (!authToken) {
|
||||
console.error('❌ 缺少 POCKETBASE_AUTH_TOKEN,无法执行字段迁移。');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function normalizeFieldPayload(field, targetSpec) {
|
||||
const payload = {
|
||||
name: targetSpec && targetSpec.name ? targetSpec.name : field.name,
|
||||
type: targetSpec && targetSpec.type ? targetSpec.type : field.type,
|
||||
};
|
||||
|
||||
if (field && field.id) {
|
||||
payload.id = field.id;
|
||||
}
|
||||
|
||||
if (typeof field.required !== 'undefined') {
|
||||
payload.required = !!field.required;
|
||||
}
|
||||
|
||||
if (payload.type === 'autodate') {
|
||||
payload.onCreate = typeof field.onCreate === 'boolean' ? field.onCreate : true;
|
||||
payload.onUpdate = typeof field.onUpdate === 'boolean' ? field.onUpdate : false;
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
async function run() {
|
||||
const pb = new PocketBase(pbUrl);
|
||||
pb.authStore.save(authToken, null);
|
||||
|
||||
console.log(`🔄 开始处理字段迁移,PocketBase: ${pbUrl}`);
|
||||
|
||||
const collections = await pb.collections.getFullList({ sort: '-created' });
|
||||
const collection = collections.find((item) => item.name === 'tbl_product_list');
|
||||
|
||||
if (!collection) {
|
||||
throw new Error('未找到集合 tbl_product_list');
|
||||
}
|
||||
|
||||
const targetFieldName = 'prod_list_function';
|
||||
const targetFieldType = 'json';
|
||||
const existingField = (collection.fields || []).find((field) => field.name === targetFieldName);
|
||||
|
||||
if (existingField && existingField.type === targetFieldType) {
|
||||
console.log('✅ 字段已存在且类型正确,无需变更。');
|
||||
console.log('✅ 校验完成: tbl_product_list.prod_list_function (json)');
|
||||
return;
|
||||
}
|
||||
|
||||
const nextFields = [];
|
||||
let patched = false;
|
||||
|
||||
for (let i = 0; i < (collection.fields || []).length; i += 1) {
|
||||
const field = collection.fields[i];
|
||||
if (field.name === targetFieldName) {
|
||||
nextFields.push(normalizeFieldPayload(field, { name: targetFieldName, type: targetFieldType }));
|
||||
patched = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
nextFields.push(normalizeFieldPayload(field));
|
||||
}
|
||||
|
||||
if (!patched) {
|
||||
nextFields.push({
|
||||
name: targetFieldName,
|
||||
type: targetFieldType,
|
||||
required: false,
|
||||
});
|
||||
}
|
||||
|
||||
await pb.collections.update(collection.id, {
|
||||
name: collection.name,
|
||||
type: collection.type,
|
||||
listRule: collection.listRule,
|
||||
viewRule: collection.viewRule,
|
||||
createRule: collection.createRule,
|
||||
updateRule: collection.updateRule,
|
||||
deleteRule: collection.deleteRule,
|
||||
fields: nextFields,
|
||||
indexes: collection.indexes || [],
|
||||
});
|
||||
|
||||
const updated = await pb.collections.getOne(collection.id);
|
||||
const verifiedField = (updated.fields || []).find((field) => field.name === targetFieldName);
|
||||
|
||||
if (!verifiedField || verifiedField.type !== targetFieldType) {
|
||||
throw new Error('字段写入后校验失败:prod_list_function 未成功写入 json 类型');
|
||||
}
|
||||
|
||||
console.log('✅ 字段迁移成功: tbl_product_list.prod_list_function (json)');
|
||||
}
|
||||
|
||||
run().catch((error) => {
|
||||
console.error('❌ 迁移失败:', {
|
||||
status: error && error.status,
|
||||
message: error && error.message,
|
||||
response: error && error.response,
|
||||
});
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -84,7 +84,7 @@
|
||||
| users_id_number | text | 证件号 |
|
||||
| users_phone | text | 用户电话号码 |
|
||||
| users_wx_openid | text | 微信号 |
|
||||
| users_level | text | 用户等级 |
|
||||
| users_level | text | 用户等级枚举值(新用户默认空) |
|
||||
| users_type | text | 用户类型 |
|
||||
| users_tag | text | 用户标签 |
|
||||
| users_status | text | 用户状态 |
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"init:dictionary": "node pocketbase.dictionary.js",
|
||||
"migrate:file-fields": "node pocketbase.file-fields-to-attachments.js",
|
||||
"migrate:product-params-array": "node migrate-product-parameters-to-array.js",
|
||||
"migrate:add-product-function-field": "node add-product-function-field.js",
|
||||
"test:company-native-api": "node test-tbl-company-native-api.js",
|
||||
"test:company-owner-sync": "node test-company-owner-sync.js"
|
||||
},
|
||||
|
||||
@@ -38,6 +38,7 @@ const collections = [
|
||||
{ name: 'prod_list_description', type: 'text' },
|
||||
{ name: 'prod_list_feature', type: 'text' },
|
||||
{ name: 'prod_list_parameters', type: 'json' },
|
||||
{ name: 'prod_list_function', type: 'json' },
|
||||
{ name: 'prod_list_plantype', type: 'text' },
|
||||
{ name: 'prod_list_category', type: 'text', required: true },
|
||||
{ name: 'prod_list_sort', type: 'number' },
|
||||
@@ -47,6 +48,7 @@ const collections = [
|
||||
{ name: 'prod_list_tags', type: 'text' },
|
||||
{ name: 'prod_list_status', type: 'text' },
|
||||
{ name: 'prod_list_basic_price', type: 'number' },
|
||||
{ name: 'prod_list_vip_price', type: 'json' },
|
||||
{ name: 'prod_list_remark', type: 'text' },
|
||||
],
|
||||
indexes: [
|
||||
|
||||
Reference in New Issue
Block a user