feat: 更新 API 响应结构,统一使用 statusCode 和 errMsg 替代 code 和 msg;新增用户类型和公司 ID 字段;优化数据库索引;添加公司所有者同步测试脚本
This commit is contained in:
@@ -54,7 +54,7 @@
|
||||
**索引规划 (Indexes):**
|
||||
* `CREATE UNIQUE INDEX` 针对 `company_id` (确保业务主键唯一)
|
||||
* `CREATE INDEX` 针对 `company_usci` (加速信用代码检索)
|
||||
* `CREATE INDEX` 针对 `company_owner_openid` (加速按公司所有者 openid 查询)
|
||||
* `CREATE UNIQUE INDEX` 针对 `company_owner_openid` (限制同一公司所有者仅能绑定一个公司)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"init:documents": "node pocketbase.documents.js",
|
||||
"init:dictionary": "node pocketbase.dictionary.js",
|
||||
"migrate:file-fields": "node pocketbase.file-fields-to-attachments.js",
|
||||
"test:company-native-api": "node test-tbl-company-native-api.js"
|
||||
"test:company-native-api": "node test-tbl-company-native-api.js",
|
||||
"test:company-owner-sync": "node test-company-owner-sync.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
||||
@@ -61,7 +61,7 @@ const collections = [
|
||||
indexes: [
|
||||
'CREATE UNIQUE INDEX idx_company_id ON tbl_company (company_id)',
|
||||
'CREATE INDEX idx_company_usci ON tbl_company (company_usci)',
|
||||
'CREATE INDEX idx_company_owner_openid ON tbl_company (company_owner_openid)'
|
||||
'CREATE UNIQUE INDEX idx_company_owner_openid ON tbl_company (company_owner_openid)'
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -37,6 +37,11 @@ const collections = [
|
||||
{
|
||||
name: 'tbl_auth_users',
|
||||
type: 'auth',
|
||||
listRule: '@request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB"',
|
||||
viewRule: '@request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB"',
|
||||
createRule: '',
|
||||
updateRule: '',
|
||||
deleteRule: '@request.auth.usergroups_id = "ROLE-1774666070666-9dDrTB"',
|
||||
fields: [
|
||||
{ name: 'users_convers_id', type: 'text' },
|
||||
{ name: 'openid', type: 'text', required: true },
|
||||
@@ -196,6 +201,11 @@ async function createOrUpdateCollection(collectionData) {
|
||||
const payload = {
|
||||
name: collectionData.name,
|
||||
type: collectionData.type,
|
||||
listRule: Object.prototype.hasOwnProperty.call(collectionData, 'listRule') ? collectionData.listRule : null,
|
||||
viewRule: Object.prototype.hasOwnProperty.call(collectionData, 'viewRule') ? collectionData.viewRule : null,
|
||||
createRule: Object.prototype.hasOwnProperty.call(collectionData, 'createRule') ? collectionData.createRule : null,
|
||||
updateRule: Object.prototype.hasOwnProperty.call(collectionData, 'updateRule') ? collectionData.updateRule : null,
|
||||
deleteRule: Object.prototype.hasOwnProperty.call(collectionData, 'deleteRule') ? collectionData.deleteRule : null,
|
||||
fields: collectionData.fields,
|
||||
indexes: collectionData.indexes,
|
||||
};
|
||||
|
||||
180
script/test-company-owner-sync.js
Normal file
180
script/test-company-owner-sync.js
Normal file
@@ -0,0 +1,180 @@
|
||||
import fs from 'node:fs/promises'
|
||||
|
||||
const runtimePath = new URL('../pocket-base/bai_api_pb_hooks/bai_api_shared/config/runtime.js', import.meta.url)
|
||||
const runtimeText = await fs.readFile(runtimePath, 'utf8')
|
||||
|
||||
function readRuntimeValue(name) {
|
||||
const match = runtimeText.match(new RegExp(`${name}:\\s*'([^']*)'`))
|
||||
if (!match) {
|
||||
throw new Error(`未在 runtime.js 中找到 ${name}`)
|
||||
}
|
||||
return match[1]
|
||||
}
|
||||
|
||||
const baseUrl = readRuntimeValue('APP_BASE_URL')
|
||||
const adminToken = readRuntimeValue('POCKETBASE_AUTH_TOKEN')
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
async function requestJson(path, options = {}) {
|
||||
const res = await fetch(`${baseUrl}${path}`, options)
|
||||
const text = await res.text()
|
||||
let json = null
|
||||
|
||||
try {
|
||||
json = text ? JSON.parse(text) : null
|
||||
} catch {
|
||||
throw new Error(`接口 ${path} 返回了非 JSON 响应:${text}`)
|
||||
}
|
||||
|
||||
return { res, json, text }
|
||||
}
|
||||
|
||||
async function findUserByOpenid(openid) {
|
||||
const filter = encodeURIComponent(`openid="${openid}"`)
|
||||
const result = await requestJson(`/pb/api/collections/tbl_auth_users/records?filter=${filter}&perPage=1&page=1&fields=id,openid,users_type,company_id`, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${adminToken}`,
|
||||
},
|
||||
})
|
||||
if (!result.res.ok) {
|
||||
throw new Error(`查询用户失败:${result.text}`)
|
||||
}
|
||||
return result.json?.items?.[0] || null
|
||||
}
|
||||
|
||||
async function patchUser(recordId, payload) {
|
||||
const result = await requestJson(`/pb/api/collections/tbl_auth_users/records/${recordId}`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
Authorization: `Bearer ${adminToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
})
|
||||
|
||||
if (!result.res.ok) {
|
||||
throw new Error(`恢复用户失败:${result.text}`)
|
||||
}
|
||||
|
||||
return result.json
|
||||
}
|
||||
|
||||
async function deleteCompany(recordId) {
|
||||
const result = await requestJson(`/pb/api/collections/tbl_company/records/${recordId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
Authorization: `Bearer ${adminToken}`,
|
||||
},
|
||||
})
|
||||
|
||||
if (!result.res.ok) {
|
||||
throw new Error(`删除测试公司失败:${result.text}`)
|
||||
}
|
||||
}
|
||||
|
||||
async function loginPlatform(loginAccount, password) {
|
||||
const result = await requestJson('/pb/api/platform/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
login_account: loginAccount,
|
||||
password,
|
||||
}),
|
||||
})
|
||||
|
||||
if (!result.res.ok || !result.json?.token) {
|
||||
throw new Error(`平台登录失败:${result.text}`)
|
||||
}
|
||||
|
||||
return result.json.token
|
||||
}
|
||||
|
||||
async function createCompany(token, ownerOpenid) {
|
||||
const ts = Date.now()
|
||||
const body = {
|
||||
company_name: `同步测试公司-${ts}`,
|
||||
company_type: '渠道商',
|
||||
company_entity: '测试人',
|
||||
company_usci: `91310000${String(ts).slice(-10)}`,
|
||||
company_nationality: '中国',
|
||||
company_nationality_code: 'CN',
|
||||
company_province: '上海',
|
||||
company_province_code: '310000',
|
||||
company_city: '上海',
|
||||
company_city_code: '310100',
|
||||
company_district: '浦东新区',
|
||||
company_district_code: '310115',
|
||||
company_postalcode: '200000',
|
||||
company_add: '同步测试地址',
|
||||
company_status: '有效',
|
||||
company_level: 'A',
|
||||
company_owner_openid: ownerOpenid,
|
||||
company_remark: 'codex-sync-test',
|
||||
}
|
||||
|
||||
const result = await requestJson('/pb/api/collections/tbl_company/records', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
|
||||
if (!result.res.ok || !result.json?.id) {
|
||||
throw new Error(`创建公司失败:${result.text}`)
|
||||
}
|
||||
|
||||
return result.json
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const openid = 'su13106859882'
|
||||
const password = '13106859882'
|
||||
|
||||
const before = await findUserByOpenid(openid)
|
||||
if (!before?.id) {
|
||||
throw new Error(`未找到测试用户:${openid}`)
|
||||
}
|
||||
|
||||
const token = await loginPlatform(password, password)
|
||||
const createdCompany = await createCompany(token, openid)
|
||||
|
||||
await sleep(1500)
|
||||
|
||||
const after = await findUserByOpenid(openid)
|
||||
|
||||
const result = {
|
||||
openid,
|
||||
before_company_id: before.company_id || '',
|
||||
before_users_type: before.users_type || '',
|
||||
created_company_id: createdCompany.company_id || '',
|
||||
created_company_record_id: createdCompany.id || '',
|
||||
after_company_id: after?.company_id || '',
|
||||
after_users_type: after?.users_type || '',
|
||||
synced_company_id: after?.company_id === createdCompany.company_id,
|
||||
synced_users_type: after?.users_type === '服务商',
|
||||
}
|
||||
|
||||
try {
|
||||
await patchUser(before.id, {
|
||||
company_id: before.company_id || '',
|
||||
users_type: before.users_type || '',
|
||||
})
|
||||
} finally {
|
||||
await deleteCompany(createdCompany.id)
|
||||
}
|
||||
|
||||
console.log(JSON.stringify(result, null, 2))
|
||||
|
||||
if (!result.synced_company_id || !result.synced_users_type) {
|
||||
process.exitCode = 1
|
||||
}
|
||||
}
|
||||
|
||||
await main()
|
||||
Reference in New Issue
Block a user