feat: 添加订单相关字段和自动生成规则,包括订单商品数量和支付状态;更新文档和迁移脚本
This commit is contained in:
@@ -10,8 +10,8 @@
|
|||||||
|
|
||||||
当前结构按“一个订单一条记录”设计:
|
当前结构按“一个订单一条记录”设计:
|
||||||
|
|
||||||
- `order_id` 是订单业务 ID
|
- `order_id` 是订单业务 ID,由数据库自动生成(`ORDER-时间戳-随机串`)
|
||||||
- `order_number` 是订单编号,建议按“用户名+年月日时分秒”或统一编号规则生成
|
- `order_number` 是订单编号,由 PocketBase 原生字段自动生成纯数字编号(`[0-9]{18}`)
|
||||||
- `order_snap` 使用 JSON 完整保存下单时的商品、数量、价格、折扣等快照,避免后续商品数据变化影响历史订单
|
- `order_snap` 使用 JSON 完整保存下单时的商品、数量、价格、折扣等快照,避免后续商品数据变化影响历史订单
|
||||||
|
|
||||||
## 字段清单
|
## 字段清单
|
||||||
@@ -19,14 +19,16 @@
|
|||||||
| 字段名 | 类型 | 必填 | 说明 |
|
| 字段名 | 类型 | 必填 | 说明 |
|
||||||
| :--- | :--- | :---: | :--- |
|
| :--- | :--- | :---: | :--- |
|
||||||
| `id` | `text` | 是 | PocketBase 记录主键 |
|
| `id` | `text` | 是 | PocketBase 记录主键 |
|
||||||
| `order_id` | `text` | 是 | 订单业务 ID,唯一标识 |
|
| `order_id` | `text` | 是 | 订单业务 ID,唯一标识;数据库自动生成,格式:`ORDER-[0-9]{13}-[A-Za-z0-9]{6}` |
|
||||||
| `order_number` | `text` | 是 | 订单编号,建议业务侧自动生成并保证可追踪 |
|
| `order_number` | `text` | 是 | 订单编号,PocketBase 原生自动生成 18 位纯数字(`[0-9]{18}`),唯一可追踪 |
|
||||||
| `order_create` | `autodate` | 否 | 订单创建时间,由数据库自动生成 |
|
| `order_create` | `autodate` | 否 | 订单创建时间,由数据库自动生成 |
|
||||||
| `order_owner` | `text` | 是 | 生成者 openid,约定保存 `tbl_auth_users.openid` |
|
| `order_owner` | `text` | 是 | 生成者 openid,约定保存 `tbl_auth_users.openid` |
|
||||||
| `order_source` | `text` | 是 | 订单来源,建议值:`购物车` / `方案清单` |
|
| `order_source` | `text` | 是 | 订单来源,建议值:`购物车` / `方案清单` |
|
||||||
| `order_status` | `text` | 是 | 订单状态,建议值:`订单已生成` / `订单已确定` / `订单已交付` / `订单已验收` / `订单已结束` |
|
| `order_status` | `text` | 是 | 订单状态,建议值:`订单已生成` / `订单已确定` / `订单已交付` / `订单已验收` / `订单已结束` |
|
||||||
| `order_source_id` | `text` | 是 | 订单来源关联 ID,如购物车 ID 或方案清单 ID |
|
| `order_source_id` | `text` | 是 | 订单来源关联 ID,如购物车 ID 或方案清单 ID |
|
||||||
| `order_snap` | `json` | 是 | 订单快照,完整保存订单明细信息 |
|
| `order_snap` | `json` | 是 | 订单快照,完整保存订单明细信息 |
|
||||||
|
| `order_product_quantity` | `number` | 否 | 订单商品总数量,允许为空,不建立索引 |
|
||||||
|
| `order_pay_status` | `text` | 否 | 订单支付状态,允许为空,不建立索引 |
|
||||||
| `order_amount` | `number` | 是 | 订单总金额 |
|
| `order_amount` | `number` | 是 | 订单总金额 |
|
||||||
| `order_remark` | `text` | 否 | 订单备注 |
|
| `order_remark` | `text` | 否 | 订单备注 |
|
||||||
| `is_delete` | `number` | 否 | 软删除标记,`0` 表示未删除,`1` 表示已删除,默认 `0` |
|
| `is_delete` | `number` | 否 | 软删除标记,`0` 表示未删除,`1` 表示已删除,默认 `0` |
|
||||||
|
|||||||
@@ -608,8 +608,7 @@ function createOrder(authState, payload) {
|
|||||||
const collection = $app.findCollectionByNameOrId('tbl_order')
|
const collection = $app.findCollectionByNameOrId('tbl_order')
|
||||||
const record = new Record(collection)
|
const record = new Record(collection)
|
||||||
|
|
||||||
record.set('order_id', buildBusinessId('ORDER'))
|
// order_id / order_number are generated by PocketBase native field rules.
|
||||||
record.set('order_number', normalizeText(payload.order_number) || buildDisplayNumber('ORDER', authState.authRecord, authState.openid))
|
|
||||||
record.set('order_owner', authState.openid)
|
record.set('order_owner', authState.openid)
|
||||||
record.set('order_source', normalizeOrderSource(payload.order_source))
|
record.set('order_source', normalizeOrderSource(payload.order_source))
|
||||||
record.set('order_status', normalizeOrderStatus(payload.order_status))
|
record.set('order_status', normalizeOrderStatus(payload.order_status))
|
||||||
|
|||||||
@@ -232,6 +232,74 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/PocketBaseNativeError'
|
$ref: '#/components/schemas/PocketBaseNativeError'
|
||||||
|
/pb/api/batch:
|
||||||
|
post:
|
||||||
|
operationId: postPocketBaseCartBatchUpdate
|
||||||
|
tags: [购物车]
|
||||||
|
summary: 批量更新购物车记录
|
||||||
|
description: |
|
||||||
|
使用 PocketBase 原生 batch 接口批量更新 `tbl_cart` 记录。
|
||||||
|
|
||||||
|
说明:
|
||||||
|
- 这是 PocketBase 原生批处理接口,不是 hooks。
|
||||||
|
- 单次请求可提交多条 `PATCH /api/collections/tbl_cart/records/{recordId}` 子请求。
|
||||||
|
- 每条子请求仍按原生 collection rule 校验权限。
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PocketBaseCartBatchRequest'
|
||||||
|
example:
|
||||||
|
requests:
|
||||||
|
- method: PATCH|string
|
||||||
|
url: /api/collections/tbl_cart/records/PocketBase记录主键|string
|
||||||
|
headers:
|
||||||
|
Content-Type: application/json|string
|
||||||
|
body:
|
||||||
|
cart_number: 购物车名称或分组号|string
|
||||||
|
cart_product_quantity: 产品数量|integer
|
||||||
|
cart_status: 购物车状态|string
|
||||||
|
cart_at_price: 加入购物车时价格|number
|
||||||
|
cart_remark: 备注|string
|
||||||
|
- method: PATCH|string
|
||||||
|
url: /api/collections/tbl_cart/records/PocketBase记录主键|string
|
||||||
|
headers:
|
||||||
|
Content-Type: application/json|string
|
||||||
|
body:
|
||||||
|
cart_status: 购物车状态|string
|
||||||
|
cart_remark: 备注|string
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: 批量处理成功
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PocketBaseBatchResponse'
|
||||||
|
'400':
|
||||||
|
description: 批处理参数错误
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PocketBaseNativeError'
|
||||||
|
'401':
|
||||||
|
description: token 无效或已过期
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PocketBaseNativeError'
|
||||||
|
'403':
|
||||||
|
description: 无权访问其中一条或多条记录
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PocketBaseNativeError'
|
||||||
|
'500':
|
||||||
|
description: 服务端错误
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PocketBaseNativeError'
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
PocketBaseNativeError:
|
PocketBaseNativeError:
|
||||||
@@ -397,6 +465,57 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: '#/components/schemas/PocketBaseCartRecord'
|
$ref: '#/components/schemas/PocketBaseCartRecord'
|
||||||
|
PocketBaseCartBatchItem:
|
||||||
|
type: object
|
||||||
|
required: [method, url, body]
|
||||||
|
properties:
|
||||||
|
method:
|
||||||
|
type: string
|
||||||
|
description: HTTP 方法
|
||||||
|
example: PATCH|string
|
||||||
|
url:
|
||||||
|
type: string
|
||||||
|
description: PocketBase 子请求路径
|
||||||
|
example: /api/collections/tbl_cart/records/PocketBase记录主键|string
|
||||||
|
headers:
|
||||||
|
type: object
|
||||||
|
description: 子请求头
|
||||||
|
additionalProperties:
|
||||||
|
type: string
|
||||||
|
example:
|
||||||
|
Content-Type: application/json|string
|
||||||
|
body:
|
||||||
|
$ref: '#/components/schemas/PocketBaseCartUpdateRequest'
|
||||||
|
PocketBaseCartBatchRequest:
|
||||||
|
type: object
|
||||||
|
required: [requests]
|
||||||
|
properties:
|
||||||
|
requests:
|
||||||
|
type: array
|
||||||
|
description: 批量子请求列表
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/PocketBaseCartBatchItem'
|
||||||
|
PocketBaseBatchResponseItem:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: [integer, string]
|
||||||
|
description: 子请求响应状态码
|
||||||
|
example: 子请求状态码|integer
|
||||||
|
body:
|
||||||
|
type: object
|
||||||
|
description: 子请求响应体
|
||||||
|
additionalProperties: true
|
||||||
|
example:
|
||||||
|
字段名|string: 字段值|string
|
||||||
|
PocketBaseBatchResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
items:
|
||||||
|
type: array
|
||||||
|
description: 批处理结果列表
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/PocketBaseBatchResponseItem'
|
||||||
PocketBaseProductListExpand:
|
PocketBaseProductListExpand:
|
||||||
type: object
|
type: object
|
||||||
description: tbl_product_list 关联展开后的记录对象(示例字段)
|
description: tbl_product_list 关联展开后的记录对象(示例字段)
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ paths:
|
|||||||
operationId: postPocketBaseOrderRecord
|
operationId: postPocketBaseOrderRecord
|
||||||
tags: [订单]
|
tags: [订单]
|
||||||
summary: 创建订单记录
|
summary: 创建订单记录
|
||||||
|
description: |
|
||||||
|
`order_id` 与 `order_number` 由 PocketBase 原生字段自动生成。
|
||||||
|
创建请求不应传入这两个字段,响应中返回生成结果。
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@@ -89,8 +92,6 @@ paths:
|
|||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/PocketBaseOrderCreateRequest'
|
$ref: '#/components/schemas/PocketBaseOrderCreateRequest'
|
||||||
example:
|
example:
|
||||||
order_id: 订单业务ID|string
|
|
||||||
order_number: 订单编号|string
|
|
||||||
order_owner: 订单所有者openid|string
|
order_owner: 订单所有者openid|string
|
||||||
order_source: 订单来源|string
|
order_source: 订单来源|string
|
||||||
order_status: 订单状态|string
|
order_status: 订单状态|string
|
||||||
@@ -271,10 +272,10 @@ components:
|
|||||||
properties:
|
properties:
|
||||||
order_id:
|
order_id:
|
||||||
type: string
|
type: string
|
||||||
description: 订单业务ID
|
description: 订单业务ID(PocketBase 原生自动生成)
|
||||||
order_number:
|
order_number:
|
||||||
type: string
|
type: string
|
||||||
description: 订单编号
|
description: 订单编号(PocketBase 原生自动生成的 18 位纯数字)
|
||||||
order_create:
|
order_create:
|
||||||
type: string
|
type: string
|
||||||
description: 订单创建时间
|
description: 订单创建时间
|
||||||
@@ -299,6 +300,12 @@ components:
|
|||||||
type: object
|
type: object
|
||||||
additionalProperties: true
|
additionalProperties: true
|
||||||
description: 订单快照
|
description: 订单快照
|
||||||
|
order_product_quantity:
|
||||||
|
type: [number, integer]
|
||||||
|
description: 订单商品总数量(可为空)
|
||||||
|
order_pay_status:
|
||||||
|
type: string
|
||||||
|
description: 订单支付状态
|
||||||
order_amount:
|
order_amount:
|
||||||
type: [number, integer]
|
type: [number, integer]
|
||||||
description: 订单金额
|
description: 订单金额
|
||||||
@@ -315,6 +322,8 @@ components:
|
|||||||
order_source_id: 来源关联业务ID|string
|
order_source_id: 来源关联业务ID|string
|
||||||
order_snap:
|
order_snap:
|
||||||
字段名|string: 字段值|string
|
字段名|string: 字段值|string
|
||||||
|
order_product_quantity: 订单商品总数量|number
|
||||||
|
order_pay_status: 订单支付状态|string
|
||||||
order_amount: 订单金额|number
|
order_amount: 订单金额|number
|
||||||
order_remark: 备注|string
|
order_remark: 备注|string
|
||||||
PocketBaseOrderRecord:
|
PocketBaseOrderRecord:
|
||||||
@@ -323,12 +332,10 @@ components:
|
|||||||
- $ref: '#/components/schemas/PocketBaseOrderFields'
|
- $ref: '#/components/schemas/PocketBaseOrderFields'
|
||||||
PocketBaseOrderCreateRequest:
|
PocketBaseOrderCreateRequest:
|
||||||
type: object
|
type: object
|
||||||
required: [order_id, order_number, order_owner, order_source, order_status, order_source_id, order_snap, order_amount]
|
description: |
|
||||||
|
创建订单时无需传入 `order_id`、`order_number`,由 PocketBase 原生字段自动生成。
|
||||||
|
required: [order_owner, order_source, order_status, order_source_id, order_snap, order_amount]
|
||||||
properties:
|
properties:
|
||||||
order_id:
|
|
||||||
type: string
|
|
||||||
order_number:
|
|
||||||
type: string
|
|
||||||
order_owner:
|
order_owner:
|
||||||
type: string
|
type: string
|
||||||
order_source:
|
order_source:
|
||||||
@@ -345,6 +352,10 @@ components:
|
|||||||
items:
|
items:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: true
|
additionalProperties: true
|
||||||
|
order_product_quantity:
|
||||||
|
type: [number, integer]
|
||||||
|
order_pay_status:
|
||||||
|
type: string
|
||||||
order_amount:
|
order_amount:
|
||||||
type: [number, integer]
|
type: [number, integer]
|
||||||
order_remark:
|
order_remark:
|
||||||
@@ -370,6 +381,10 @@ components:
|
|||||||
items:
|
items:
|
||||||
type: object
|
type: object
|
||||||
additionalProperties: true
|
additionalProperties: true
|
||||||
|
order_product_quantity:
|
||||||
|
type: [number, integer]
|
||||||
|
order_pay_status:
|
||||||
|
type: string
|
||||||
order_amount:
|
order_amount:
|
||||||
type: [number, integer]
|
type: [number, integer]
|
||||||
order_remark:
|
order_remark:
|
||||||
|
|||||||
@@ -12,7 +12,10 @@
|
|||||||
"init:scheme": "node pocketbase.scheme.js",
|
"init:scheme": "node pocketbase.scheme.js",
|
||||||
"migrate:file-fields": "node pocketbase.file-fields-to-attachments.js",
|
"migrate:file-fields": "node pocketbase.file-fields-to-attachments.js",
|
||||||
"migrate:add-is-delete-field": "node pocketbase.add-is-delete-field.js",
|
"migrate:add-is-delete-field": "node pocketbase.add-is-delete-field.js",
|
||||||
|
"migrate:add-order-product-quantity-field": "node pocketbase.add-order-product-quantity-field.js",
|
||||||
|
"migrate:add-order-pay-status-field": "node pocketbase.add-order-pay-status-field.js",
|
||||||
"migrate:apply-soft-delete-rules": "node pocketbase.apply-soft-delete-rules.js",
|
"migrate:apply-soft-delete-rules": "node pocketbase.apply-soft-delete-rules.js",
|
||||||
|
"migrate:ensure-order-autogen-fields": "node pocketbase.ensure-order-autogen-fields.js",
|
||||||
"migrate:ensure-cart-order-autogen-id": "node pocketbase.ensure-cart-order-autogen-id.js",
|
"migrate:ensure-cart-order-autogen-id": "node pocketbase.ensure-cart-order-autogen-id.js",
|
||||||
"migrate:cart-active-unique-index": "node pocketbase.cart-active-unique-index.js",
|
"migrate:cart-active-unique-index": "node pocketbase.cart-active-unique-index.js",
|
||||||
"migrate:product-params-array": "node migrate-product-parameters-to-array.js",
|
"migrate:product-params-array": "node migrate-product-parameters-to-array.js",
|
||||||
|
|||||||
187
script/pocketbase.add-order-pay-status-field.js
Normal file
187
script/pocketbase.add-order-pay-status-field.js
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
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,无法执行 tbl_order 字段迁移。');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pb = new PocketBase(PB_URL);
|
||||||
|
|
||||||
|
const TARGET_FIELD = {
|
||||||
|
name: 'order_pay_status',
|
||||||
|
type: 'text',
|
||||||
|
required: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload.type === 'relation') {
|
||||||
|
payload.maxSelect = typeof payload.maxSelect === 'number' ? payload.maxSelect : 1;
|
||||||
|
payload.cascadeDelete = typeof payload.cascadeDelete === 'boolean' ? payload.cascadeDelete : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 migrateField() {
|
||||||
|
const collection = await pb.collections.getOne('tbl_order');
|
||||||
|
const fields = Array.isArray(collection.fields) ? collection.fields : [];
|
||||||
|
const existingField = fields.find((field) => field && field.name === TARGET_FIELD.name);
|
||||||
|
|
||||||
|
const fieldReady = !!existingField
|
||||||
|
&& existingField.type === TARGET_FIELD.type
|
||||||
|
&& existingField.required === TARGET_FIELD.required;
|
||||||
|
|
||||||
|
if (fieldReady) {
|
||||||
|
return {
|
||||||
|
action: 'skipped',
|
||||||
|
field: {
|
||||||
|
name: existingField.name,
|
||||||
|
type: existingField.type,
|
||||||
|
required: !!existingField.required,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextFields = fields
|
||||||
|
.filter((field) => field && field.name !== 'id')
|
||||||
|
.map((field) => {
|
||||||
|
if (field.name === TARGET_FIELD.name) {
|
||||||
|
return normalizeFieldPayload(field, TARGET_FIELD);
|
||||||
|
}
|
||||||
|
return normalizeFieldPayload(field);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existingField) {
|
||||||
|
nextFields.push(normalizeFieldPayload(null, TARGET_FIELD));
|
||||||
|
}
|
||||||
|
|
||||||
|
await pb.collections.update(collection.id, buildCollectionPayload(collection, nextFields));
|
||||||
|
|
||||||
|
return {
|
||||||
|
action: existingField ? 'normalized' : 'added',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verifyField() {
|
||||||
|
const collection = await pb.collections.getOne('tbl_order');
|
||||||
|
const field = (collection.fields || []).find((item) => item && item.name === TARGET_FIELD.name);
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
name: field ? field.name : '',
|
||||||
|
type: field ? field.type : '',
|
||||||
|
required: !!(field && field.required),
|
||||||
|
ok: !!field && field.type === TARGET_FIELD.type && field.required === TARGET_FIELD.required,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!result.ok) {
|
||||||
|
throw new Error('order_pay_status 字段校验失败: ' + JSON.stringify(result, 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 migrated = await migrateField();
|
||||||
|
console.log('📝 迁移结果:');
|
||||||
|
console.log(JSON.stringify(migrated, null, 2));
|
||||||
|
|
||||||
|
const verified = await verifyField();
|
||||||
|
console.log('📝 校验结果:');
|
||||||
|
console.log(JSON.stringify(verified, null, 2));
|
||||||
|
|
||||||
|
console.log('🎉 tbl_order.order_pay_status 字段已就绪。');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ tbl_order 字段迁移失败:');
|
||||||
|
console.error('status:', error && error.status);
|
||||||
|
console.error('message:', error && error.message);
|
||||||
|
console.error('response:', error && error.response);
|
||||||
|
console.error('originalError:', error && error.originalError);
|
||||||
|
console.error('stack:', error && error.stack);
|
||||||
|
process.exitCode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
187
script/pocketbase.add-order-product-quantity-field.js
Normal file
187
script/pocketbase.add-order-product-quantity-field.js
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
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,无法执行 tbl_order 字段迁移。');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pb = new PocketBase(PB_URL);
|
||||||
|
|
||||||
|
const TARGET_FIELD = {
|
||||||
|
name: 'order_product_quantity',
|
||||||
|
type: 'number',
|
||||||
|
required: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload.type === 'relation') {
|
||||||
|
payload.maxSelect = typeof payload.maxSelect === 'number' ? payload.maxSelect : 1;
|
||||||
|
payload.cascadeDelete = typeof payload.cascadeDelete === 'boolean' ? payload.cascadeDelete : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 migrateField() {
|
||||||
|
const collection = await pb.collections.getOne('tbl_order');
|
||||||
|
const fields = Array.isArray(collection.fields) ? collection.fields : [];
|
||||||
|
const existingField = fields.find((field) => field && field.name === TARGET_FIELD.name);
|
||||||
|
|
||||||
|
const fieldReady = !!existingField
|
||||||
|
&& existingField.type === TARGET_FIELD.type
|
||||||
|
&& existingField.required === TARGET_FIELD.required;
|
||||||
|
|
||||||
|
if (fieldReady) {
|
||||||
|
return {
|
||||||
|
action: 'skipped',
|
||||||
|
field: {
|
||||||
|
name: existingField.name,
|
||||||
|
type: existingField.type,
|
||||||
|
required: !!existingField.required,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextFields = fields
|
||||||
|
.filter((field) => field && field.name !== 'id')
|
||||||
|
.map((field) => {
|
||||||
|
if (field.name === TARGET_FIELD.name) {
|
||||||
|
return normalizeFieldPayload(field, TARGET_FIELD);
|
||||||
|
}
|
||||||
|
return normalizeFieldPayload(field);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!existingField) {
|
||||||
|
nextFields.push(normalizeFieldPayload(null, TARGET_FIELD));
|
||||||
|
}
|
||||||
|
|
||||||
|
await pb.collections.update(collection.id, buildCollectionPayload(collection, nextFields));
|
||||||
|
|
||||||
|
return {
|
||||||
|
action: existingField ? 'normalized' : 'added',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verifyField() {
|
||||||
|
const collection = await pb.collections.getOne('tbl_order');
|
||||||
|
const field = (collection.fields || []).find((item) => item && item.name === TARGET_FIELD.name);
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
name: field ? field.name : '',
|
||||||
|
type: field ? field.type : '',
|
||||||
|
required: !!(field && field.required),
|
||||||
|
ok: !!field && field.type === TARGET_FIELD.type && field.required === TARGET_FIELD.required,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!result.ok) {
|
||||||
|
throw new Error('order_product_quantity 字段校验失败: ' + JSON.stringify(result, 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 migrated = await migrateField();
|
||||||
|
console.log('📝 迁移结果:');
|
||||||
|
console.log(JSON.stringify(migrated, null, 2));
|
||||||
|
|
||||||
|
const verified = await verifyField();
|
||||||
|
console.log('📝 校验结果:');
|
||||||
|
console.log(JSON.stringify(verified, null, 2));
|
||||||
|
|
||||||
|
console.log('🎉 tbl_order.order_product_quantity 字段已就绪。');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ tbl_order 字段迁移失败:');
|
||||||
|
console.error('status:', error && error.status);
|
||||||
|
console.error('message:', error && error.message);
|
||||||
|
console.error('response:', error && error.response);
|
||||||
|
console.error('originalError:', error && error.originalError);
|
||||||
|
console.error('stack:', error && error.stack);
|
||||||
|
process.exitCode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
@@ -81,13 +81,15 @@ async function buildCollections() {
|
|||||||
deleteRule: `${OWNER_AUTH_RULE} && ${ORDER_OWNER_MATCH_RULE}`,
|
deleteRule: `${OWNER_AUTH_RULE} && ${ORDER_OWNER_MATCH_RULE}`,
|
||||||
fields: [
|
fields: [
|
||||||
{ name: 'order_id', type: 'text', required: true, autogeneratePattern: 'ORDER-[0-9]{13}-[A-Za-z0-9]{6}' },
|
{ 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_number', type: 'text', required: true, autogeneratePattern: '[0-9]{18}' },
|
||||||
{ name: 'order_create', type: 'autodate', onCreate: true, onUpdate: false },
|
{ name: 'order_create', type: 'autodate', onCreate: true, onUpdate: false },
|
||||||
{ name: 'order_owner', type: 'text', required: true },
|
{ name: 'order_owner', type: 'text', required: true },
|
||||||
{ name: 'order_source', type: 'text', required: true },
|
{ name: 'order_source', type: 'text', required: true },
|
||||||
{ name: 'order_status', type: 'text', required: true },
|
{ name: 'order_status', type: 'text', required: true },
|
||||||
{ name: 'order_source_id', type: 'text', required: true },
|
{ name: 'order_source_id', type: 'text', required: true },
|
||||||
{ name: 'order_snap', type: 'json', required: true },
|
{ name: 'order_snap', type: 'json', required: true },
|
||||||
|
{ name: 'order_product_quantity', type: 'number', required: false },
|
||||||
|
{ name: 'order_pay_status', type: 'text', required: false },
|
||||||
{ name: 'order_amount', type: 'number', required: true },
|
{ name: 'order_amount', type: 'number', required: true },
|
||||||
{ name: 'order_remark', type: 'text' },
|
{ name: 'order_remark', type: 'text' },
|
||||||
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true },
|
{ name: 'is_delete', type: 'number', default: 0, min: 0, max: 1, onlyInt: true },
|
||||||
|
|||||||
209
script/pocketbase.ensure-order-autogen-fields.js
Normal file
209
script/pocketbase.ensure-order-autogen-fields.js
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
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,无法执行 tbl_order 自动编号迁移。');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pb = new PocketBase(PB_URL);
|
||||||
|
|
||||||
|
const ORDER_ID_PATTERN = 'ORDER-[0-9]{13}-[A-Za-z0-9]{6}';
|
||||||
|
const ORDER_NUMBER_PATTERN = '[0-9]{18}';
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload.type === 'relation') {
|
||||||
|
payload.maxSelect = typeof payload.maxSelect === 'number' ? payload.maxSelect : 1;
|
||||||
|
payload.cascadeDelete = typeof payload.cascadeDelete === 'boolean' ? payload.cascadeDelete : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 migrateOrderFields() {
|
||||||
|
const collection = await pb.collections.getOne('tbl_order');
|
||||||
|
const fields = Array.isArray(collection.fields) ? collection.fields : [];
|
||||||
|
|
||||||
|
const orderIdField = fields.find((field) => field && field.name === 'order_id');
|
||||||
|
const orderNumberField = fields.find((field) => field && field.name === 'order_number');
|
||||||
|
|
||||||
|
if (!orderIdField || !orderNumberField) {
|
||||||
|
throw new Error('tbl_order 缺少 order_id 或 order_number 字段');
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderIdReady = orderIdField.type === 'text' && String(orderIdField.autogeneratePattern || '') === ORDER_ID_PATTERN;
|
||||||
|
const orderNumberReady = orderNumberField.type === 'text'
|
||||||
|
&& String(orderNumberField.autogeneratePattern || '') === ORDER_NUMBER_PATTERN;
|
||||||
|
|
||||||
|
if (orderIdReady && orderNumberReady) {
|
||||||
|
return {
|
||||||
|
action: 'skipped',
|
||||||
|
order_id: {
|
||||||
|
type: orderIdField.type,
|
||||||
|
autogeneratePattern: String(orderIdField.autogeneratePattern || ''),
|
||||||
|
},
|
||||||
|
order_number: {
|
||||||
|
type: orderNumberField.type,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextFields = fields
|
||||||
|
.filter((field) => field && field.name !== 'id')
|
||||||
|
.map((field) => {
|
||||||
|
if (field.name === 'order_id') {
|
||||||
|
return normalizeFieldPayload(field, {
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
autogeneratePattern: ORDER_ID_PATTERN,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field.name === 'order_number') {
|
||||||
|
return normalizeFieldPayload(field, {
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
autogeneratePattern: ORDER_NUMBER_PATTERN,
|
||||||
|
pattern: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return normalizeFieldPayload(field);
|
||||||
|
});
|
||||||
|
|
||||||
|
await pb.collections.update(collection.id, buildCollectionPayload(collection, nextFields));
|
||||||
|
|
||||||
|
return {
|
||||||
|
action: 'updated',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verifyOrderFields() {
|
||||||
|
const collection = await pb.collections.getOne('tbl_order');
|
||||||
|
const orderIdField = (collection.fields || []).find((field) => field && field.name === 'order_id');
|
||||||
|
const orderNumberField = (collection.fields || []).find((field) => field && field.name === 'order_number');
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
order_id: {
|
||||||
|
type: orderIdField ? orderIdField.type : '',
|
||||||
|
autogeneratePattern: String(orderIdField && orderIdField.autogeneratePattern || ''),
|
||||||
|
ok: !!orderIdField && orderIdField.type === 'text' && String(orderIdField.autogeneratePattern || '') === ORDER_ID_PATTERN,
|
||||||
|
},
|
||||||
|
order_number: {
|
||||||
|
type: orderNumberField ? orderNumberField.type : '',
|
||||||
|
autogeneratePattern: String(orderNumberField && orderNumberField.autogeneratePattern || ''),
|
||||||
|
ok: !!orderNumberField
|
||||||
|
&& orderNumberField.type === 'text'
|
||||||
|
&& String(orderNumberField.autogeneratePattern || '') === ORDER_NUMBER_PATTERN,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!result.order_id.ok || !result.order_number.ok) {
|
||||||
|
throw new Error('tbl_order 自动编号规则校验失败: ' + JSON.stringify(result, 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 migrated = await migrateOrderFields();
|
||||||
|
console.log('📝 迁移结果:');
|
||||||
|
console.log(JSON.stringify(migrated, null, 2));
|
||||||
|
|
||||||
|
const verified = await verifyOrderFields();
|
||||||
|
console.log('📝 校验结果:');
|
||||||
|
console.log(JSON.stringify(verified, null, 2));
|
||||||
|
|
||||||
|
console.log('🎉 tbl_order 自动编号规则已就绪。');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ tbl_order 自动编号迁移失败:');
|
||||||
|
console.error('status:', error && error.status);
|
||||||
|
console.error('message:', error && error.message);
|
||||||
|
console.error('response:', error && error.response);
|
||||||
|
console.error('originalError:', error && error.originalError);
|
||||||
|
console.error('stack:', error && error.stack);
|
||||||
|
process.exitCode = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
Reference in New Issue
Block a user