feat(0.2.1): M3 前端接入 —— PowerSyncProvider/登录连接/登出清库, 任务模块数据层切本地库 (projectApi/columnApi/taskApi 本地实现, 离线读写+自动上行), 任务编号徽标展示

This commit is contained in:
jif2.zhang
2026-10-26 00:41:51 +08:00
parent 1a695920ce
commit a714013e3e
13 changed files with 771 additions and 48 deletions
+22 -10
View File
@@ -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 {
+26
View File
@@ -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'