feat: 添加系统刷新令牌请求和用户统计响应的 OpenAPI 规范
feat: 添加微信认证相关的 OpenAPI 规范,包括用户信息、登录请求和个人资料请求 feat: 添加 is_delete 字段迁移脚本,支持在集合中添加软删除字段 feat: 添加软删除规则应用脚本,确保所有相关集合的查询规则包含软删除条件 feat: 添加购物车和订单业务 ID 自动生成的迁移脚本,确保字段类型和自动生成规则正确
This commit is contained in:
@@ -89,7 +89,9 @@ async function run() {
|
||||
const targetFieldType = 'json';
|
||||
const existingField = (collection.fields || []).find((field) => field.name === targetFieldName);
|
||||
|
||||
if (existingField && existingField.type === targetFieldType) {
|
||||
const hasBrokenCustomIdField = (collection.fields || []).some((field) => field && field.name === 'id');
|
||||
|
||||
if (existingField && existingField.type === targetFieldType && !hasBrokenCustomIdField) {
|
||||
console.log('✅ 字段已存在且类型正确,无需变更。');
|
||||
console.log('✅ 校验完成: tbl_product_list.prod_list_function (json)');
|
||||
return;
|
||||
@@ -100,6 +102,10 @@ async function run() {
|
||||
|
||||
for (let i = 0; i < (collection.fields || []).length; i += 1) {
|
||||
const field = collection.fields[i];
|
||||
if (field && field.name === 'id') {
|
||||
// PocketBase system id is implicit; custom required id field will break record creation.
|
||||
continue;
|
||||
}
|
||||
if (field.name === targetFieldName) {
|
||||
nextFields.push(normalizeFieldPayload(field, { name: targetFieldName, type: targetFieldType }));
|
||||
patched = true;
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
"init:product-list": "node pocketbase.product-list.js",
|
||||
"init:dictionary": "node pocketbase.dictionary.js",
|
||||
"migrate:file-fields": "node pocketbase.file-fields-to-attachments.js",
|
||||
"migrate:add-is-delete-field": "node pocketbase.add-is-delete-field.js",
|
||||
"migrate:apply-soft-delete-rules": "node pocketbase.apply-soft-delete-rules.js",
|
||||
"migrate:ensure-cart-order-autogen-id": "node pocketbase.ensure-cart-order-autogen-id.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",
|
||||
|
||||
233
script/pocketbase.add-is-delete-field.js
Normal file
233
script/pocketbase.add-is-delete-field.js
Normal file
@@ -0,0 +1,233 @@
|
||||
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 PB_URL = String(
|
||||
process.env.PB_URL
|
||||
|| backendEnv.POCKETBASE_API_URL
|
||||
|| runtimeConfig.POCKETBASE_API_URL
|
||||
|| 'http://127.0.0.1:8090'
|
||||
).replace(/\/+$/, '');
|
||||
const AUTH_TOKEN = process.env.POCKETBASE_AUTH_TOKEN || runtimeConfig.POCKETBASE_AUTH_TOKEN || '';
|
||||
|
||||
if (!AUTH_TOKEN) {
|
||||
console.error('❌ 缺少 POCKETBASE_AUTH_TOKEN,无法执行 is_delete 字段迁移。');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const pb = new PocketBase(PB_URL);
|
||||
const TARGET_FIELD = {
|
||||
name: 'is_delete',
|
||||
type: 'number',
|
||||
required: false,
|
||||
presentable: true,
|
||||
hidden: false,
|
||||
default: 0,
|
||||
min: 0,
|
||||
max: 1,
|
||||
onlyInt: true,
|
||||
};
|
||||
|
||||
function isSystemCollection(collection) {
|
||||
return !!(collection && (collection.system || String(collection.name || '').startsWith('_')));
|
||||
}
|
||||
|
||||
function normalizeFieldPayload(field, targetSpec) {
|
||||
const payload = field ? Object.assign({}, field) : {};
|
||||
const next = targetSpec || field || {};
|
||||
|
||||
if (field && field.id) {
|
||||
payload.id = field.id;
|
||||
}
|
||||
|
||||
payload.name = next.name;
|
||||
payload.type = next.type;
|
||||
|
||||
if (typeof next.required !== 'undefined') {
|
||||
payload.required = !!next.required;
|
||||
}
|
||||
if (typeof next.presentable !== 'undefined') {
|
||||
payload.presentable = !!next.presentable;
|
||||
}
|
||||
if (typeof next.hidden !== 'undefined') {
|
||||
payload.hidden = !!next.hidden;
|
||||
}
|
||||
|
||||
if (next.type === 'number') {
|
||||
if (Object.prototype.hasOwnProperty.call(next, 'default')) payload.default = next.default;
|
||||
if (Object.prototype.hasOwnProperty.call(next, 'min')) payload.min = next.min;
|
||||
if (Object.prototype.hasOwnProperty.call(next, 'max')) payload.max = next.max;
|
||||
if (Object.prototype.hasOwnProperty.call(next, 'onlyInt')) payload.onlyInt = !!next.onlyInt;
|
||||
}
|
||||
|
||||
if (next.type === 'autodate') {
|
||||
payload.onCreate = typeof next.onCreate === 'boolean' ? next.onCreate : (typeof field?.onCreate === 'boolean' ? field.onCreate : true);
|
||||
payload.onUpdate = typeof next.onUpdate === 'boolean' ? next.onUpdate : (typeof field?.onUpdate === 'boolean' ? field.onUpdate : false);
|
||||
}
|
||||
|
||||
if (next.type === 'file') {
|
||||
payload.maxSelect = typeof next.maxSelect === 'number' ? next.maxSelect : (typeof field?.maxSelect === 'number' ? field.maxSelect : 0);
|
||||
payload.maxSize = typeof next.maxSize === 'number' ? next.maxSize : (typeof field?.maxSize === 'number' ? field.maxSize : 0);
|
||||
payload.mimeTypes = Array.isArray(next.mimeTypes)
|
||||
? next.mimeTypes
|
||||
: (Array.isArray(field?.mimeTypes) ? field.mimeTypes : null);
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
function buildCollectionPayload(collection, fields) {
|
||||
return {
|
||||
name: collection.name,
|
||||
type: collection.type,
|
||||
listRule: collection.listRule,
|
||||
viewRule: collection.viewRule,
|
||||
createRule: collection.createRule,
|
||||
updateRule: collection.updateRule,
|
||||
deleteRule: collection.deleteRule,
|
||||
fields,
|
||||
indexes: collection.indexes || [],
|
||||
};
|
||||
}
|
||||
|
||||
async function addFieldToCollections() {
|
||||
const collections = await pb.collections.getFullList({ sort: 'name' });
|
||||
const changed = [];
|
||||
|
||||
for (const collection of collections) {
|
||||
if (isSystemCollection(collection)) continue;
|
||||
|
||||
const currentFields = Array.isArray(collection.fields) ? collection.fields : [];
|
||||
const existingField = currentFields.find((field) => field && field.name === TARGET_FIELD.name);
|
||||
const nextFields = currentFields
|
||||
.filter((field) => field && field.name !== 'id')
|
||||
.map((field) => normalizeFieldPayload(field));
|
||||
|
||||
if (existingField) {
|
||||
for (let i = 0; i < nextFields.length; i += 1) {
|
||||
if (nextFields[i].name === TARGET_FIELD.name) {
|
||||
nextFields[i] = normalizeFieldPayload(existingField, TARGET_FIELD);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nextFields.push(normalizeFieldPayload(null, TARGET_FIELD));
|
||||
}
|
||||
|
||||
await pb.collections.update(collection.id, buildCollectionPayload(collection, nextFields));
|
||||
changed.push({ name: collection.name, action: existingField ? 'normalized' : 'added' });
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
async function backfillRecords() {
|
||||
const collections = await pb.collections.getFullList({ sort: 'name' });
|
||||
const summary = [];
|
||||
|
||||
for (const collection of collections) {
|
||||
if (isSystemCollection(collection)) continue;
|
||||
|
||||
let page = 1;
|
||||
let patched = 0;
|
||||
const perPage = 200;
|
||||
|
||||
while (true) {
|
||||
const list = await pb.collection(collection.name).getList(page, perPage, {
|
||||
fields: 'id,is_delete',
|
||||
skipTotal: false,
|
||||
});
|
||||
|
||||
const items = Array.isArray(list.items) ? list.items : [];
|
||||
for (const item of items) {
|
||||
const value = item && Object.prototype.hasOwnProperty.call(item, 'is_delete') ? item.is_delete : null;
|
||||
if (value === 0 || value === '0') continue;
|
||||
|
||||
await pb.collection(collection.name).update(item.id, { is_delete: 0 });
|
||||
patched += 1;
|
||||
}
|
||||
|
||||
if (page >= list.totalPages) break;
|
||||
page += 1;
|
||||
}
|
||||
|
||||
summary.push({ name: collection.name, backfilledRecords: patched });
|
||||
}
|
||||
|
||||
return summary;
|
||||
}
|
||||
|
||||
async function verifyCollections() {
|
||||
const collections = await pb.collections.getFullList({ sort: 'name' });
|
||||
const failed = [];
|
||||
|
||||
for (const collection of collections) {
|
||||
if (isSystemCollection(collection)) continue;
|
||||
const field = (collection.fields || []).find((item) => item && item.name === TARGET_FIELD.name);
|
||||
if (!field || field.type !== 'number') failed.push(collection.name);
|
||||
}
|
||||
|
||||
if (failed.length) {
|
||||
throw new Error('以下集合缺少 is_delete 字段或类型不正确: ' + failed.join(', '));
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log(`🔄 正在连接 PocketBase: ${PB_URL}`);
|
||||
pb.authStore.save(AUTH_TOKEN, null);
|
||||
console.log('✅ 已使用 POCKETBASE_AUTH_TOKEN 载入认证状态。');
|
||||
|
||||
const changed = await addFieldToCollections();
|
||||
console.log('📝 已更新集合:');
|
||||
console.log(JSON.stringify(changed, null, 2));
|
||||
|
||||
const backfilled = await backfillRecords();
|
||||
console.log('📝 已回填记录:');
|
||||
console.log(JSON.stringify(backfilled, null, 2));
|
||||
|
||||
await verifyCollections();
|
||||
console.log('✅ 校验通过:所有业务集合已包含 is_delete(number, default=0) 字段。');
|
||||
console.log('🎉 is_delete 字段迁移完成!');
|
||||
} catch (error) {
|
||||
console.error('❌ is_delete 字段迁移失败:', error.response?.data || error.message || error);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
176
script/pocketbase.apply-soft-delete-rules.js
Normal file
176
script/pocketbase.apply-soft-delete-rules.js
Normal file
@@ -0,0 +1,176 @@
|
||||
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 PB_URL = String(
|
||||
process.env.PB_URL
|
||||
|| backendEnv.POCKETBASE_API_URL
|
||||
|| runtimeConfig.POCKETBASE_API_URL
|
||||
|| 'http://127.0.0.1:8090'
|
||||
).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);
|
||||
|
||||
function isSystemCollection(collection) {
|
||||
return !!(collection && (collection.system || String(collection.name || '').startsWith('_')));
|
||||
}
|
||||
|
||||
function normalizeFieldPayload(field) {
|
||||
const payload = Object.assign({}, field);
|
||||
|
||||
if (field.type === 'number') {
|
||||
if (Object.prototype.hasOwnProperty.call(field, 'default')) payload.default = field.default;
|
||||
if (Object.prototype.hasOwnProperty.call(field, 'min')) payload.min = field.min;
|
||||
if (Object.prototype.hasOwnProperty.call(field, 'max')) payload.max = field.max;
|
||||
if (Object.prototype.hasOwnProperty.call(field, 'onlyInt')) payload.onlyInt = !!field.onlyInt;
|
||||
}
|
||||
|
||||
if (field.type === 'autodate') {
|
||||
payload.onCreate = typeof field.onCreate === 'boolean' ? field.onCreate : true;
|
||||
payload.onUpdate = typeof field.onUpdate === 'boolean' ? field.onUpdate : false;
|
||||
}
|
||||
|
||||
if (field.type === 'file') {
|
||||
payload.maxSelect = typeof field.maxSelect === 'number' ? field.maxSelect : 0;
|
||||
payload.maxSize = typeof field.maxSize === 'number' ? field.maxSize : 0;
|
||||
payload.mimeTypes = Array.isArray(field.mimeTypes) ? field.mimeTypes : null;
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
function mergeRuleWithSoftDelete(rule) {
|
||||
const currentRule = typeof rule === 'string' ? rule.trim() : '';
|
||||
|
||||
if (!currentRule) return SOFT_DELETE_RULE;
|
||||
if (currentRule === SOFT_DELETE_RULE) return currentRule;
|
||||
if (currentRule.includes(SOFT_DELETE_RULE)) return currentRule;
|
||||
|
||||
return `(${currentRule}) && ${SOFT_DELETE_RULE}`;
|
||||
}
|
||||
|
||||
function buildCollectionPayload(collection) {
|
||||
return {
|
||||
name: collection.name,
|
||||
type: collection.type,
|
||||
listRule: mergeRuleWithSoftDelete(collection.listRule),
|
||||
viewRule: mergeRuleWithSoftDelete(collection.viewRule),
|
||||
createRule: collection.createRule,
|
||||
updateRule: collection.updateRule,
|
||||
deleteRule: collection.deleteRule,
|
||||
fields: (collection.fields || []).filter((field) => field && field.name !== 'id').map((field) => normalizeFieldPayload(field)),
|
||||
indexes: collection.indexes || [],
|
||||
};
|
||||
}
|
||||
|
||||
async function applyRules() {
|
||||
const collections = await pb.collections.getFullList({ sort: 'name' });
|
||||
const changed = [];
|
||||
|
||||
for (const collection of collections) {
|
||||
if (isSystemCollection(collection)) continue;
|
||||
|
||||
const hasSoftDelete = (collection.fields || []).some((field) => field && field.name === 'is_delete');
|
||||
if (!hasSoftDelete) continue;
|
||||
|
||||
const nextListRule = mergeRuleWithSoftDelete(collection.listRule);
|
||||
const nextViewRule = mergeRuleWithSoftDelete(collection.viewRule);
|
||||
const listChanged = nextListRule !== (collection.listRule || '');
|
||||
const viewChanged = nextViewRule !== (collection.viewRule || '');
|
||||
|
||||
if (!listChanged && !viewChanged) {
|
||||
changed.push({ name: collection.name, action: 'skipped', listRule: nextListRule, viewRule: nextViewRule });
|
||||
continue;
|
||||
}
|
||||
|
||||
await pb.collections.update(collection.id, buildCollectionPayload(collection));
|
||||
changed.push({ name: collection.name, action: 'updated', listRule: nextListRule, viewRule: nextViewRule });
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
async function verifyRules() {
|
||||
const collections = await pb.collections.getFullList({ sort: 'name' });
|
||||
const failed = [];
|
||||
|
||||
for (const collection of collections) {
|
||||
if (isSystemCollection(collection)) continue;
|
||||
const hasSoftDelete = (collection.fields || []).some((field) => field && field.name === 'is_delete');
|
||||
if (!hasSoftDelete) continue;
|
||||
|
||||
const listRule = String(collection.listRule || '');
|
||||
const viewRule = String(collection.viewRule || '');
|
||||
|
||||
if (!listRule.includes(SOFT_DELETE_RULE) || !viewRule.includes(SOFT_DELETE_RULE)) {
|
||||
failed.push({ name: collection.name, listRule, viewRule });
|
||||
}
|
||||
}
|
||||
|
||||
if (failed.length) {
|
||||
throw new Error(`以下集合未正确应用软删除规则: ${JSON.stringify(failed, null, 2)}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log(`🔄 正在连接 PocketBase: ${PB_URL}`);
|
||||
pb.authStore.save(AUTH_TOKEN, null);
|
||||
console.log('✅ 已使用 POCKETBASE_AUTH_TOKEN 载入认证状态。');
|
||||
|
||||
const changed = await applyRules();
|
||||
console.log('📝 规则更新结果:');
|
||||
console.log(JSON.stringify(changed, null, 2));
|
||||
|
||||
await verifyRules();
|
||||
console.log('✅ 校验通过:所有带 is_delete 的业务集合已默认过滤 is_delete = 0。');
|
||||
console.log('🎉 软删除默认查询规则迁移完成!');
|
||||
} catch (error) {
|
||||
console.error('❌ 软删除默认查询规则迁移失败:', error.response?.data || error.message || error);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -15,6 +15,7 @@ const AUTH_TOKEN = process.env.POCKETBASE_AUTH_TOKEN || runtimeConfig.POCKETBASE
|
||||
const OWNER_AUTH_RULE = '@request.auth.id != ""';
|
||||
const CART_OWNER_MATCH_RULE = 'cart_owner = @request.auth.openid';
|
||||
const ORDER_OWNER_MATCH_RULE = 'order_owner = @request.auth.openid';
|
||||
const SOFT_DELETE_RULE = 'is_delete = 0';
|
||||
|
||||
if (!AUTH_TOKEN) {
|
||||
console.error('❌ 缺少 POCKETBASE_AUTH_TOKEN,无法执行建表。');
|
||||
@@ -27,13 +28,13 @@ const collections = [
|
||||
{
|
||||
name: 'tbl_cart',
|
||||
type: 'base',
|
||||
listRule: `${OWNER_AUTH_RULE} && ${CART_OWNER_MATCH_RULE}`,
|
||||
viewRule: `${OWNER_AUTH_RULE} && ${CART_OWNER_MATCH_RULE}`,
|
||||
listRule: `${OWNER_AUTH_RULE} && ${CART_OWNER_MATCH_RULE} && ${SOFT_DELETE_RULE}`,
|
||||
viewRule: `${OWNER_AUTH_RULE} && ${CART_OWNER_MATCH_RULE} && ${SOFT_DELETE_RULE}`,
|
||||
createRule: `${OWNER_AUTH_RULE} && @request.body.cart_owner = @request.auth.openid`,
|
||||
updateRule: `${OWNER_AUTH_RULE} && ${CART_OWNER_MATCH_RULE}`,
|
||||
deleteRule: `${OWNER_AUTH_RULE} && ${CART_OWNER_MATCH_RULE}`,
|
||||
fields: [
|
||||
{ name: 'cart_id', type: 'text', required: true },
|
||||
{ name: 'cart_id', type: 'text', required: true, autogeneratePattern: 'CART-[0-9]{13}-[A-Za-z0-9]{6}' },
|
||||
{ name: 'cart_number', type: 'text', required: true },
|
||||
{ name: 'cart_create', type: 'autodate', onCreate: true, onUpdate: false },
|
||||
{ name: 'cart_owner', type: 'text', required: true },
|
||||
@@ -42,6 +43,7 @@ const collections = [
|
||||
{ name: 'cart_status', type: 'text', required: true },
|
||||
{ name: 'cart_at_price', type: 'number', required: true },
|
||||
{ name: 'cart_remark', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true },
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_cart_cart_id ON tbl_cart (cart_id)',
|
||||
@@ -57,13 +59,13 @@ const collections = [
|
||||
{
|
||||
name: 'tbl_order',
|
||||
type: 'base',
|
||||
listRule: `${OWNER_AUTH_RULE} && ${ORDER_OWNER_MATCH_RULE}`,
|
||||
viewRule: `${OWNER_AUTH_RULE} && ${ORDER_OWNER_MATCH_RULE}`,
|
||||
listRule: `${OWNER_AUTH_RULE} && ${ORDER_OWNER_MATCH_RULE} && ${SOFT_DELETE_RULE}`,
|
||||
viewRule: `${OWNER_AUTH_RULE} && ${ORDER_OWNER_MATCH_RULE} && ${SOFT_DELETE_RULE}`,
|
||||
createRule: `${OWNER_AUTH_RULE} && @request.body.order_owner = @request.auth.openid`,
|
||||
updateRule: `${OWNER_AUTH_RULE} && ${ORDER_OWNER_MATCH_RULE}`,
|
||||
deleteRule: `${OWNER_AUTH_RULE} && ${ORDER_OWNER_MATCH_RULE}`,
|
||||
fields: [
|
||||
{ name: 'order_id', type: 'text', required: true },
|
||||
{ name: 'order_id', type: 'text', required: true, autogeneratePattern: 'ORDER-[0-9]{13}-[A-Za-z0-9]{6}' },
|
||||
{ name: 'order_number', type: 'text', required: true },
|
||||
{ name: 'order_create', type: 'autodate', onCreate: true, onUpdate: false },
|
||||
{ name: 'order_owner', type: 'text', required: true },
|
||||
@@ -73,6 +75,7 @@ const collections = [
|
||||
{ name: 'order_snap', type: 'json', required: true },
|
||||
{ name: 'order_amount', type: 'number', required: true },
|
||||
{ name: 'order_remark', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true },
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_order_order_id ON tbl_order (order_id)',
|
||||
|
||||
@@ -12,6 +12,7 @@ try {
|
||||
|
||||
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,无法执行字典建表。');
|
||||
@@ -23,8 +24,8 @@ const pb = new PocketBase(PB_URL);
|
||||
const collectionData = {
|
||||
name: 'tbl_system_dict',
|
||||
type: 'base',
|
||||
listRule: '',
|
||||
viewRule: '',
|
||||
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")',
|
||||
@@ -38,6 +39,7 @@ const collectionData = {
|
||||
{ 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)',
|
||||
|
||||
@@ -12,6 +12,7 @@ try {
|
||||
|
||||
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,无法执行建表。');
|
||||
@@ -24,8 +25,8 @@ const collections = [
|
||||
{
|
||||
name: 'tbl_attachments',
|
||||
type: 'base',
|
||||
listRule: '',
|
||||
viewRule: '',
|
||||
listRule: SOFT_DELETE_RULE,
|
||||
viewRule: SOFT_DELETE_RULE,
|
||||
fields: [
|
||||
{ name: 'attachments_id', type: 'text', required: true },
|
||||
{ name: 'attachments_link', type: 'file', maxSelect: 0, maxSize: 4294967296, mimeTypes: [] },
|
||||
@@ -37,6 +38,7 @@ const collections = [
|
||||
{ name: 'attachments_ocr', type: 'text' },
|
||||
{ name: 'attachments_status', type: 'text' },
|
||||
{ name: 'attachments_remark', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true },
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_attachments_attachments_id ON tbl_attachments (attachments_id)',
|
||||
@@ -47,8 +49,8 @@ const collections = [
|
||||
{
|
||||
name: 'tbl_document',
|
||||
type: 'base',
|
||||
listRule: '',
|
||||
viewRule: '',
|
||||
listRule: SOFT_DELETE_RULE,
|
||||
viewRule: SOFT_DELETE_RULE,
|
||||
fields: [
|
||||
{ name: 'document_id', type: 'text', required: true },
|
||||
{ name: 'document_create', type: 'autodate', onCreate: true, onUpdate: false },
|
||||
@@ -77,6 +79,7 @@ const collections = [
|
||||
{ name: 'document_application_scenarios', type: 'text' },
|
||||
{ name: 'document_hotel_type', type: 'text' },
|
||||
{ name: 'document_remark', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true },
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_document_document_id ON tbl_document (document_id)',
|
||||
@@ -99,6 +102,7 @@ const collections = [
|
||||
{ name: 'doh_user_id', type: 'text' },
|
||||
{ name: 'doh_current_count', type: 'number' },
|
||||
{ name: 'doh_remark', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true },
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_document_operation_history_doh_id ON tbl_document_operation_history (doh_id)',
|
||||
|
||||
198
script/pocketbase.ensure-cart-order-autogen-id.js
Normal file
198
script/pocketbase.ensure-cart-order-autogen-id.js
Normal file
@@ -0,0 +1,198 @@
|
||||
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 PB_URL = String(
|
||||
process.env.PB_URL
|
||||
|| backendEnv.POCKETBASE_API_URL
|
||||
|| runtimeConfig.POCKETBASE_API_URL
|
||||
|| 'http://127.0.0.1:8090'
|
||||
).replace(/\/+$/, '');
|
||||
const AUTH_TOKEN = process.env.POCKETBASE_AUTH_TOKEN || runtimeConfig.POCKETBASE_AUTH_TOKEN || '';
|
||||
|
||||
if (!AUTH_TOKEN) {
|
||||
console.error('❌ 缺少 POCKETBASE_AUTH_TOKEN,无法执行 cart/order 业务 ID 自动生成迁移。');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const pb = new PocketBase(PB_URL);
|
||||
|
||||
const TARGETS = [
|
||||
{
|
||||
collectionName: 'tbl_cart',
|
||||
fieldName: 'cart_id',
|
||||
autogeneratePattern: 'CART-[0-9]{13}-[A-Za-z0-9]{6}',
|
||||
},
|
||||
{
|
||||
collectionName: 'tbl_order',
|
||||
fieldName: 'order_id',
|
||||
autogeneratePattern: 'ORDER-[0-9]{13}-[A-Za-z0-9]{6}',
|
||||
},
|
||||
];
|
||||
|
||||
function normalizeFieldPayload(field, overrides) {
|
||||
const payload = Object.assign({}, field, overrides || {});
|
||||
|
||||
if (payload.type === 'number') {
|
||||
if (Object.prototype.hasOwnProperty.call(payload, 'onlyInt')) payload.onlyInt = !!payload.onlyInt;
|
||||
}
|
||||
|
||||
if (payload.type === 'autodate') {
|
||||
payload.onCreate = typeof payload.onCreate === 'boolean' ? payload.onCreate : true;
|
||||
payload.onUpdate = typeof payload.onUpdate === 'boolean' ? payload.onUpdate : false;
|
||||
}
|
||||
|
||||
if (payload.type === 'file') {
|
||||
payload.maxSelect = typeof payload.maxSelect === 'number' ? payload.maxSelect : 0;
|
||||
payload.maxSize = typeof payload.maxSize === 'number' ? payload.maxSize : 0;
|
||||
payload.mimeTypes = Array.isArray(payload.mimeTypes) ? payload.mimeTypes : null;
|
||||
}
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
function buildCollectionPayload(collection, fields) {
|
||||
return {
|
||||
name: collection.name,
|
||||
type: collection.type,
|
||||
listRule: collection.listRule,
|
||||
viewRule: collection.viewRule,
|
||||
createRule: collection.createRule,
|
||||
updateRule: collection.updateRule,
|
||||
deleteRule: collection.deleteRule,
|
||||
fields,
|
||||
indexes: collection.indexes || [],
|
||||
};
|
||||
}
|
||||
|
||||
async function ensureAutoGenerateField(target) {
|
||||
const collection = await pb.collections.getOne(target.collectionName);
|
||||
const fields = Array.isArray(collection.fields) ? collection.fields : [];
|
||||
const existingField = fields.find((field) => field && field.name === target.fieldName);
|
||||
|
||||
if (!existingField) {
|
||||
throw new Error(`${target.collectionName}.${target.fieldName} 不存在`);
|
||||
}
|
||||
|
||||
const currentPattern = String(existingField.autogeneratePattern || '');
|
||||
if (existingField.type === 'text' && currentPattern === target.autogeneratePattern) {
|
||||
return {
|
||||
collectionName: target.collectionName,
|
||||
fieldName: target.fieldName,
|
||||
action: 'skipped',
|
||||
autogeneratePattern: currentPattern,
|
||||
};
|
||||
}
|
||||
|
||||
const nextFields = fields
|
||||
.filter((field) => field && field.name !== 'id')
|
||||
.map((field) => {
|
||||
if (field.name !== target.fieldName) {
|
||||
return normalizeFieldPayload(field);
|
||||
}
|
||||
|
||||
return normalizeFieldPayload(field, {
|
||||
type: 'text',
|
||||
required: true,
|
||||
autogeneratePattern: target.autogeneratePattern,
|
||||
});
|
||||
});
|
||||
|
||||
await pb.collections.update(collection.id, buildCollectionPayload(collection, nextFields));
|
||||
|
||||
return {
|
||||
collectionName: target.collectionName,
|
||||
fieldName: target.fieldName,
|
||||
action: 'updated',
|
||||
autogeneratePattern: target.autogeneratePattern,
|
||||
};
|
||||
}
|
||||
|
||||
async function verifyTargets() {
|
||||
const result = [];
|
||||
|
||||
for (const target of TARGETS) {
|
||||
const collection = await pb.collections.getOne(target.collectionName);
|
||||
const field = (collection.fields || []).find((item) => item && item.name === target.fieldName);
|
||||
const pattern = String(field && field.autogeneratePattern || '');
|
||||
const ok = !!field && field.type === 'text' && pattern === target.autogeneratePattern;
|
||||
|
||||
result.push({
|
||||
collectionName: target.collectionName,
|
||||
fieldName: target.fieldName,
|
||||
type: field ? field.type : '',
|
||||
required: !!(field && field.required),
|
||||
autogeneratePattern: pattern,
|
||||
ok,
|
||||
});
|
||||
}
|
||||
|
||||
const failed = result.filter((item) => !item.ok);
|
||||
if (failed.length) {
|
||||
throw new Error(`以下字段未正确启用自动生成: ${JSON.stringify(failed, null, 2)}`);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
console.log(`🔄 正在连接 PocketBase: ${PB_URL}`);
|
||||
pb.authStore.save(AUTH_TOKEN, null);
|
||||
console.log('✅ 已使用 POCKETBASE_AUTH_TOKEN 载入认证状态。');
|
||||
|
||||
const changed = [];
|
||||
for (const target of TARGETS) {
|
||||
changed.push(await ensureAutoGenerateField(target));
|
||||
}
|
||||
|
||||
console.log('📝 业务 ID 自动生成处理结果:');
|
||||
console.log(JSON.stringify(changed, null, 2));
|
||||
|
||||
const verified = await verifyTargets();
|
||||
console.log('📝 校验结果:');
|
||||
console.log(JSON.stringify(verified, null, 2));
|
||||
|
||||
console.log('🎉 cart_id / order_id 自动生成规则已就绪。');
|
||||
} catch (error) {
|
||||
console.error('❌ cart/order 业务 ID 自动生成迁移失败:', error.response?.data || error.message || error);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -8,13 +8,14 @@ const ADMIN_PASSWORD = 'Momo123456';
|
||||
// ==========================================
|
||||
|
||||
const pb = new PocketBase(PB_URL);
|
||||
const SOFT_DELETE_RULE = 'is_delete = 0';
|
||||
|
||||
const collections = [
|
||||
{
|
||||
name: 'tbl_system_dict',
|
||||
type: 'base',
|
||||
listRule: '',
|
||||
viewRule: '',
|
||||
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")',
|
||||
@@ -26,7 +27,8 @@ const collections = [
|
||||
{ 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: '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)',
|
||||
@@ -56,7 +58,8 @@ const collections = [
|
||||
{ name: 'company_status', type: 'text' },
|
||||
{ name: 'company_level', type: 'text' },
|
||||
{ name: 'company_owner_openid', type: 'text' },
|
||||
{ name: 'company_remark', type: 'text' }
|
||||
{ name: 'company_remark', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true }
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_company_id ON tbl_company (company_id)',
|
||||
@@ -71,7 +74,8 @@ const collections = [
|
||||
{ name: 'usergroups_id', type: 'text', required: true },
|
||||
{ name: 'usergroups_name', type: 'text' },
|
||||
{ name: 'usergroups_level', type: 'number' },
|
||||
{ name: 'usergroups_remark', type: 'text' }
|
||||
{ name: 'usergroups_remark', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true }
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_usergroups_id ON tbl_user_groups (usergroups_id)'
|
||||
@@ -97,7 +101,8 @@ const collections = [
|
||||
{ name: 'users_id_pic_b', type: 'text' },
|
||||
{ name: 'users_title_picture', type: 'text' },
|
||||
{ name: 'users_picture', type: 'text' },
|
||||
{ name: 'usergroups_id', type: 'text' }
|
||||
{ name: 'usergroups_id', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true }
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_users_id ON tbl_users (users_id)',
|
||||
|
||||
@@ -32,13 +32,14 @@ const ADMIN_PASSWORD = process.env.PB_ADMIN_PASSWORD || backendEnv.PB_ADMIN_PASS
|
||||
const AUTH_TOKEN = process.env.POCKETBASE_AUTH_TOKEN || backendEnv.POCKETBASE_AUTH_TOKEN || '';
|
||||
|
||||
const pb = new PocketBase(PB_URL);
|
||||
const SOFT_DELETE_RULE = 'is_delete = 0';
|
||||
|
||||
const collections = [
|
||||
{
|
||||
name: 'tbl_auth_users',
|
||||
type: 'auth',
|
||||
listRule: '@request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB"',
|
||||
viewRule: '@request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB"',
|
||||
listRule: '@request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB" && is_delete = 0',
|
||||
viewRule: '@request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB" && is_delete = 0',
|
||||
createRule: '',
|
||||
updateRule: '',
|
||||
deleteRule: '@request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB"',
|
||||
@@ -66,6 +67,7 @@ const collections = [
|
||||
{ name: 'users_id_pic_b', type: 'text' },
|
||||
{ name: 'users_title_picture', type: 'text' },
|
||||
{ name: 'users_picture', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true },
|
||||
{ name: 'usergroups_id', type: 'text' }
|
||||
],
|
||||
indexes: [
|
||||
@@ -86,11 +88,14 @@ const collections = [
|
||||
{
|
||||
name: 'tbl_auth_resources',
|
||||
type: 'base',
|
||||
listRule: SOFT_DELETE_RULE,
|
||||
viewRule: SOFT_DELETE_RULE,
|
||||
fields: [
|
||||
{ name: 'res_id', type: 'text', required: true },
|
||||
{ name: 'table_name', type: 'text', required: true },
|
||||
{ name: 'column_name', type: 'text' },
|
||||
{ name: 'res_type', type: 'text', required: true }
|
||||
{ name: 'res_type', type: 'text', required: true },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true }
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_auth_resources_res_id ON tbl_auth_resources (res_id)',
|
||||
@@ -102,12 +107,15 @@ const collections = [
|
||||
{
|
||||
name: 'tbl_auth_roles',
|
||||
type: 'base',
|
||||
listRule: SOFT_DELETE_RULE,
|
||||
viewRule: SOFT_DELETE_RULE,
|
||||
fields: [
|
||||
{ name: 'role_id', type: 'text', required: true },
|
||||
{ name: 'role_name', type: 'text', required: true },
|
||||
{ name: 'role_code', type: 'text' },
|
||||
{ name: 'role_status', type: 'number' },
|
||||
{ name: 'role_remark', type: 'text' }
|
||||
{ name: 'role_remark', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true }
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_auth_roles_role_id ON tbl_auth_roles (role_id)',
|
||||
@@ -118,12 +126,15 @@ const collections = [
|
||||
{
|
||||
name: 'tbl_auth_role_perms',
|
||||
type: 'base',
|
||||
listRule: SOFT_DELETE_RULE,
|
||||
viewRule: SOFT_DELETE_RULE,
|
||||
fields: [
|
||||
{ name: 'role_perm_id', type: 'text', required: true },
|
||||
{ name: 'role_id', type: 'text', required: true },
|
||||
{ name: 'res_id', type: 'text', required: true },
|
||||
{ name: 'access_level', type: 'number', required: true },
|
||||
{ name: 'priority', type: 'number' }
|
||||
{ name: 'priority', type: 'number' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true }
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_auth_role_perms_role_perm_id ON tbl_auth_role_perms (role_perm_id)',
|
||||
@@ -135,12 +146,15 @@ const collections = [
|
||||
{
|
||||
name: 'tbl_auth_user_overrides',
|
||||
type: 'base',
|
||||
listRule: SOFT_DELETE_RULE,
|
||||
viewRule: SOFT_DELETE_RULE,
|
||||
fields: [
|
||||
{ name: 'override_id', type: 'text', required: true },
|
||||
{ name: 'users_convers_id', type: 'text', required: true },
|
||||
{ name: 'res_id', type: 'text', required: true },
|
||||
{ name: 'access_level', type: 'number', required: true },
|
||||
{ name: 'priority', type: 'number' }
|
||||
{ name: 'priority', type: 'number' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true }
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_auth_user_overrides_override_id ON tbl_auth_user_overrides (override_id)',
|
||||
@@ -152,12 +166,15 @@ const collections = [
|
||||
{
|
||||
name: 'tbl_auth_row_scopes',
|
||||
type: 'base',
|
||||
listRule: SOFT_DELETE_RULE,
|
||||
viewRule: SOFT_DELETE_RULE,
|
||||
fields: [
|
||||
{ name: 'scope_id', type: 'text', required: true },
|
||||
{ name: 'target_type', type: 'text', required: true },
|
||||
{ name: 'target_id', type: 'text', required: true },
|
||||
{ name: 'table_name', type: 'text', required: true },
|
||||
{ name: 'filter_sql', type: 'editor', required: true }
|
||||
{ name: 'filter_sql', type: 'editor', required: true },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true }
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_auth_row_scopes_scope_id ON tbl_auth_row_scopes (scope_id)',
|
||||
|
||||
@@ -12,6 +12,7 @@ try {
|
||||
|
||||
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,无法执行建表。');
|
||||
@@ -25,8 +26,8 @@ const collections = [
|
||||
name: 'tbl_product_list',
|
||||
type: 'base',
|
||||
// Empty rules in PocketBase mean public read access.
|
||||
listRule: '',
|
||||
viewRule: '',
|
||||
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")',
|
||||
@@ -50,6 +51,7 @@ const collections = [
|
||||
{ name: 'prod_list_basic_price', type: 'number' },
|
||||
{ name: 'prod_list_vip_price', type: 'json' },
|
||||
{ name: 'prod_list_remark', type: 'text' },
|
||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true },
|
||||
],
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_tbl_product_list_prod_list_id ON tbl_product_list (prod_list_id)',
|
||||
@@ -108,7 +110,9 @@ function buildCollectionPayload(collectionData, existingCollection) {
|
||||
}
|
||||
|
||||
const targetFieldMap = new Map(collectionData.fields.map((field) => [field.name, field]));
|
||||
const fields = (existingCollection.fields || []).map((existingField) => {
|
||||
const fields = (existingCollection.fields || []).filter((existingField) => {
|
||||
return existingField && existingField.name !== 'id';
|
||||
}).map((existingField) => {
|
||||
const targetField = targetFieldMap.get(existingField.name);
|
||||
if (!targetField) {
|
||||
return existingField;
|
||||
|
||||
Reference in New Issue
Block a user