feat(0.2.1): M3 前端接入 —— PowerSyncProvider/登录连接/登出清库, 任务模块数据层切本地库 (projectApi/columnApi/taskApi 本地实现, 离线读写+自动上行), 任务编号徽标展示
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
// PowerSync 后端连接器: 凭证获取 + 上传队列落地 (0.2.1)
|
||||
// 契约见 server/routes/powersync.js: POST /api/powersync/upload { ops: [{ id, table, op, uuid, data }] }
|
||||
import { PowerSyncBackendConnector, UpdateType } from '@powersync/web'
|
||||
// Web SDK 无需基类, 实现 fetchCredentials / uploadData 两个方法即可
|
||||
import { api, getToken } from '../../api/client.js'
|
||||
|
||||
export class IBoardConnector extends PowerSyncBackendConnector {
|
||||
export class IBoardConnector {
|
||||
async fetchCredentials() {
|
||||
// 未登录: 返回 null 让 SDK 保持断开 (登录后由页面触发 connect)
|
||||
if (!getToken()) return null
|
||||
@@ -19,14 +19,26 @@ export class IBoardConnector extends PowerSyncBackendConnector {
|
||||
const batch = await database.getCrudBatch()
|
||||
if (!batch) return
|
||||
|
||||
// 本地行的 id 即为 uuid (客户端创建时生成), 服务端按 uuid 幂等 upsert
|
||||
const ops = batch.crud.map((op, i) => ({
|
||||
id: String(i),
|
||||
table: op.table,
|
||||
op: op.op === UpdateType.DELETE ? 'DELETE' : 'PUT',
|
||||
uuid: op.id,
|
||||
data: op.opData || {},
|
||||
}))
|
||||
// 本地行的 id 即为 uuid (客户端创建时生成), 服务端按 uuid 幂等 upsert。
|
||||
// PATCH 的 opData 只含变更列, 这里统一回读全行按 PUT 上行, 保证服务端整行 upsert 语义。
|
||||
const ops = []
|
||||
for (let i = 0; i < batch.crud.length; i++) {
|
||||
const op = batch.crud[i]
|
||||
let data = op.opData || {}
|
||||
if (op.op !== 'DELETE') {
|
||||
try {
|
||||
const row = await database.get(`SELECT * FROM "${op.table}" WHERE id = ?`, [op.id])
|
||||
if (row) data = row
|
||||
} catch { /* 回读失败则用 opData 兜底 */ }
|
||||
}
|
||||
ops.push({
|
||||
id: String(i),
|
||||
table: op.table,
|
||||
op: op.op === 'DELETE' ? 'DELETE' : 'PUT',
|
||||
uuid: op.id,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
let res
|
||||
try {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// PowerSync React 接入 (0.2.1 离线编辑)
|
||||
// 用法: 在 App 外层包 <PowerSyncProvider>; 任务模块内用 re-export 的 useQuery/useStatus/usePowerSync
|
||||
import React, { useEffect, useMemo } from 'react'
|
||||
import { PowerSyncContext } from '@powersync/react'
|
||||
import { getPowersyncDb, connectPowersync, disconnectAndClearPowersync } from './db.js'
|
||||
import { useAuth } from '../../auth/AuthContext.jsx'
|
||||
|
||||
/**
|
||||
* 登录后建立同步连接; 登出后断开并清空本地库 (避免下一用户读到残留数据)
|
||||
*/
|
||||
export function PowerSyncProvider({ children }) {
|
||||
const { user } = useAuth()
|
||||
const db = useMemo(() => getPowersyncDb(), [])
|
||||
|
||||
useEffect(() => {
|
||||
if (user) {
|
||||
connectPowersync().catch((e) => console.error('[powersync] connect 失败:', e))
|
||||
} else {
|
||||
disconnectAndClearPowersync()
|
||||
}
|
||||
}, [user])
|
||||
|
||||
return <PowerSyncContext.Provider value={db}>{children}</PowerSyncContext.Provider>
|
||||
}
|
||||
|
||||
export { useQuery, useStatus, useSuspenseQuery, usePowerSync } from '@powersync/react'
|
||||
Reference in New Issue
Block a user