feat: 积分商城-供应商-对账-发票3

This commit is contained in:
2026-09-08 16:41:48 +08:00
parent 3abe4ce9c9
commit f42ea5b270
47 changed files with 1211 additions and 285 deletions
@@ -0,0 +1,41 @@
import { config } from 'dotenv'
import { PrismaClient } from '@prisma/client'
import { randomBytes, scryptSync } from 'node:crypto'
import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
config({ path: fileURLToPath(new URL('../.env', import.meta.url)), quiet: true })
const prisma = new PrismaClient()
try {
const username = (process.env.SUPPLIED_ADMIN_USERNAME || 'admin').trim()
const password = process.env.SUPPLIED_ADMIN_PASSWORD || `Sp!${randomBytes(12).toString('base64url')}9a`
if (!username || username.length > 64 || password.length < 12 || password.length > 128) {
throw new Error('账号长度需为 1-64,密码长度需为 12-128')
}
const tables = await prisma.$queryRaw`SELECT TABLE_NAME AS name FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND LOWER(TABLE_NAME) IN ('user', 'cartitem', 'supplied_cart_item')`
const legacyUser = tables.find(row => row.name.toLowerCase() === 'user')
const legacyCart = tables.find(row => row.name.toLowerCase() === 'cartitem')
if (legacyUser) {
const rows = await prisma.$queryRawUnsafe('SELECT COUNT(*) AS count FROM `' + legacyUser.name.replace(/`/g, '``') + '`')
if (Number(rows[0].count) > 0) throw new Error('旧 user 表存在数据,未删除,请先处理原有数据')
}
if (legacyCart) {
if (tables.some(row => row.name.toLowerCase() === 'supplied_cart_item')) throw new Error('新旧购物车表同时存在,未覆盖数据')
await prisma.$executeRawUnsafe('RENAME TABLE `' + legacyCart.name.replace(/`/g, '``') + '` TO `supplied_cart_item`')
}
if (legacyUser) await prisma.$executeRawUnsafe('DROP TABLE `' + legacyUser.name.replace(/`/g, '``') + '`')
await prisma.$executeRawUnsafe(readFileSync(new URL('./sql/supplied-user.sql', import.meta.url), 'utf8').trim().replace(/;$/, ''))
const existing = await prisma.$queryRaw`SELECT id FROM supplied_user WHERE username = ${username} LIMIT 1`
if (existing.length) throw new Error('账号已存在,未覆盖原有密码')
const salt = randomBytes(16).toString('hex')
const hash = scryptSync(password, salt, 64, { N: 32768, r: 8, p: 1, maxmem: 64 * 1024 * 1024 }).toString('hex')
const passwordHash = `scrypt$${salt}$${hash}`
await prisma.$executeRaw`INSERT INTO supplied_user (username, passwordHash, nickname) VALUES (${username}, ${passwordHash}, ${'管理员'})`
console.log(JSON.stringify({ username, password, table: 'supplied_user' }))
} catch (error) {
console.error(error instanceof Error ? error.message : '初始化账号失败')
process.exitCode = 1
} finally {
await prisma.$disconnect()
}
+16 -11
View File
@@ -7,16 +7,21 @@ datasource db {
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
mobile String @unique
nickname String?
avatarUrl String?
points Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model SuppliedUser {
id Int @id @default(autoincrement())
username String? @unique @db.VarChar(64)
virtualId String? @unique @db.VarChar(191)
passwordHash String? @db.VarChar(255)
nickname String @default("管理员") @db.VarChar(64)
enabled Boolean @default(true)
tokenHash String? @unique @db.Char(64)
tokenExpiresAt DateTime?
failedLoginCount Int @default(0)
lockedUntil DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
carts CartItem[]
@@map("supplied_user")
}
model SupplierProduct {
@@ -75,10 +80,10 @@ model CartItem {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
product SupplierProduct @relation(fields: [productId], references: [id], onDelete: Cascade)
@@unique([userId, productId, skuText])
@@unique([userId, productId, skuText], map: "CartItem_userId_productId_skuText_key")
@@map("supplied_cart_item")
}
model SupplierOrderMain {
+22 -23
View File
@@ -18,10 +18,10 @@ SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for cartitem
-- Table structure for supplied_cart_item
-- ----------------------------
DROP TABLE IF EXISTS `cartitem`;
CREATE TABLE `cartitem` (
DROP TABLE IF EXISTS `supplied_cart_item`;
CREATE TABLE `supplied_cart_item` (
`id` int NOT NULL AUTO_INCREMENT,
`userId` int NOT NULL,
`productId` int NOT NULL,
@@ -35,7 +35,7 @@ CREATE TABLE `cartitem` (
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of cartitem
-- Records of supplied_cart_item
-- ----------------------------
-- ----------------------------
@@ -528,24 +528,23 @@ CREATE TABLE `supplier_user_address` (
INSERT INTO `supplier_user_address` VALUES (1, 'addr-1785395646503', '99999999', 'b2397ac9a67f476c9833471d27709db1', '谌盼兮', '13545478393', '吉林省', '白山市', '临江市', '未来科技城', '220681', '430213', 1, '2026-07-30 07:14:06.541', '2026-07-30 07:29:34.829', 0);
INSERT INTO `supplier_user_address` VALUES (2, 'addr-1788252731181', '99999999', 'c281e124321c8db3a14f0a7c86046c3c', '谌盼兮', '19090230905', '湖北省', '武汉市', '洪山区', '中国地质大学', '420111', '430074', 1, '2026-09-01 08:52:11.226', '2026-09-01 08:52:11.226', 0);
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`mobile` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`nickname` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`avatarUrl` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`points` int NOT NULL DEFAULT 0,
`createdAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` datetime(3) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `User_mobile_key`(`mobile` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
CREATE TABLE IF NOT EXISTS `supplied_user` (
`id` INT NOT NULL AUTO_INCREMENT,
`username` VARCHAR(64) NULL,
`virtualId` VARCHAR(191) COLLATE utf8mb4_bin NULL,
`passwordHash` VARCHAR(255) NULL,
`nickname` VARCHAR(64) NOT NULL DEFAULT '管理员',
`enabled` BOOLEAN NOT NULL DEFAULT TRUE,
`tokenHash` CHAR(64) NULL,
`tokenExpiresAt` DATETIME(3) NULL,
`failedLoginCount` INT NOT NULL DEFAULT 0,
`lockedUntil` DATETIME(3) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE KEY `supplied_user_username_key` (`username`),
UNIQUE KEY `supplied_user_virtualId_key` (`virtualId`),
UNIQUE KEY `supplied_user_tokenHash_key` (`tokenHash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
SET FOREIGN_KEY_CHECKS = 1;
@@ -0,0 +1,5 @@
ALTER TABLE `supplied_user`
ADD COLUMN `virtualId` VARCHAR(191) COLLATE utf8mb4_bin NULL AFTER `username`,
ADD UNIQUE KEY `supplied_user_virtualId_key` (`virtualId`),
MODIFY COLUMN `username` VARCHAR(64) NULL,
MODIFY COLUMN `passwordHash` VARCHAR(255) NULL;
@@ -0,0 +1,18 @@
CREATE TABLE IF NOT EXISTS `supplied_user` (
`id` INT NOT NULL AUTO_INCREMENT,
`username` VARCHAR(64) NULL,
`virtualId` VARCHAR(191) COLLATE utf8mb4_bin NULL,
`passwordHash` VARCHAR(255) NULL,
`nickname` VARCHAR(64) NOT NULL DEFAULT '管理员',
`enabled` BOOLEAN NOT NULL DEFAULT TRUE,
`tokenHash` CHAR(64) NULL,
`tokenExpiresAt` DATETIME(3) NULL,
`failedLoginCount` INT NOT NULL DEFAULT 0,
`lockedUntil` DATETIME(3) NULL,
`createdAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`),
UNIQUE KEY `supplied_user_username_key` (`username`),
UNIQUE KEY `supplied_user_virtualId_key` (`virtualId`),
UNIQUE KEY `supplied_user_tokenHash_key` (`tokenHash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;