From 53305757f8efc1fa4a412a773fd2677c985d5186 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=B0=8C=E5=85=88=E8=88=9C?= <2499071264@qq.com>
Date: Tue, 28 Jul 2026 15:43:27 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=90=8E=E7=AB=AF=E5=88=9D=E5=A7=8B?=
=?UTF-8?q?=E5=8C=962?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 3 +
supplied-h5/.env.example | 2 +
supplied-h5/src/api/supplied-service.js | 21 ++
supplied-h5/src/store/user.js | 137 +++++++
.../src/view/joyful-selection/layout.vue | 20 +-
supplied-service/.env.example | 10 +-
supplied-service/README.md | 8 +-
supplied-service/deno.lock | 30 ++
.../netlify/functions/cart-add.ts | 2 +-
supplied-service/netlify/functions/login.ts | 2 +-
.../netlify/functions/order-create.ts | 2 +-
.../netlify/functions/order-pay.ts | 2 +-
.../netlify/functions/product-detail.ts | 2 +-
.../netlify/functions/product-list.ts | 2 +-
.../netlify/functions/supplier-info.ts | 38 ++
.../netlify/functions/supplier-token.ts | 86 +++++
supplied-service/netlify/functions/upload.ts | 2 +-
.../netlify/functions/user-info.ts | 2 +-
supplied-service/netlify/utils/crypto.ts | 9 +
supplied-service/netlify/utils/handler.ts | 2 +-
supplied-service/netlify/utils/http.ts | 16 +-
supplied-service/netlify/utils/prisma.ts | 11 +-
supplied-service/package-lock.json | 335 +++++++++++++++++-
supplied-service/package.json | 4 +-
supplied-service/prisma.config.ts | 2 +-
supplied-service/prisma/schema.prisma | 20 +-
26 files changed, 734 insertions(+), 36 deletions(-)
create mode 100644 supplied-h5/.env.example
create mode 100644 supplied-h5/src/api/supplied-service.js
create mode 100644 supplied-h5/src/store/user.js
create mode 100644 supplied-service/deno.lock
create mode 100644 supplied-service/netlify/functions/supplier-info.ts
create mode 100644 supplied-service/netlify/functions/supplier-token.ts
create mode 100644 supplied-service/netlify/utils/crypto.ts
diff --git a/.gitignore b/.gitignore
index 85676bc..67f5a95 100644
--- a/.gitignore
+++ b/.gitignore
@@ -158,3 +158,6 @@ dist
hs_err_pid*
replay_pid*
+
+# Local Netlify folder
+.netlify
diff --git a/supplied-h5/.env.example b/supplied-h5/.env.example
new file mode 100644
index 0000000..2bea682
--- /dev/null
+++ b/supplied-h5/.env.example
@@ -0,0 +1,2 @@
+VUE_APP_SUPPLIED_API_BASE="http://localhost:8888/.netlify/functions"
+VUE_APP_SUPPLIER_IDENTIFICATION="joyful-selection"
diff --git a/supplied-h5/src/api/supplied-service.js b/supplied-h5/src/api/supplied-service.js
new file mode 100644
index 0000000..c8ced21
--- /dev/null
+++ b/supplied-h5/src/api/supplied-service.js
@@ -0,0 +1,21 @@
+const API_BASE = process.env.VUE_APP_SUPPLIED_API_BASE || 'http://localhost:8888/.netlify/functions'
+
+const normalizeBase = base => base.replace(/\/$/, '')
+
+export const postFunction = async (name, body = {}) => {
+ const response = await fetch(`${normalizeBase(API_BASE)}/${name}`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(body)
+ })
+
+ const payload = await response.json().catch(() => ({}))
+ if (!response.ok || payload.success === false) {
+ const message = payload.error?.message || payload.msg || '请求失败'
+ throw new Error(message)
+ }
+
+ return payload.data
+}
diff --git a/supplied-h5/src/store/user.js b/supplied-h5/src/store/user.js
new file mode 100644
index 0000000..a8c804c
--- /dev/null
+++ b/supplied-h5/src/store/user.js
@@ -0,0 +1,137 @@
+import { defineStore } from 'pinia'
+import { postFunction } from '@/api/supplied-service'
+
+const USER_KEY = 'joyful-selection-user'
+const DEFAULT_SUPPLIER_IDENTIFICATION = (process.env.VUE_APP_SUPPLIER_IDENTIFICATION || '').toLowerCase()
+
+const readUser = () => {
+ try {
+ return JSON.parse(localStorage.getItem(USER_KEY) || '{}')
+ } catch (error) {
+ return {}
+ }
+}
+
+const saveUser = data => {
+ localStorage.setItem(USER_KEY, JSON.stringify(data))
+}
+
+export const useUserStore = defineStore('joyfulSelectionUser', {
+ state: () => ({
+ userId: '',
+ supplierIdentification: '',
+ supplierId: '',
+ supplierName: '',
+ clientId: '',
+ token: '',
+ refreshToken: '',
+ tokenExpiresAt: 0,
+ loaded: false,
+ loadingToken: false
+ }),
+ getters: {
+ hasToken: state => Boolean(state.token && state.tokenExpiresAt > Date.now())
+ },
+ actions: {
+ loadUser() {
+ const data = readUser()
+ this.userId = data.userId || ''
+ const supplierIdentification = DEFAULT_SUPPLIER_IDENTIFICATION || data.supplierIdentification || ''
+ const supplierChanged = Boolean(data.supplierIdentification && supplierIdentification !== data.supplierIdentification)
+
+ this.supplierIdentification = supplierIdentification
+ this.supplierId = supplierChanged ? '' : data.supplierId || ''
+ this.supplierName = supplierChanged ? '' : data.supplierName || ''
+ this.clientId = supplierChanged ? '' : data.clientId || ''
+ this.token = supplierChanged ? '' : data.token || ''
+ this.refreshToken = supplierChanged ? '' : data.refreshToken || ''
+ this.tokenExpiresAt = supplierChanged ? 0 : Number(data.tokenExpiresAt || 0)
+ this.loaded = true
+ },
+ persistUser() {
+ saveUser({
+ userId: this.userId,
+ supplierIdentification: this.supplierIdentification,
+ supplierId: this.supplierId,
+ supplierName: this.supplierName,
+ clientId: this.clientId,
+ token: this.token,
+ refreshToken: this.refreshToken,
+ tokenExpiresAt: this.tokenExpiresAt
+ })
+ this.loaded = true
+ },
+ hydrateFromRoute(query = {}) {
+ if (!this.loaded) {
+ this.loadUser()
+ }
+
+ const nextUserId = query.userId || ''
+
+ if (nextUserId && nextUserId !== this.userId) {
+ this.userId = nextUserId
+ this.token = ''
+ this.refreshToken = ''
+ this.tokenExpiresAt = 0
+ }
+ if (!this.supplierIdentification) {
+ this.supplierIdentification = DEFAULT_SUPPLIER_IDENTIFICATION
+ }
+
+ this.persistUser()
+ },
+ async fetchSupplierInfo() {
+ if (!this.loaded) {
+ this.loadUser()
+ }
+ if (!this.supplierIdentification) {
+ return
+ }
+
+ const data = await postFunction('supplier-info', {
+ supplierIdentification: this.supplierIdentification
+ })
+
+ if (data?.supplierId && data.supplierId !== this.supplierId) {
+ this.token = ''
+ this.refreshToken = ''
+ this.tokenExpiresAt = 0
+ }
+
+ this.supplierId = data?.supplierId || ''
+ this.supplierName = data?.supplierName || ''
+ this.clientId = data?.clientId || ''
+ this.persistUser()
+ },
+ async fetchBridgeToken() {
+ if (!this.loaded) {
+ this.loadUser()
+ }
+ if (!this.userId || !this.supplierIdentification || this.loadingToken || this.hasToken) {
+ return
+ }
+
+ this.loadingToken = true
+ try {
+ if (!this.supplierId) {
+ await this.fetchSupplierInfo()
+ }
+
+ const data = await postFunction('supplier-token', {
+ userId: this.userId,
+ supplierIdentification: this.supplierIdentification
+ })
+
+ this.supplierId = data?.supplierId || this.supplierId
+ this.supplierName = data?.supplierName || this.supplierName
+ this.token = data?.token || data?.accessToken || ''
+ this.refreshToken = data?.refreshToken || ''
+ const expiresIn = Number(data?.expiresIn || 0)
+ this.tokenExpiresAt = this.token && expiresIn > 0 ? Date.now() + expiresIn * 1000 : 0
+ this.persistUser()
+ } finally {
+ this.loadingToken = false
+ }
+ }
+ }
+})
diff --git a/supplied-h5/src/view/joyful-selection/layout.vue b/supplied-h5/src/view/joyful-selection/layout.vue
index 26694d3..381062a 100644
--- a/supplied-h5/src/view/joyful-selection/layout.vue
+++ b/supplied-h5/src/view/joyful-selection/layout.vue
@@ -13,6 +13,7 @@
diff --git a/supplied-service/.env.example b/supplied-service/.env.example
index 6427f1b..831742f 100644
--- a/supplied-service/.env.example
+++ b/supplied-service/.env.example
@@ -1,9 +1,9 @@
-# Pooled Neon connection string for Netlify Functions runtime.
-DATABASE_URL="postgresql://USER:PASSWORD@HOST-pooler.REGION.aws.neon.tech/DB?sslmode=require"
-
-# Direct Neon connection string for Prisma CLI commands such as migrate.
-DIRECT_URL="postgresql://USER:PASSWORD@HOST.REGION.aws.neon.tech/DB?sslmode=require"
+# MySQL connection string for Netlify Functions runtime and Prisma CLI.
+DATABASE_URL="mysql://supper:Supper%40123456@localhost:10086/supplier_db"
# Optional app settings.
JWT_SECRET="replace-me"
UPLOAD_TOKEN="replace-me"
+
+# Main points mall bridge API, for example http://localhost/open.
+POINTS_MALL_OPEN_API_BASE="http://localhost/open"
diff --git a/supplied-service/README.md b/supplied-service/README.md
index 4845591..5ad8e43 100644
--- a/supplied-service/README.md
+++ b/supplied-service/README.md
@@ -25,10 +25,12 @@ prisma/
Copy `.env.example` to `.env` and set:
-- `DATABASE_URL`: pooled Neon connection string for Netlify Functions runtime
-- `DIRECT_URL`: direct Neon connection string for Prisma CLI and migrations
+- `DATABASE_URL`: Neon Postgres connection string for Netlify Functions runtime and Prisma CLI
- `JWT_SECRET`: auth signing secret
- `UPLOAD_TOKEN`: upload guard token
+- `POINTS_MALL_OPEN_API_BASE`: main platform bridge base URL, for example `http://localhost/open`
+
+Supplier H5 uses `VUE_APP_SUPPLIER_IDENTIFICATION` to request supplier config from this service. The supplier `clientSecret` stays in the database and is only used by the Netlify Function when requesting the platform bridge token.
## Scripts
@@ -55,3 +57,5 @@ Current placeholders:
- `order-pay`
- `user-info`
- `upload`
+- `supplier-info`
+- `supplier-token`
diff --git a/supplied-service/deno.lock b/supplied-service/deno.lock
new file mode 100644
index 0000000..fb17491
--- /dev/null
+++ b/supplied-service/deno.lock
@@ -0,0 +1,30 @@
+{
+ "version": "5",
+ "remote": {
+ "https://edge.netlify.com/": "fd941d61d88673d5f28aab283fb86fcc50f08a3bc80ee5470498fcfa88c65cfb",
+ "https://edge.netlify.com/bootstrap/config.ts": "6a2ce0e544e15e8f8883a5c18da5948e37fd0f2619f68cb31f3af53c51817025",
+ "https://edge.netlify.com/bootstrap/context.ts": "e97240232121e2f369f6546ce961490f34d961ea1ea54be3ff09633e3f08373f",
+ "https://edge.netlify.com/bootstrap/cookie.ts": "8b0baae708989ca183c6f3b4ab3d029e6abcbc2e43f93edeb0ff447b3bbc3a05",
+ "https://edge.netlify.com/bootstrap/edge_function.ts": "b8253e86aa83c67341f5cfedeba5049d77fbf84dcab7eceff7566b7728ae9b39",
+ "https://edge.netlify.com/bootstrap/globals/types.ts": "eaa6148ded3121d8dee62dd91c86e7fe76601df0f3ca8d7962243a30f4c8935f"
+ },
+ "workspace": {
+ "packageJson": {
+ "dependencies": [
+ "npm:@neondatabase/serverless@^1.0.1",
+ "npm:@netlify/functions@^4.2.5",
+ "npm:@prisma/adapter-neon@^6.16.0",
+ "npm:@prisma/client@^6.16.0",
+ "npm:@types/crypto-js@^4.2.2",
+ "npm:@types/node@^24.10.1",
+ "npm:@types/ws@^8.18.1",
+ "npm:crypto-js@^4.2.0",
+ "npm:dotenv@^17.2.3",
+ "npm:netlify-cli@^23.13.3",
+ "npm:prisma@^6.19.3",
+ "npm:typescript@^5.9.3",
+ "npm:ws@^8.18.3"
+ ]
+ }
+ }
+}
diff --git a/supplied-service/netlify/functions/cart-add.ts b/supplied-service/netlify/functions/cart-add.ts
index b3618d4..d084907 100644
--- a/supplied-service/netlify/functions/cart-add.ts
+++ b/supplied-service/netlify/functions/cart-add.ts
@@ -7,5 +7,5 @@ export default withErrorBoundary(async (request: Request, _context: Context) =>
const methodResponse = guardMethod(request, ['POST'])
if (methodResponse) return methodResponse
- return ok({ message: 'cart-add endpoint placeholder' })
+ return ok({ message: '加入购物车接口待实现' })
})
diff --git a/supplied-service/netlify/functions/login.ts b/supplied-service/netlify/functions/login.ts
index 3bf0cbc..532e78c 100644
--- a/supplied-service/netlify/functions/login.ts
+++ b/supplied-service/netlify/functions/login.ts
@@ -7,5 +7,5 @@ export default withErrorBoundary(async (request: Request, _context: Context) =>
const methodResponse = guardMethod(request, ['POST'])
if (methodResponse) return methodResponse
- return ok({ message: 'login endpoint placeholder' })
+ return ok({ message: '登录接口待实现' })
})
diff --git a/supplied-service/netlify/functions/order-create.ts b/supplied-service/netlify/functions/order-create.ts
index 3de2734..01770d9 100644
--- a/supplied-service/netlify/functions/order-create.ts
+++ b/supplied-service/netlify/functions/order-create.ts
@@ -7,5 +7,5 @@ export default withErrorBoundary(async (request: Request, _context: Context) =>
const methodResponse = guardMethod(request, ['POST'])
if (methodResponse) return methodResponse
- return ok({ message: 'order-create endpoint placeholder' })
+ return ok({ message: '创建订单接口待实现' })
})
diff --git a/supplied-service/netlify/functions/order-pay.ts b/supplied-service/netlify/functions/order-pay.ts
index 6ae7f34..24eedde 100644
--- a/supplied-service/netlify/functions/order-pay.ts
+++ b/supplied-service/netlify/functions/order-pay.ts
@@ -7,5 +7,5 @@ export default withErrorBoundary(async (request: Request, _context: Context) =>
const methodResponse = guardMethod(request, ['POST'])
if (methodResponse) return methodResponse
- return ok({ message: 'order-pay endpoint placeholder' })
+ return ok({ message: '订单支付接口待实现' })
})
diff --git a/supplied-service/netlify/functions/product-detail.ts b/supplied-service/netlify/functions/product-detail.ts
index ea7a90b..f936c23 100644
--- a/supplied-service/netlify/functions/product-detail.ts
+++ b/supplied-service/netlify/functions/product-detail.ts
@@ -7,5 +7,5 @@ export default withErrorBoundary(async (request: Request, _context: Context) =>
const methodResponse = guardMethod(request, ['GET'])
if (methodResponse) return methodResponse
- return ok({ message: 'product-detail endpoint placeholder' })
+ return ok({ message: '商品详情接口待实现' })
})
diff --git a/supplied-service/netlify/functions/product-list.ts b/supplied-service/netlify/functions/product-list.ts
index a9c425f..0bdc2af 100644
--- a/supplied-service/netlify/functions/product-list.ts
+++ b/supplied-service/netlify/functions/product-list.ts
@@ -7,5 +7,5 @@ export default withErrorBoundary(async (request: Request, _context: Context) =>
const methodResponse = guardMethod(request, ['GET'])
if (methodResponse) return methodResponse
- return ok({ message: 'product-list endpoint placeholder' })
+ return ok({ message: '商品列表接口待实现' })
})
diff --git a/supplied-service/netlify/functions/supplier-info.ts b/supplied-service/netlify/functions/supplier-info.ts
new file mode 100644
index 0000000..b5b9c14
--- /dev/null
+++ b/supplied-service/netlify/functions/supplier-info.ts
@@ -0,0 +1,38 @@
+import type { Context } from '@netlify/functions'
+import { guardMethod } from '../utils/method.js'
+import { fail, ok } from '../utils/http.js'
+import { readJson } from '../utils/request.js'
+import { prisma } from '../utils/prisma.js'
+import { withErrorBoundary } from '../utils/handler.js'
+
+type SupplierInfoRequest = {
+ supplierIdentification?: string
+}
+
+export default withErrorBoundary(async (request: Request, _context: Context) => {
+ const methodResponse = guardMethod(request, ['POST'])
+ if (methodResponse) return methodResponse
+
+ const body = await readJson(request)
+ const supplierIdentification = String(body.supplierIdentification || '').trim().toLowerCase()
+
+ if (!supplierIdentification) {
+ return fail('供应商唯一标识不能为空')
+ }
+
+ const supplier = await prisma.supplierInfo.findUnique({
+ where: { supplierIdentification }
+ })
+
+ if (!supplier || supplier.deleted === 1) {
+ return fail('供应商信息未配置或已停用', 404, 'SUPPLIER_NOT_CONFIGURED')
+ }
+
+ return ok({
+ id: supplier.id,
+ supplierIdentification: supplier.supplierIdentification,
+ supplierId: supplier.supplierId,
+ supplierName: supplier.supplierName,
+ clientId: supplier.clientId
+ })
+})
diff --git a/supplied-service/netlify/functions/supplier-token.ts b/supplied-service/netlify/functions/supplier-token.ts
new file mode 100644
index 0000000..0f15467
--- /dev/null
+++ b/supplied-service/netlify/functions/supplier-token.ts
@@ -0,0 +1,86 @@
+import type { Context } from '@netlify/functions'
+import { guardMethod } from '../utils/method.js'
+import { fail, ok } from '../utils/http.js'
+import { readJson } from '../utils/request.js'
+import { prisma } from '../utils/prisma.js'
+import { createBridgeSignature } from '../utils/crypto.js'
+import { withErrorBoundary } from '../utils/handler.js'
+
+type SupplierTokenRequest = {
+ userId?: string
+ supplierIdentification?: string
+}
+
+type BridgeTokenResponse = {
+ resultCode?: number
+ message?: string
+ accessToken?: string
+ refreshToken?: string
+ expire?: number
+ refreshExpire?: number
+ time?: string
+}
+
+const normalizeBase = (base: string) => base.replace(/\/$/, '')
+
+export default withErrorBoundary(async (request: Request, _context: Context) => {
+ const methodResponse = guardMethod(request, ['POST'])
+ if (methodResponse) return methodResponse
+
+ const body = await readJson(request)
+ const userId = String(body.userId || '').trim()
+ const supplierIdentification = String(body.supplierIdentification || '').trim().toLowerCase()
+
+ if (!userId || !supplierIdentification) {
+ return fail('用户信息和供应商唯一标识不能为空')
+ }
+
+ const supplier = await prisma.supplierInfo.findUnique({
+ where: { supplierIdentification }
+ })
+
+ if (!supplier || supplier.deleted === 1) {
+ return fail('供应商信息未配置或已停用', 404, 'SUPPLIER_NOT_CONFIGURED')
+ }
+
+ const timestamp = String(Date.now())
+ const signature = createBridgeSignature(supplier.clientId, supplier.clientSecret, timestamp)
+ const apiBase = normalizeBase(process.env.POINTS_MALL_OPEN_API_BASE || '')
+
+ if (!apiBase) {
+ return fail('平台积分商城接口地址未配置', 500, 'OPEN_API_BASE_MISSING')
+ }
+
+ const response = await fetch(`${apiBase}/connect/token`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ supplierId: supplier.supplierId,
+ clientId: supplier.clientId,
+ clientSecret: signature,
+ code: '',
+ timestamp
+ })
+ })
+
+ const tokenPayload = (await response.json().catch(() => ({}))) as BridgeTokenResponse
+
+ if (!response.ok || tokenPayload.resultCode !== 0) {
+ return fail(tokenPayload.message || '获取平台授权令牌失败', 502, 'BRIDGE_TOKEN_FAILED')
+ }
+
+ return ok({
+ supplierIdentification,
+ supplierId: supplier.supplierId,
+ supplierName: supplier.supplierName,
+ userId,
+ token: tokenPayload.accessToken,
+ accessToken: tokenPayload.accessToken,
+ refreshToken: tokenPayload.refreshToken,
+ expiresIn: tokenPayload.expire,
+ refreshExpiresIn: tokenPayload.refreshExpire,
+ issuedAt: tokenPayload.time
+ })
+})
diff --git a/supplied-service/netlify/functions/upload.ts b/supplied-service/netlify/functions/upload.ts
index cbe9b9f..ab74663 100644
--- a/supplied-service/netlify/functions/upload.ts
+++ b/supplied-service/netlify/functions/upload.ts
@@ -7,5 +7,5 @@ export default withErrorBoundary(async (request: Request, _context: Context) =>
const methodResponse = guardMethod(request, ['POST'])
if (methodResponse) return methodResponse
- return ok({ message: 'upload endpoint placeholder' })
+ return ok({ message: '上传接口待实现' })
})
diff --git a/supplied-service/netlify/functions/user-info.ts b/supplied-service/netlify/functions/user-info.ts
index 390c722..1da9459 100644
--- a/supplied-service/netlify/functions/user-info.ts
+++ b/supplied-service/netlify/functions/user-info.ts
@@ -7,5 +7,5 @@ export default withErrorBoundary(async (request: Request, _context: Context) =>
const methodResponse = guardMethod(request, ['GET'])
if (methodResponse) return methodResponse
- return ok({ message: 'user-info endpoint placeholder' })
+ return ok({ message: '用户信息接口待实现' })
})
diff --git a/supplied-service/netlify/utils/crypto.ts b/supplied-service/netlify/utils/crypto.ts
new file mode 100644
index 0000000..c29662e
--- /dev/null
+++ b/supplied-service/netlify/utils/crypto.ts
@@ -0,0 +1,9 @@
+import CryptoJS from 'crypto-js'
+
+export const sha256 = (value: string) => {
+ return CryptoJS.SHA256(value).toString(CryptoJS.enc.Hex)
+}
+
+export const createBridgeSignature = (clientId: string, clientSecret: string, timestamp: string) => {
+ return sha256(`${clientId}${clientSecret}${timestamp}${clientSecret}`)
+}
diff --git a/supplied-service/netlify/utils/handler.ts b/supplied-service/netlify/utils/handler.ts
index ff1bba5..d16b0a9 100644
--- a/supplied-service/netlify/utils/handler.ts
+++ b/supplied-service/netlify/utils/handler.ts
@@ -9,7 +9,7 @@ export const withErrorBoundary = (handler: FunctionHandler): FunctionHandler =>
return await handler(request, context)
} catch (error) {
console.error(error)
- return fail('Internal server error', 500, 'INTERNAL_SERVER_ERROR')
+ return fail('服务异常,请稍后再试', 500, 'INTERNAL_SERVER_ERROR')
}
}
}
diff --git a/supplied-service/netlify/utils/http.ts b/supplied-service/netlify/utils/http.ts
index 45cda93..0b0406e 100644
--- a/supplied-service/netlify/utils/http.ts
+++ b/supplied-service/netlify/utils/http.ts
@@ -1,10 +1,17 @@
export type JsonBody = Record | unknown[]
+const corsHeaders = {
+ 'Access-Control-Allow-Origin': '*',
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
+ 'Access-Control-Allow-Methods': 'GET, POST, PUT, PATCH, DELETE, OPTIONS'
+}
+
export const json = (body: JsonBody, init: ResponseInit = {}) =>
Response.json(body, {
...init,
headers: {
'Content-Type': 'application/json',
+ ...corsHeaders,
...(init.headers || {})
}
})
@@ -16,10 +23,11 @@ export const fail = (message: string, status = 400, code = 'BAD_REQUEST') =>
export const methodNotAllowed = (allowedMethods: string[]) =>
json(
- { success: false, error: { code: 'METHOD_NOT_ALLOWED', message: 'Method not allowed' } },
+ { success: false, error: { code: 'METHOD_NOT_ALLOWED', message: '请求方式不支持' } },
{
status: 405,
headers: {
+ ...corsHeaders,
Allow: allowedMethods.join(', ')
}
}
@@ -28,9 +36,5 @@ export const methodNotAllowed = (allowedMethods: string[]) =>
export const handleOptions = () =>
new Response(null, {
status: 204,
- headers: {
- 'Access-Control-Allow-Origin': '*',
- 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
- 'Access-Control-Allow-Methods': 'GET, POST, PUT, PATCH, DELETE, OPTIONS'
- }
+ headers: corsHeaders
})
diff --git a/supplied-service/netlify/utils/prisma.ts b/supplied-service/netlify/utils/prisma.ts
index 28332b0..7a99582 100644
--- a/supplied-service/netlify/utils/prisma.ts
+++ b/supplied-service/netlify/utils/prisma.ts
@@ -1,23 +1,16 @@
-import { neonConfig } from '@neondatabase/serverless'
-import { PrismaNeon } from '@prisma/adapter-neon'
import { PrismaClient } from '@prisma/client'
-import ws from 'ws'
-
-neonConfig.webSocketConstructor = ws
const connectionString = process.env.DATABASE_URL
if (!connectionString) {
- throw new Error('DATABASE_URL is required')
+ throw new Error('缺少数据库连接配置 DATABASE_URL')
}
const globalForPrisma = globalThis as typeof globalThis & {
prisma?: PrismaClient
}
-const adapter = new PrismaNeon({ connectionString })
-
-export const prisma = globalForPrisma.prisma || new PrismaClient({ adapter })
+export const prisma = globalForPrisma.prisma || new PrismaClient()
if (process.env.NODE_ENV !== 'production') {
globalForPrisma.prisma = prisma
diff --git a/supplied-service/package-lock.json b/supplied-service/package-lock.json
index b58a299..1843a52 100644
--- a/supplied-service/package-lock.json
+++ b/supplied-service/package-lock.json
@@ -12,14 +12,16 @@
"@netlify/functions": "^4.2.5",
"@prisma/adapter-neon": "^6.16.0",
"@prisma/client": "^6.16.0",
+ "crypto-js": "^4.2.0",
"dotenv": "^17.2.3",
"ws": "^8.18.3"
},
"devDependencies": {
+ "@types/crypto-js": "^4.2.2",
"@types/node": "^24.10.1",
"@types/ws": "^8.18.1",
"netlify-cli": "^23.13.3",
- "prisma": "^6.16.0",
+ "prisma": "^6.19.3",
"typescript": "^5.9.3"
}
},
@@ -967,6 +969,13 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/@types/crypto-js": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.2.2.tgz",
+ "integrity": "sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/estree": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz",
@@ -2116,6 +2125,12 @@
"node": ">= 8"
}
},
+ "node_modules/crypto-js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==",
+ "license": "MIT"
+ },
"node_modules/data-view-buffer": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz",
@@ -9260,6 +9275,270 @@
}
}
},
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.2.tgz",
+ "integrity": "sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==",
+ "cpu": [
+ "arm"
+ ],
+ "extraneous": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.2.tgz",
+ "integrity": "sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==",
+ "cpu": [
+ "arm64"
+ ],
+ "extraneous": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.2.tgz",
+ "integrity": "sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==",
+ "cpu": [
+ "arm64"
+ ],
+ "extraneous": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.2.tgz",
+ "integrity": "sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==",
+ "cpu": [
+ "x64"
+ ],
+ "extraneous": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.2.tgz",
+ "integrity": "sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==",
+ "cpu": [
+ "arm64"
+ ],
+ "extraneous": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.2.tgz",
+ "integrity": "sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==",
+ "cpu": [
+ "x64"
+ ],
+ "extraneous": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.2.tgz",
+ "integrity": "sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==",
+ "cpu": [
+ "arm"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.2.tgz",
+ "integrity": "sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==",
+ "cpu": [
+ "arm"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.2.tgz",
+ "integrity": "sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==",
+ "cpu": [
+ "arm64"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.2.tgz",
+ "integrity": "sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==",
+ "cpu": [
+ "arm64"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.2.tgz",
+ "integrity": "sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==",
+ "cpu": [
+ "loong64"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.2.tgz",
+ "integrity": "sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==",
+ "cpu": [
+ "ppc64"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.2.tgz",
+ "integrity": "sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.2.tgz",
+ "integrity": "sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==",
+ "cpu": [
+ "riscv64"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.2.tgz",
+ "integrity": "sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.2.tgz",
+ "integrity": "sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==",
+ "cpu": [
+ "x64"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.2.tgz",
+ "integrity": "sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==",
+ "cpu": [
+ "x64"
+ ],
+ "extraneous": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.2.tgz",
+ "integrity": "sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "extraneous": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.2.tgz",
+ "integrity": "sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==",
+ "cpu": [
+ "arm64"
+ ],
+ "extraneous": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.2.tgz",
+ "integrity": "sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==",
+ "cpu": [
+ "ia32"
+ ],
+ "extraneous": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.2.tgz",
+ "integrity": "sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==",
+ "cpu": [
+ "x64"
+ ],
+ "extraneous": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/netlify-cli/node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.2.tgz",
+ "integrity": "sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==",
+ "cpu": [
+ "x64"
+ ],
+ "extraneous": true,
+ "os": [
+ "win32"
+ ]
+ },
"node_modules/netlify-cli/node_modules/@sec-ant/readable-stream": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
@@ -13324,6 +13603,19 @@
"safe-buffer": "~5.1.0"
}
},
+ "node_modules/netlify-cli/node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "extraneous": true,
+ "hasInstallScript": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
"node_modules/netlify-cli/node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -17381,6 +17673,47 @@
"integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
"dev": true
},
+ "node_modules/netlify-cli/node_modules/rollup": {
+ "version": "4.52.2",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.2.tgz",
+ "integrity": "sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==",
+ "extraneous": true,
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.52.2",
+ "@rollup/rollup-android-arm64": "4.52.2",
+ "@rollup/rollup-darwin-arm64": "4.52.2",
+ "@rollup/rollup-darwin-x64": "4.52.2",
+ "@rollup/rollup-freebsd-arm64": "4.52.2",
+ "@rollup/rollup-freebsd-x64": "4.52.2",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.52.2",
+ "@rollup/rollup-linux-arm-musleabihf": "4.52.2",
+ "@rollup/rollup-linux-arm64-gnu": "4.52.2",
+ "@rollup/rollup-linux-arm64-musl": "4.52.2",
+ "@rollup/rollup-linux-loong64-gnu": "4.52.2",
+ "@rollup/rollup-linux-ppc64-gnu": "4.52.2",
+ "@rollup/rollup-linux-riscv64-gnu": "4.52.2",
+ "@rollup/rollup-linux-riscv64-musl": "4.52.2",
+ "@rollup/rollup-linux-s390x-gnu": "4.52.2",
+ "@rollup/rollup-linux-x64-gnu": "4.52.2",
+ "@rollup/rollup-linux-x64-musl": "4.52.2",
+ "@rollup/rollup-openharmony-arm64": "4.52.2",
+ "@rollup/rollup-win32-arm64-msvc": "4.52.2",
+ "@rollup/rollup-win32-ia32-msvc": "4.52.2",
+ "@rollup/rollup-win32-x64-gnu": "4.52.2",
+ "@rollup/rollup-win32-x64-msvc": "4.52.2",
+ "fsevents": "~2.3.2"
+ }
+ },
"node_modules/netlify-cli/node_modules/router": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
diff --git a/supplied-service/package.json b/supplied-service/package.json
index c1423e6..ae01753 100644
--- a/supplied-service/package.json
+++ b/supplied-service/package.json
@@ -16,14 +16,16 @@
"@netlify/functions": "^4.2.5",
"@prisma/adapter-neon": "^6.16.0",
"@prisma/client": "^6.16.0",
+ "crypto-js": "^4.2.0",
"dotenv": "^17.2.3",
"ws": "^8.18.3"
},
"devDependencies": {
+ "@types/crypto-js": "^4.2.2",
"@types/node": "^24.10.1",
"@types/ws": "^8.18.1",
"netlify-cli": "^23.13.3",
- "prisma": "^6.16.0",
+ "prisma": "^6.19.3",
"typescript": "^5.9.3"
}
}
diff --git a/supplied-service/prisma.config.ts b/supplied-service/prisma.config.ts
index 03a7de4..ccffac9 100644
--- a/supplied-service/prisma.config.ts
+++ b/supplied-service/prisma.config.ts
@@ -4,6 +4,6 @@ import { defineConfig, env } from 'prisma/config'
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
- url: env('DIRECT_URL')
+ url: env('DATABASE_URL')
}
})
diff --git a/supplied-service/prisma/schema.prisma b/supplied-service/prisma/schema.prisma
index 7306394..712486f 100644
--- a/supplied-service/prisma/schema.prisma
+++ b/supplied-service/prisma/schema.prisma
@@ -3,7 +3,8 @@ generator client {
}
datasource db {
- provider = "postgresql"
+ provider = "mysql"
+ url = env("DATABASE_URL")
}
model User {
@@ -37,6 +38,23 @@ model Product {
orderItems OrderItem[]
}
+model SupplierInfo {
+ id Int @id @default(autoincrement())
+ supplierIdentification String @unique
+ supplierId String @unique
+ supplierName String
+ clientId String
+ clientSecret String
+ createTime DateTime @default(now())
+ updateTime DateTime @updatedAt
+ creator String?
+ updator String?
+ version Int @default(0)
+ deleted Int @default(0)
+
+ @@map("supplier_info")
+}
+
model CartItem {
id String @id @default(cuid())
userId String