feat(diy): add cabinet workbench with saved versions and BOM exports
@ -0,0 +1,15 @@
|
||||
CREATE TABLE "DiyScheme" (
|
||||
"id" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"parentCode" TEXT,
|
||||
"createdBy" TEXT NOT NULL,
|
||||
"snapshot" JSONB NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "DiyScheme_pkey" PRIMARY KEY ("id"),
|
||||
CONSTRAINT "DiyScheme_name_not_blank" CHECK (length(btrim("name")) BETWEEN 1 AND 80),
|
||||
CONSTRAINT "DiyScheme_snapshot_object" CHECK (jsonb_typeof("snapshot") = 'object')
|
||||
);
|
||||
CREATE UNIQUE INDEX "DiyScheme_code_key" ON "DiyScheme"("code");
|
||||
CREATE INDEX "DiyScheme_createdBy_createdAt_id_idx" ON "DiyScheme"("createdBy", "createdAt", "id");
|
||||
ALTER TABLE "DiyScheme" ADD CONSTRAINT "DiyScheme_createdBy_fkey" FOREIGN KEY ("createdBy") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@ -2740,6 +2740,19 @@ model AssistedAssemblyAiRender {
|
||||
@@index([status, createdAt])
|
||||
}
|
||||
|
||||
model DiyScheme {
|
||||
id String @id @default(cuid())
|
||||
code String @unique
|
||||
name String
|
||||
parentCode String?
|
||||
createdBy String
|
||||
creator User @relation("DiySchemeCreator", fields: [createdBy], references: [id], onDelete: Cascade)
|
||||
snapshot Json
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([createdBy, createdAt, id])
|
||||
}
|
||||
|
||||
model AiRenderWorkbenchSpu {
|
||||
id String @id @default(cuid())
|
||||
|
||||
@ -3290,6 +3303,7 @@ model User {
|
||||
createdAssetSeries AssetSeries[] @relation("AssetSeriesCreator")
|
||||
createdDraftGroups DraftGroup[] @relation("DraftGroupCreator")
|
||||
createdAiRenderWorkbenchSpus AiRenderWorkbenchSpu[] @relation("AiRenderWorkbenchSpuCreator")
|
||||
createdDiySchemes DiyScheme[] @relation("DiySchemeCreator")
|
||||
createdAiRenderWorkbenchSkus AiRenderWorkbenchSku[] @relation("AiRenderWorkbenchSkuCreator")
|
||||
assistedAssemblyAiRenders AssistedAssemblyAiRender[] @relation("AssistedAssemblyAiRenderCreator")
|
||||
createdIntakeProductModelAssets IntakeProductModelAsset[] @relation("IntakeProductModelAssetCreator")
|
||||
|
||||
BIN
furniture-3d-system/public/diy/images/access-control.png
Normal file
|
After Width: | Height: | Size: 467 KiB |
BIN
furniture-3d-system/public/diy/images/cloud-call.png
Normal file
|
After Width: | Height: | Size: 146 KiB |
BIN
furniture-3d-system/public/diy/images/cloud-function.png
Normal file
|
After Width: | Height: | Size: 367 KiB |
BIN
furniture-3d-system/public/diy/images/collection-todos.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
furniture-3d-system/public/diy/images/function-deploy.png
Normal file
|
After Width: | Height: | Size: 104 KiB |
BIN
furniture-3d-system/public/diy/images/icons/copy.png
Normal file
|
After Width: | Height: | Size: 666 B |
BIN
furniture-3d-system/public/diy/images/icons/examples-active.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
furniture-3d-system/public/diy/images/icons/examples.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
furniture-3d-system/public/diy/images/icons/home-active.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
furniture-3d-system/public/diy/images/icons/home.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
1
furniture-3d-system/public/diy/images/icons/info.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg width="16" height="16" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M24 44C29.5228 44 34.5228 41.7614 38.1421 38.1421C41.7614 34.5228 44 29.5228 44 24C44 18.4772 41.7614 13.4772 38.1421 9.85786C34.5228 6.23858 29.5228 4 24 4C18.4772 4 13.4772 6.23858 9.85786 9.85786C6.23858 13.4772 4 18.4772 4 24C4 29.5228 6.23858 34.5228 9.85786 38.1421C13.4772 41.7614 18.4772 44 24 44Z" fill="#0064fa" stroke="#0064fa" stroke-width="4" stroke-linejoin="round"/><path fill-rule="evenodd" clip-rule="evenodd" d="M24 11C25.3807 11 26.5 12.1193 26.5 13.5C26.5 14.8807 25.3807 16 24 16C22.6193 16 21.5 14.8807 21.5 13.5C21.5 12.1193 22.6193 11 24 11Z" fill="#FFF"/><path d="M24.5 34V20H23.5H22.5" stroke="#FFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M21 34H28" stroke="#FFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
|
After Width: | Height: | Size: 938 B |
BIN
furniture-3d-system/public/diy/images/nodejs-function.png
Normal file
|
After Width: | Height: | Size: 300 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038043.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038044.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038045.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038046.jpg
Normal file
|
After Width: | Height: | Size: 8.9 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038047.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038048.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038049.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038050.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038051.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038052.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038053.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038054.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038055.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038056.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038057.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038058.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038059.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038060.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038061.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038062.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038063.jpg
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038064.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038065.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038066.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038067.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038068.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038069.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038070.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038071.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038072.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038073.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
furniture-3d-system/public/diy/images/patterns-3d/SJ038074.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
furniture-3d-system/public/diy/images/quick-deploy.png
Normal file
|
After Width: | Height: | Size: 504 KiB |
BIN
furniture-3d-system/public/diy/images/styles/SJ0376K09.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
furniture-3d-system/public/diy/images/styles/SJ0380K01.jpg
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
furniture-3d-system/public/diy/images/styles/SJ0380K02.jpg
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
furniture-3d-system/public/diy/images/styles/SJ0380K03.jpg
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
furniture-3d-system/public/diy/images/styles/SJ0380K04.jpg
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
furniture-3d-system/public/diy/images/styles/SJ0380K05.jpg
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
furniture-3d-system/public/diy/images/styles/SJ0380K06.jpg
Normal file
|
After Width: | Height: | Size: 8.5 KiB |
BIN
furniture-3d-system/public/diy/images/styles/SJ0380K07.jpg
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
furniture-3d-system/public/diy/images/styles/SJ0380K08.jpg
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
furniture-3d-system/public/diy/images/styles/SJ0380K09.jpg
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 8.8 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 443 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 328 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 329 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 352 KiB |
|
After Width: | Height: | Size: 11 KiB |
@ -211,6 +211,7 @@ const schemaJsonFieldClassifications = new Map(
|
||||
['AssistedAssemblyAiRender.workspaceSnapshot', ['process-snapshot', '辅助装配工作区快照。']],
|
||||
['AssistedAssemblyAiRender.assetSnapshot', ['process-snapshot', '辅助装配资产快照。']],
|
||||
['AssistedAssemblyAiRender.attempts', ['process-snapshot', '辅助装配 AI 生图尝试记录。']],
|
||||
['DiyScheme.snapshot', ['process-snapshot', 'DIY 组合方案配置与几何恢复快照;不创建正式产品、SKU 或条码。']],
|
||||
['PreSku.familySelection', ['compatibility-snapshot', '准 SKU 资产族选择快照;正式基础资料主读必须走 PreSkuBasicInfo。']],
|
||||
['PreSku.variantSelection', ['process-snapshot', '准 SKU 规格款组合快照。']],
|
||||
['PreSku.recommendedHardware', ['process-snapshot', '准 SKU 推荐五金快照。']],
|
||||
@ -758,7 +759,9 @@ const rules = [
|
||||
'应用层不能把本地 JSON 文件读写或导入当作主数据真相;正式资料必须进入数据库或明确的服务端契约,文件 JSON 只能作为导入载荷、迁移计划、备份或测试夹具。',
|
||||
pattern:
|
||||
/\b(?:fs\.)?(?:promises\.)?(?:readFileSync|writeFileSync|readFile|writeFile)\s*\([\s\S]{0,220}\.json['"`][\s\S]{0,180}\)|\bimport\s+[^;\n]+?\s+from\s+['"`][^'"`]+\.json['"`]|\brequire\s*\(\s*['"`][^'"`]+\.json['"`]\s*\)|\bimport\s*\(\s*['"`][^'"`]+\.json['"`]\s*\)/g,
|
||||
isAllowed: ({ relativePath }) => isTestFile(relativePath),
|
||||
// DIY 的两个固定样本仅提供几何预览/参考明细,方案存入 DiyScheme;禁止写正式产品、SKU 或订单。
|
||||
isAllowed: ({ relativePath, match }) => isTestFile(relativePath) ||
|
||||
(relativePath === 'src/lib/diy/catalog.ts' && /^import (spuData|catalogData) from '\.\/data\/(spu|catalog)-SJ0380\.json'$/.test(match[0])),
|
||||
},
|
||||
{
|
||||
id: 'reference-library-item-key-id-fallback',
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
import { NextRequest } from 'next/server'
|
||||
import { handleRequest, jsonSuccess } from '@/server/core/response'
|
||||
import { diySchemeService } from '@/server/services/diy-scheme.service'
|
||||
|
||||
export async function GET(request: NextRequest, context: { params: Promise<{ code: string }> }) {
|
||||
const { code } = await context.params
|
||||
return handleRequest(request, async ctx => jsonSuccess(await diySchemeService.get(code, ctx.user), 200, ctx.requestId), { requireAuth: true })
|
||||
}
|
||||
19
furniture-3d-system/src/app/api/diy/schemes/route.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { NextRequest } from 'next/server'
|
||||
import { handleRequest, jsonSuccess, jsonError } from '@/server/core/response'
|
||||
import { ErrorCode } from '@/server/core/errors'
|
||||
import { diySchemeService } from '@/server/services/diy-scheme.service'
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
return handleRequest(request, async ctx => jsonSuccess(
|
||||
await diySchemeService.list(ctx.user, request.nextUrl.searchParams.get('page'), request.nextUrl.searchParams.get('pageSize')), 200, ctx.requestId,
|
||||
), { requireAuth: true })
|
||||
}
|
||||
export async function POST(request: NextRequest) {
|
||||
return handleRequest(request, async ctx => {
|
||||
const text = await request.text()
|
||||
if (Buffer.byteLength(text) > 256 * 1024) return jsonError(ErrorCode.FILE_TOO_LARGE, '方案不能超过256KB', 413, ctx.requestId)
|
||||
let input: unknown
|
||||
try { input = JSON.parse(text) } catch { return jsonError(ErrorCode.VALIDATION_FAILED, '方案格式无效', 400, ctx.requestId) }
|
||||
return jsonSuccess(await diySchemeService.create(input, ctx.user), 201, ctx.requestId)
|
||||
}, { requireAuth: true })
|
||||
}
|
||||