;
-
-export interface SendMessage> {
- apiName: string;
- parameter?: P;
- displayScale?: number;
-}
-
-export interface PrinterResponse {
- apiName: string;
- resultAck: T;
-}
-
-export interface InitCanvasParams {
- width: number;
- height: number;
- rotate: 0 | 90 | 180 | 270,
- path: "",
- verticalShift: 0,
- HorizontalShift: 0
-}
-
-export interface DrawTextParams {
- x: number;
- y: number;
- width: number;
- height: number;
- value: string;
- fontFamily: "";
- rotate: 0 | 1 | 2 | 3;
- fontSize: number;
- textAlignHorizonral: 0 | 1 | 2;
- textAlignVertical: 0 | 1 | 2;
- letterSpacing: number;
- lineSpacing: number;
- lineMode: 1 | 2 | 4 | 6;
- fontStyle: boolean[];
-}
-
-export interface DrawQrCodeParams {
- x: number;
- y: number;
- height: number;
- width: number;
- value: string;
- codeType: 31 | 32 | 33 | 34;
- rotate: 0 | 90 | 180 | 270,
-}
-
-export interface StartJobParams {
- printDensity: number;
- printLabelType: number;
- printMode: number;
- count: number;
-}
-
-export interface InitCanvasParams {
- width: number;
- height: number;
-}
diff --git a/src/type/setting.ts b/src/type/setting.ts
deleted file mode 100644
index 9cc4416..0000000
--- a/src/type/setting.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import {object, string, infer as zInfer} from "zod";
-
-export const settingSchema = object({
- address: string().default(""),
- name: string().default(""),
- phone: string().default(""),
- label: string().default(""),
- callback: string().default(""),
- cargo: string().default("")
-})
-
-export type SettingSchema = zInfer;
diff --git a/src/type/summary.ts b/src/type/summary.ts
deleted file mode 100644
index 1b87fe8..0000000
--- a/src/type/summary.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export interface User {
- id: number;
- qq: string;
- total: number
-}
-
-export interface Weight {
- id: number;
- qq: string;
- total: number
-}
diff --git a/src/type/user.ts b/src/type/user.ts
deleted file mode 100644
index 9c2dd90..0000000
--- a/src/type/user.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import {number, object, string, infer as zInfer, coerce} from "zod";
-
-export const userSchema = object({
- id: number(),
- qq: string().regex(/^\d+$/),
- name: string(),
- email: string().email().nullable().default(null),
- phone: string().regex(/^1\d{10}$/).nullable().default(null),
- address: string().nullable().default(null),
- createAt: coerce.date().default(new Date()),
-})
-
-export type UserSchema = zInfer
diff --git a/src/util/data/indexedDB.ts b/src/util/data/indexedDB.ts
deleted file mode 100644
index 7612af0..0000000
--- a/src/util/data/indexedDB.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import Dexie, { type EntityTable } from 'dexie';
-
-export type LocalData = {
- id: number;
- tax?: number;
- fee?: number;
-}
-
-export const db = new Dexie('localDataDB') as Dexie & {
- localData: EntityTable;
-};
-
-db.version(1).stores({
- localData: '++id, tax, fee'
-});
diff --git a/src/util/data/setting.ts b/src/util/data/setting.ts
deleted file mode 100644
index 07ee5db..0000000
--- a/src/util/data/setting.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import database from "@/util/data/database";
-import {SettingSchema, settingSchema} from "@/type/setting";
-
-export const parse = async () => {
- const raw = await database.setting.findMany();
- const result: Record = {};
- raw.forEach(({ key, value }) => {
- result[key] = value;
- });
- return settingSchema.parse(result);
-}
-
-export const update = async (data: SettingSchema) => {
- for (const [key, value] of Object.entries(data)) {
- await database.setting.upsert({
- where: {key},
- update: {
- value: String(value)
- },
- create: {
- value: String(value),
- key
- }
- });
- }
-}
diff --git a/src/util/item/comic-zin.ts b/src/util/item/comic-zin.ts
deleted file mode 100644
index d0e392c..0000000
--- a/src/util/item/comic-zin.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import * as cheerio from "cheerio";
-import {jStd} from "@/util/string";
-
-export const match = /https:\/\/shop\.comiczin\.jp\/products\/detail\.php\?product_id=\d+/g;
-
-export const parse = async (url: URL) => {
- const $ = await cheerio.fromURL(url);
- const price = Number($("span.fnt_mark_color.fnt_size_12em").text().replace(/[^\d.]/g, ""));
- const name = jStd($("h2.fw_main_block_header_type2.vb_space_15px").text());
- return {name, price, url: url.toString()};
-}
diff --git a/src/util/item/melonbooks.ts b/src/util/item/melonbooks.ts
deleted file mode 100644
index 828ee22..0000000
--- a/src/util/item/melonbooks.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import * as cheerio from "cheerio";
-import {jStd} from "@/util/string";
-
-export const match = /^https:\/\/www\.melonbooks\.co\.jp\/detail\/detail\.php\?product_id=\d+$/;
-
-export const parse = async (url: URL) => {
- const $ = await cheerio.fromURL(url);
- const price = Number($("span.yen.__discount").text().replace(/[^\d.]/g, ""));
- const name = jStd($("h1.page-header").text());
- return {name, price, url: url.toString()}
-}
diff --git a/src/util/print/label.ts b/src/util/print/label.ts
deleted file mode 100644
index aaa321d..0000000
--- a/src/util/print/label.ts
+++ /dev/null
@@ -1,81 +0,0 @@
-import {labelSdk} from "@/util/print/sdk";
-import {methodMap} from "@/type/delivery";
-import {DrawTextParams} from "@/type/print";
-
-const printLabel = async (data: Record, isPrint?: boolean) => {
- const items = [
- {
- x: 2,
- y: 2,
- width: 30,
- height: 4.3,
- value: data.label,
- fontFamily: "",
- rotate: 0,
- fontSize: 9,
- textAlignHorizonral: 0,
- textAlignVertical: 1,
- letterSpacing: 0,
- lineSpacing: 0,
- lineMode: 6,
- fontStyle: [false, false, false, false]
- },
- {
- x: 36,
- y: 2,
- width: 12,
- height: 4.3,
- value: methodMap[data?.method as keyof typeof methodMap].text,
- fontFamily: "",
- rotate: 0,
- fontSize: 9,
- textAlignHorizonral: 2,
- textAlignVertical: 1,
- letterSpacing: 0,
- lineSpacing: 0,
- lineMode: 6,
- fontStyle: [false, false, false, false]
- },
- {
- x: 2,
- y: 15,
- width: 30,
- height: 8.5,
- value: `${data.name}\n${(data.phone as string).slice(-4)}`,
- fontFamily: "",
- rotate: 0,
- fontSize: 9,
- textAlignHorizonral: 0,
- textAlignVertical: 0,
- letterSpacing: 0,
- lineSpacing: 0,
- lineMode: 6,
- fontStyle: [false, false, false, false]
- }
- ];
- if (isPrint) await labelSdk.startJob(3, 1, 1, 1)
- await labelSdk.initCanvas({width: 50, height: 30, rotate: 0, path: "", verticalShift: 0, HorizontalShift: 0});
- for (const item of items) await labelSdk.drawText(item as DrawTextParams)
- await labelSdk.drawQrCode({
- x: 36,
- y: 16,
- width: 12,
- height: 12,
- value: JSON.stringify({
- name: data.name,
- phone: (data.phone as string).slice(-4),
- method: data.method,
- createdAt: Math.floor(Date.now() / 1000),
- }),
- codeType: 31,
- rotate: 0
- })
- if (isPrint) {
- await labelSdk.commitJob(null, {printQuantity: 1});
- }
- else {
- return await labelSdk.preview(8);
- }
-}
-
-export default printLabel;
diff --git a/src/util/print/sdk.ts b/src/util/print/sdk.ts
deleted file mode 100644
index f41f281..0000000
--- a/src/util/print/sdk.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import {
- ApiResponse,
- DrawQrCodeParams,
- DrawTextParams,
- InitCanvasParams, PrinterRequest,
- PrinterResponse,
- SendMessage,
- StartJobParams
-} from "@/type/print";
-
-export class LabelSdk {
- private websocket: WebSocket | null = null;
- private callbacks: Map void> = new Map();
- private timeout = 10000;
-
- constructor(private url = "ws://127.0.0.1:37989") {}
-
- connect(): Promise {
- return new Promise((resolve, reject) => {
- if (typeof window === "undefined") return reject("必须在浏览器中执行");
-
- this.websocket = new WebSocket(this.url);
- this.websocket.binaryType = "arraybuffer";
-
- this.websocket.addEventListener("open", () => resolve());
- this.websocket.addEventListener("error", (err) => reject(err));
- this.websocket.addEventListener("message", (event) => {
- try {
- const msg = JSON.parse(event.data);
- const cb = this.callbacks.get(msg.apiName);
- if (cb) {
- cb(msg.resultAck);
- this.callbacks.delete(msg.apiName);
- }
- }
- catch {
- console.warn("标签机返回非 JSON 格式", event.data);
- }
- });
- });
- }
-
- disconnect() {
- this.websocket?.close()
- }
-
- send>(
- apiName: string,
- parameter: P = {} as P,
- displayScale?: number
- ): Promise {
- return new Promise((resolve, reject) => {
- if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN) {
- return reject(new Error("WebSocket 未连接"));
- }
-
- const msg: SendMessage = displayScale ? {apiName, displayScale} : {apiName, parameter};
- this.callbacks.set(apiName, (res) => resolve(res as T));
-
- this.websocket.send(JSON.stringify(msg));
-
- setTimeout(() => {
- if (this.callbacks.has(apiName)) {
- this.callbacks.delete(apiName);
- reject(new Error(`调用 ${apiName} 超时`));
- }
- }, this.timeout);
- });
- }
-
- initSdk() {
- return this.send("initSdk");
- }
-
- getAllPrinters() {
- return this.send("getAllPrinters");
- }
-
- selectPrinter(printerName: string, port: number) {
- return this.send("selectPrinter", { printerName, port });
- }
-
- setPrinterAutoShutDownTime(nType: 1 | 2 | 3 | 4) {
- return this.send("setPrinterAutoShutDownTime", {nType});
- }
-
- startJob(printDensity: number, printLabelType: number, printMode: number, count: number) {
- const params: StartJobParams = { printDensity, printLabelType, printMode, count };
- return this.send("startJob", params as unknown as PrinterRequest);
- }
-
- commitJob(printData: Record | null, printerImageProcessingInfo: Record) {
- const params = {printData, printerImageProcessingInfo};
- return this.send("commitJob", params);
- }
-
- initCanvas(params: InitCanvasParams) {
- return this.send("InitDrawingBoard", params);
- }
-
- drawText(params: DrawTextParams) {
- return this.send("DrawLableText", params);
- }
-
- drawQrCode(params: DrawQrCodeParams) {
- return this.send("DrawLableQrCode", params);
- }
-
- preview(displayScale: number) {
- return this.send("generateImagePreviewImage", {}, displayScale);
- }
-}
-
-export const labelSdk = new LabelSdk();
diff --git a/src/util/query.ts b/src/util/query.ts
deleted file mode 100644
index a628e88..0000000
--- a/src/util/query.ts
+++ /dev/null
@@ -1,78 +0,0 @@
-import {number, object, string, enum as zEnum, infer as zInfer} from "zod";
-import {any} from "zod";
-import {record} from "zod";
-
-type Input = Record;
-
-const int = ["id", "userId", "groupId", "itemId", "deliveryId"]
-const blocked = ["address", "phone", "keyword"]
-const bool = ["allowed"]
-
-const stringToRecord = (key: string, value: Input) => {
- const keys = key?.split(".");
- return keys?.reverse().reduce>((acc, key) => ({[key]: acc}), value);
-}
-
-export const queryParams = object({
- params: object({
- pageSize: number().default(20),
- current: number().default(1),
- keyword: string().optional(),
- }).catchall(any()).transform((params) => {
- for (const i in params) {
- if (params[i] == null) {
- } else if (int.includes(i)) {
- params[i] = Number(params[i]);
- } else if (bool.includes(i)) {
- params[i] = (params[i] === "true");
- }
- }
- return params;
- }),
- sort: record(zEnum(["ascend", "descend"]).nullable()).transform((sort) => {
- const field = Object.keys(sort)[0];
- const order = sort[field];
- if (!field || !order) {
- return {id: "asc"};
- }
- return {[field.replace(/,/g, '.')]: order === 'descend' ? 'desc' : 'asc'};
- }).default({"id": "ascend"})
-})
-
-const searchBuilder = (keyword: string, fields: string[]) => {
- const result = []
- const condition = {
- contains: keyword,
- mode: "insensitive"
- }
- for (const field of fields) {
- if (int.includes(field) || bool.includes(field)) continue;
- result.push(stringToRecord(field, condition));
- }
- return result
-}
-
-export const queryParser = (
- query: zInfer,
- fields: string[],
- where: Input = {}
-) => {
- const {pageSize, current, keyword, ...filter} = query.params;
- const builder: Input = {};
- if (keyword) {
- builder.OR = searchBuilder(keyword || "", fields);
- }
- const filters = Object.fromEntries(Object.entries(filter).filter(([key]) => !blocked.includes(key)))
- for (const key in filters) {
- builder[key] = filters[key];
- }
- for (const key in where) {
- builder[key] = where[key];
- }
- return {
- where: builder,
- orderBy: stringToRecord(Object.keys(query.sort)[0], Object.values(query.sort)[0]) as Record,
- skip: (current - 1) * pageSize,
- take: pageSize
- }
-}
diff --git a/src/util/summary.ts b/src/util/summary.ts
deleted file mode 100644
index 0dbe62e..0000000
--- a/src/util/summary.ts
+++ /dev/null
@@ -1,115 +0,0 @@
-import database from "@/util/data/database";
-import {User} from "@/type/summary";
-
-export const summaryItem = async (id: number) => {
- const sum = await database.order.groupBy({
- by: [
- "itemId"
- ],
- where: {
- item: {
- groupId: id
- },
- status: {
- not: "failed"
- }
- },
- _sum: {
- count: true,
- }
- });
- const items = new Map((await database.item.findMany({
- where: {
- id: {
- in: sum.map(i => i.itemId)
- }
- }
- })).map(i => [i.id, i]))
- return sum.map(i => ({
- id: i.itemId,
- name: items.get(i.itemId)?.name,
- url: items.get(i.itemId)?.url,
- price: items.get(i.itemId)?.price,
- count: i._sum.count,
- total: (items.get(i.itemId)?.price ?? 0) * (i._sum.count ?? 0)
- }))
-}
-
-export const summaryUser = async (id: number) => {
- const orders = await database.order.findMany({
- where: {
- item: {
- groupId: id
- },
- status: {
- not: "failed"
- }
- },
- include: {
- item: {
- select: {
- price: true
- }
- },
- user: true
- }
- });
- let total = 0;
- const userSpendMap: Record = {};
- for (const order of orders) {
- const amount = order.count * order.item.price;
- userSpendMap[order.userId] = {
- ...order.user,
- total: (userSpendMap[order.userId]?.total || 0) + amount
- };
- total += amount;
- }
- return Object.entries(userSpendMap).map(([, result]) => ({
- ...result,
- ratio: total === 0 ? 0 : result.total / total
- }));
-}
-
-export const summaryWeight = async (id: number) => {
- const orders = await database.order.findMany({
- where: {
- item: {
- groupId: id
- }
- },
- include: {
- user: true,
- item: true
- }
- });
- const hasMissingWeight = orders.some(order => order.item.weight == null);
- if (hasMissingWeight) {
- return [];
- }
- const map = new Map();
- let grandTotal = 0;
- for (const order of orders) {
- const {id, name, qq} = order.user;
- const weight = Number(order.item.weight);
- const total = weight * order.count;
- grandTotal += total;
- if (!map.has(id)) {
- map.set(id, {
- id: id,
- total: total,
- name, qq
- });
- } else {
- map.get(id)!.total += total;
- }
- }
- return Array.from(map.values()).map(user => ({
- ...user,
- ratio: grandTotal === 0 ? 0 : user.total / grandTotal
- }));
-}
\ No newline at end of file
diff --git a/turbo.json b/turbo.json
new file mode 100644
index 0000000..a4af495
--- /dev/null
+++ b/turbo.json
@@ -0,0 +1,24 @@
+{
+ "$schema": "https://turborepo.com/schema.json",
+ "ui": "tui",
+ "tasks": {
+ "prisma:generate": {
+ "outputs": ["node_modules/.prisma/**"]
+ },
+ "build": {
+ "dependsOn": ["^prisma:generate", "^build"],
+ "inputs": ["$TURBO_DEFAULT$", ".env*"],
+ "outputs": [".next/**", "!.next/cache/**"]
+ },
+ "lint": {
+ "dependsOn": ["^lint"]
+ },
+ "check-types": {
+ "dependsOn": ["^check-types"]
+ },
+ "dev": {
+ "cache": false,
+ "persistent": true
+ }
+ }
+}