Compare commits
No commits in common. "9495895ff1cb598c4030034f944333e7190a9d4f" and "4eeda35c2d0e62d1020474cfc5fd754138c73030" have entirely different histories.
9495895ff1
...
4eeda35c2d
|
|
@ -1,3 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: require.resolve('@umijs/max/eslint'),
|
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"extends": "./node_modules/mwts/",
|
||||||
|
"ignorePatterns": ["node_modules", "dist", "test", "jest.config.js", "typings"],
|
||||||
|
"env": {
|
||||||
|
"jest": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,19 +1,17 @@
|
||||||
/node_modules
|
logs/
|
||||||
/.env.local
|
npm-debug.log
|
||||||
/.umirc.local.ts
|
yarn-error.log
|
||||||
/config/config.local.ts
|
node_modules/
|
||||||
/src/.umi
|
coverage/
|
||||||
/src/.umi-production
|
dist/
|
||||||
/src/.umi-test
|
.idea/
|
||||||
/.umi
|
run/
|
||||||
/.umi-production
|
|
||||||
/.umi-test
|
|
||||||
/dist
|
|
||||||
/.mfsu
|
|
||||||
.swc
|
|
||||||
/package-lock.json
|
|
||||||
/yarn.lock
|
|
||||||
*.yaml
|
|
||||||
#
|
|
||||||
/docs
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
*.sw*
|
||||||
|
*.un~
|
||||||
|
.tsbuildinfo
|
||||||
|
.tsbuildinfo.*
|
||||||
|
yarn.lock
|
||||||
|
**/config.prod.ts
|
||||||
|
**/config.local.ts
|
||||||
|
container
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
export default {
|
|
||||||
schemaPath: 'http://127.0.0.1:7001/swagger-ui/index.json',
|
|
||||||
serversPath: './src/servers',
|
|
||||||
};
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
node_modules
|
|
||||||
.umi
|
|
||||||
.umi-production
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"printWidth": 80,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "all",
|
|
||||||
"proseWrap": "never",
|
|
||||||
"overrides": [{ "files": ".prettierrc", "options": { "parser": "json" } }],
|
|
||||||
"plugins": ["prettier-plugin-organize-imports", "prettier-plugin-packagejson"]
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
module.exports = {
|
||||||
|
...require('mwts/.prettierrc.json')
|
||||||
|
}
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: require.resolve('@umijs/max/stylelint'),
|
|
||||||
};
|
|
||||||
234
.umirc.ts
234
.umirc.ts
|
|
@ -1,234 +0,0 @@
|
||||||
import { defineConfig } from '@umijs/max';
|
|
||||||
|
|
||||||
const isDev = process.env.NODE_ENV === 'development';
|
|
||||||
const UMI_APP_API_URL = isDev
|
|
||||||
? 'http://localhost:7001'
|
|
||||||
: 'https://api.yoone.ca';
|
|
||||||
import { codeInspectorPlugin } from 'code-inspector-plugin';
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
hash: true,
|
|
||||||
antd: {},
|
|
||||||
access: {},
|
|
||||||
model: {},
|
|
||||||
initialState: {},
|
|
||||||
request: {},
|
|
||||||
layout: {
|
|
||||||
title: 'YOONE',
|
|
||||||
},
|
|
||||||
define: {
|
|
||||||
UMI_APP_API_URL,
|
|
||||||
},
|
|
||||||
chainWebpack(config) {
|
|
||||||
config.plugin('code-inspector-plugin').use(
|
|
||||||
codeInspectorPlugin({
|
|
||||||
bundler: 'webpack',
|
|
||||||
})
|
|
||||||
);
|
|
||||||
},
|
|
||||||
routes: [
|
|
||||||
{ path: '/', redirect: '/home' },
|
|
||||||
{ name: '追踪', path: '/track', component: './Track', layout: false },
|
|
||||||
{ name: '登录', path: '/login', component: './Login', layout: false },
|
|
||||||
{ name: '首页', path: '/home', component: './Home' },
|
|
||||||
{
|
|
||||||
name: '组织架构',
|
|
||||||
path: '/organiza',
|
|
||||||
access: 'canSeeOrganiza',
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: '用户管理',
|
|
||||||
path: '/organiza/user',
|
|
||||||
component: './Organiza/User',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '站点管理',
|
|
||||||
path: '/site',
|
|
||||||
access: 'canSeeSite',
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: '站点列表',
|
|
||||||
path: '/site/list',
|
|
||||||
component: './Site/List',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '商品管理',
|
|
||||||
path: '/product',
|
|
||||||
access: 'canSeeProduct',
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: '商品分类',
|
|
||||||
path: '/product/category',
|
|
||||||
component: './Product/Category',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '强度',
|
|
||||||
path: '/product/strength',
|
|
||||||
component: './Product/Strength',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '口味',
|
|
||||||
path: '/product/flavors',
|
|
||||||
component: './Product/Flavors',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '产品列表',
|
|
||||||
path: '/product/list',
|
|
||||||
component: './Product/List',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'WP商品列表',
|
|
||||||
path: '/product/wp_list',
|
|
||||||
component: './Product/WpList',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '库存管理',
|
|
||||||
path: '/stock',
|
|
||||||
access: 'canSeeStock',
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: '库存列表',
|
|
||||||
path: '/stock/list',
|
|
||||||
component: './Stock/List',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '仓库点',
|
|
||||||
path: '/stock/warehouse',
|
|
||||||
component: './Stock/Warehouse',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '采购管理',
|
|
||||||
path: '/stock/purchaseOrder',
|
|
||||||
component: './Stock/PurchaseOrder',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '发货管理',
|
|
||||||
path: '/stock/transfer',
|
|
||||||
component: './Stock/Transfer',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '库存记录',
|
|
||||||
path: '/stock/record',
|
|
||||||
component: './Stock/Record',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '订单管理',
|
|
||||||
path: '/order',
|
|
||||||
access: 'canSeeOrder',
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: '订单列表',
|
|
||||||
path: '/order/list',
|
|
||||||
component: './Order/List',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '待发货产品',
|
|
||||||
path: '/order/item',
|
|
||||||
component: './Order/PendingItems',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
// 新增:订阅管理路由分组(权限复用 canSeeOrder)
|
|
||||||
{
|
|
||||||
name: '订阅管理',
|
|
||||||
path: '/subscription',
|
|
||||||
access: 'canSeeOrder',
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: '订阅列表',
|
|
||||||
path: '/subscription/list',
|
|
||||||
component: './Subscription/List',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '订单管理',
|
|
||||||
path: '/subscription/orders',
|
|
||||||
component: './Subscription/Orders',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '客户管理',
|
|
||||||
path: '/customer',
|
|
||||||
access: 'canSeeCustomer',
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: '客户列表',
|
|
||||||
path: '/customer/list',
|
|
||||||
component: './Customer/List',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '物流管理',
|
|
||||||
path: '/logistics',
|
|
||||||
access: 'canSeeLogistics',
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: '服务商',
|
|
||||||
path: '/logistics/services',
|
|
||||||
component: './Logistics/Services',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '地址管理',
|
|
||||||
path: '/logistics/address',
|
|
||||||
component: './Logistics/Address',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '物流列表',
|
|
||||||
path: '/logistics/list',
|
|
||||||
component: './Logistics/List',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '数据统计',
|
|
||||||
path: '/statistics',
|
|
||||||
access: 'canSeeStatistics',
|
|
||||||
routes: [
|
|
||||||
{
|
|
||||||
name: '销售统计',
|
|
||||||
path: '/statistics/sales',
|
|
||||||
component: './Statistics/Sales',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '订单统计',
|
|
||||||
path: '/statistics/order',
|
|
||||||
component: './Statistics/Order',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '订单来源',
|
|
||||||
path: '/statistics/orderSource',
|
|
||||||
component: './Statistics/OrderSource',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '客户统计',
|
|
||||||
path: '/statistics/customer',
|
|
||||||
component: './Statistics/Customer',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '库存预测',
|
|
||||||
path: '/statistics/inventoryForecast',
|
|
||||||
component: './Statistics/InventoryForecast',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '补货',
|
|
||||||
path: '/statistics/restocking',
|
|
||||||
component: './Statistics/Restocking',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// path: '*',
|
|
||||||
// component: './404',
|
|
||||||
// },
|
|
||||||
],
|
|
||||||
npmClient: 'pnpm',
|
|
||||||
});
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
const { Bootstrap } = require('@midwayjs/bootstrap')
|
||||||
|
Bootstrap.run()
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testPathIgnorePatterns: ['<rootDir>/test/fixtures'],
|
||||||
|
coveragePathIgnorePatterns: ['<rootDir>/test/'],
|
||||||
|
};
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
const users = [
|
|
||||||
{ id: 0, name: 'Umi', nickName: 'U', gender: 'MALE' },
|
|
||||||
{ id: 1, name: 'Fish', nickName: 'B', gender: 'FEMALE' },
|
|
||||||
];
|
|
||||||
|
|
||||||
export default {
|
|
||||||
'GET /api/v1/queryUserList': (req: any, res: any) => {
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
data: { list: users },
|
|
||||||
errorCode: 0,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'PUT /api/v1/user/': (req: any, res: any) => {
|
|
||||||
res.json({
|
|
||||||
success: true,
|
|
||||||
errorCode: 0,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
File diff suppressed because it is too large
Load Diff
86
package.json
86
package.json
|
|
@ -1,44 +1,56 @@
|
||||||
{
|
{
|
||||||
|
"name": "my-midway-project",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
"private": true,
|
"private": true,
|
||||||
"author": "cll <931958862@qq.com>",
|
|
||||||
"scripts": {
|
|
||||||
"build": "max build",
|
|
||||||
"dev": "max dev",
|
|
||||||
"format": "prettier --cache --write .",
|
|
||||||
"postinstall": "max setup",
|
|
||||||
"openapi2ts": "openapi2ts",
|
|
||||||
"prepare": "husky",
|
|
||||||
"setup": "max setup",
|
|
||||||
"start": "npm run dev"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/charts": "^2.2.6",
|
"@midwayjs/bootstrap": "^3.20.0",
|
||||||
"@ant-design/icons": "^5.0.1",
|
"@midwayjs/core": "^3.20.0",
|
||||||
"@ant-design/pro-components": "^2.4.4",
|
"@midwayjs/cron": "^3.20.0",
|
||||||
"@fingerprintjs/fingerprintjs": "^4.6.2",
|
"@midwayjs/cross-domain": "^3.20.2",
|
||||||
"@umijs/max": "^4.4.4",
|
"@midwayjs/decorator": "^3.20.0",
|
||||||
"@umijs/max-plugin-openapi": "^2.0.3",
|
"@midwayjs/info": "^3.20.2",
|
||||||
"@umijs/plugin-openapi": "^1.3.3",
|
"@midwayjs/jwt": "^3.20.2",
|
||||||
"antd": "^5.4.0",
|
"@midwayjs/koa": "^3.20.2",
|
||||||
"dayjs": "^1.11.9",
|
"@midwayjs/logger": "^3.1.0",
|
||||||
"echarts": "^5.6.0",
|
"@midwayjs/swagger": "^3.20.2",
|
||||||
"echarts-for-react": "^3.0.2",
|
"@midwayjs/typeorm": "^3.20.0",
|
||||||
"file-saver": "^2.0.5",
|
"@midwayjs/validate": "^3.20.2",
|
||||||
"print-js": "^1.6.0",
|
"@woocommerce/woocommerce-rest-api": "^1.0.2",
|
||||||
"react-phone-input-2": "^2.15.1",
|
"axios": "^1.7.9",
|
||||||
"react-toastify": "^11.0.5",
|
"bcryptjs": "^2.4.3",
|
||||||
"xlsx": "^0.18.5"
|
"class-transformer": "^0.5.1",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
|
"mysql2": "^3.11.5",
|
||||||
|
"nodemailer": "^7.0.5",
|
||||||
|
"swagger-ui-dist": "^5.18.2",
|
||||||
|
"typeorm": "^0.3.20",
|
||||||
|
"xml2js": "^0.6.2"
|
||||||
},
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "cross-env NODE_ENV=prod pm2 start ./bootstrap.js --name yoone -i 4",
|
||||||
|
"prod": "cross-env NODE_ENV=prod node ./bootstrap.js ",
|
||||||
|
"dev": "cross-env NODE_ENV=local mwtsc --watch --run @midwayjs/mock/app.js",
|
||||||
|
"test": "cross-env NODE_ENV=unittest jest",
|
||||||
|
"cov": "jest --coverage",
|
||||||
|
"lint": "mwts check",
|
||||||
|
"lint:fix": "mwts fix",
|
||||||
|
"ci": "npm run cov",
|
||||||
|
"build": "mwtsc --cleanOutDir"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": ""
|
||||||
|
},
|
||||||
|
"author": "anonymous",
|
||||||
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/react": "^18.0.33",
|
"@midwayjs/mock": "^3.20.11",
|
||||||
"@types/react-dom": "^18.0.11",
|
"cross-env": "^10.1.0",
|
||||||
"code-inspector-plugin": "^1.2.10",
|
"mwtsc": "^1.15.2",
|
||||||
"husky": "^9",
|
"typescript": "^5.9.3"
|
||||||
"lint-staged": "^13.2.0",
|
|
||||||
"openapi2ts": "^1.1.14",
|
|
||||||
"prettier": "^2.8.7",
|
|
||||||
"prettier-plugin-organize-imports": "^3.2.2",
|
|
||||||
"prettier-plugin-packagejson": "^2.4.3",
|
|
||||||
"typescript": "^5.7.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,24 +0,0 @@
|
||||||
export default (initialState: any) => {
|
|
||||||
const isSuper = initialState?.user?.isSuper ?? false;
|
|
||||||
const isAdmin = initialState?.user?.Admin ?? false;
|
|
||||||
const canSeeOrganiza = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('organiza') ?? false);
|
|
||||||
const canSeeProduct = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('product') ?? false);
|
|
||||||
const canSeeStock = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('stock') ?? false);
|
|
||||||
const canSeeOrder = (isSuper || isAdmin) ||
|
|
||||||
((initialState?.user?.permissions?.includes('order') ?? false) || (initialState?.user?.permissions?.includes('order-10-days') ?? false));
|
|
||||||
const canSeeCustomer = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('customer') ?? false);
|
|
||||||
const canSeeLogistics = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('logistics') ?? false);
|
|
||||||
const canSeeStatistics = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('statistics') ?? false);
|
|
||||||
const canSeeSite = (isSuper || isAdmin) || (initialState?.user?.permissions?.includes('site') ?? false);
|
|
||||||
|
|
||||||
return {
|
|
||||||
canSeeOrganiza,
|
|
||||||
canSeeProduct,
|
|
||||||
canSeeStock,
|
|
||||||
canSeeOrder,
|
|
||||||
canSeeCustomer,
|
|
||||||
canSeeLogistics,
|
|
||||||
canSeeStatistics,
|
|
||||||
canSeeSite,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
128
src/app.tsx
128
src/app.tsx
|
|
@ -1,128 +0,0 @@
|
||||||
// 运行时配置
|
|
||||||
|
|
||||||
import { LogoutOutlined, UserOutlined } from '@ant-design/icons';
|
|
||||||
import {
|
|
||||||
ProLayoutProps,
|
|
||||||
ProSchemaValueEnumObj,
|
|
||||||
ProTable,
|
|
||||||
} from '@ant-design/pro-components';
|
|
||||||
import { RequestConfig, history, useModel } from '@umijs/max';
|
|
||||||
import { App, Avatar, ConfigProvider, Dropdown, MenuProps } from 'antd';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import 'dayjs/locale/zh-cn';
|
|
||||||
import { usercontrollerGetuser } from './servers/api/user';
|
|
||||||
|
|
||||||
// 设置 dayjs 全局语言为中文
|
|
||||||
dayjs.locale('zh-cn');
|
|
||||||
|
|
||||||
// 全局初始化数据配置,用于 Layout 用户信息和权限初始化
|
|
||||||
// 更多信息见文档:https://umijs.org/docs/api/runtime-config#getinitialstate
|
|
||||||
export async function getInitialState(): Promise<{
|
|
||||||
user?: Record<string, any>;
|
|
||||||
categoryList?: ProSchemaValueEnumObj;
|
|
||||||
sites?: API.SiteConfig[];
|
|
||||||
}> {
|
|
||||||
if (!localStorage.getItem('token') || history.location.pathname === '/login')
|
|
||||||
return {};
|
|
||||||
|
|
||||||
const { data: user } = await usercontrollerGetuser();
|
|
||||||
return { user };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const layout = (): ProLayoutProps => {
|
|
||||||
const { initialState } = useModel('@@initialState');
|
|
||||||
const items: MenuProps['items'] = [
|
|
||||||
{
|
|
||||||
key: '1',
|
|
||||||
label: '我的账号',
|
|
||||||
disabled: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'divider',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '3',
|
|
||||||
label: '退出登录',
|
|
||||||
icon: <LogoutOutlined />,
|
|
||||||
onClick: async () => {
|
|
||||||
//TODO 清理服务器登陆状态
|
|
||||||
localStorage.removeItem('token');
|
|
||||||
history.push('/login');
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return {
|
|
||||||
menu: {
|
|
||||||
locale: false,
|
|
||||||
},
|
|
||||||
layout: 'mix',
|
|
||||||
actionsRender: () => (
|
|
||||||
<Dropdown key="avatar" menu={{ items }}>
|
|
||||||
<div style={{ cursor: 'pointer' }}>
|
|
||||||
<Avatar size="large" icon={<UserOutlined />} />
|
|
||||||
<span style={{ marginLeft: 8 }}>{initialState?.name}</span>
|
|
||||||
</div>
|
|
||||||
</Dropdown>
|
|
||||||
),
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const request: RequestConfig = {
|
|
||||||
baseURL: UMI_APP_API_URL,
|
|
||||||
requestInterceptors: [
|
|
||||||
(url: string, options: any) => {
|
|
||||||
const token = localStorage.getItem('token');
|
|
||||||
return {
|
|
||||||
url,
|
|
||||||
options: {
|
|
||||||
...options,
|
|
||||||
headers: {
|
|
||||||
...options.headers,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
],
|
|
||||||
errorConfig: {
|
|
||||||
errorHandler: (error: any) => {
|
|
||||||
if (error?.response?.status === 401) {
|
|
||||||
localStorage.removeItem('token');
|
|
||||||
history.push('/login');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const onRouteChange = ({ location }: { location: Location }) => {
|
|
||||||
const token = localStorage.getItem('token');
|
|
||||||
|
|
||||||
// 白名单,不需要登录的页面
|
|
||||||
const whiteList = ['/login', '/track'];
|
|
||||||
|
|
||||||
if (!token && !whiteList.includes(location.pathname)) {
|
|
||||||
// 没有 token 且不在白名单内,跳转到登录页
|
|
||||||
history.push('/login');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export function rootContainer(container: React.ReactNode) {
|
|
||||||
// 全局过滤空字段逻辑
|
|
||||||
(ProTable as any).defaultProps = {
|
|
||||||
...(ProTable as any).defaultProps,
|
|
||||||
beforeSearchSubmit: (params: any) => {
|
|
||||||
return Object.fromEntries(
|
|
||||||
Object.entries(params).filter(
|
|
||||||
([_, value]) => value !== undefined && value !== null && value !== '',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<ConfigProvider>
|
|
||||||
<App>{container}</App>
|
|
||||||
</ConfigProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
import { Input, Select } from 'antd';
|
|
||||||
import React, { useEffect } from 'react';
|
|
||||||
|
|
||||||
const { Option } = Select;
|
|
||||||
|
|
||||||
// 定义国家代码和扩展码的映射关系
|
|
||||||
const phoneExtensions: { [key: string]: string } = {
|
|
||||||
CA: '1',
|
|
||||||
CN: '86',
|
|
||||||
US: '1',
|
|
||||||
};
|
|
||||||
|
|
||||||
interface InternationalPhoneInputProps {
|
|
||||||
value?: { country?: string; phone?: string; extension?: string };
|
|
||||||
onChange?: (value: {
|
|
||||||
country: string;
|
|
||||||
phone: string;
|
|
||||||
extension?: string;
|
|
||||||
}) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const InternationalPhoneInput: React.FC<InternationalPhoneInputProps> = ({
|
|
||||||
value = {},
|
|
||||||
onChange,
|
|
||||||
}) => {
|
|
||||||
const {
|
|
||||||
country = 'CA',
|
|
||||||
phone = '',
|
|
||||||
extension = phoneExtensions['CA'],
|
|
||||||
} = value || {};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
triggerChange({ extension });
|
|
||||||
}, []);
|
|
||||||
const triggerChange = (
|
|
||||||
changedValue: Partial<{
|
|
||||||
country: string;
|
|
||||||
phone: string;
|
|
||||||
extension?: string;
|
|
||||||
}>,
|
|
||||||
) => {
|
|
||||||
if (onChange) {
|
|
||||||
onChange({
|
|
||||||
country,
|
|
||||||
phone,
|
|
||||||
...value,
|
|
||||||
...changedValue,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCountryChange = (newCountry: string) => {
|
|
||||||
triggerChange({
|
|
||||||
country: newCountry,
|
|
||||||
extension: phoneExtensions[newCountry],
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onPhoneChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
|
|
||||||
triggerChange({ phone: e.target.value });
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Input
|
|
||||||
addonBefore={
|
|
||||||
<Select
|
|
||||||
value={country}
|
|
||||||
onChange={onCountryChange}
|
|
||||||
style={{ width: 100 }}
|
|
||||||
>
|
|
||||||
<Option value="CA">🇨🇦 +1</Option>
|
|
||||||
<Option value="CN">🇨🇳 +86</Option>
|
|
||||||
<Option value="US">🇺🇸 +1</Option>
|
|
||||||
{/* 添加更多国家代码 */}
|
|
||||||
</Select>
|
|
||||||
}
|
|
||||||
value={phone}
|
|
||||||
onChange={onPhoneChange}
|
|
||||||
placeholder="请输入联系电话"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default InternationalPhoneInput;
|
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
import { MidwayConfig } from '@midwayjs/core';
|
||||||
|
import { Product } from '../entity/product.entity';
|
||||||
|
import { Category } from '../entity/category.entity';
|
||||||
|
import { WpProduct } from '../entity/wp_product.entity';
|
||||||
|
import { Variation } from '../entity/variation.entity';
|
||||||
|
import { User } from '../entity/user.entity';
|
||||||
|
import { PurchaseOrder } from '../entity/purchase_order.entity';
|
||||||
|
import { PurchaseOrderItem } from '../entity/purchase_order_item.entity';
|
||||||
|
import { Stock } from '../entity/stock.entity';
|
||||||
|
import { StockPoint } from '../entity/stock_point.entity';
|
||||||
|
import { StockRecord } from '../entity/stock_record.entity';
|
||||||
|
import { Order } from '../entity/order.entity';
|
||||||
|
import { OrderItem } from '../entity/order_item.entity';
|
||||||
|
import { OrderCoupon } from '../entity/order_copon.entity';
|
||||||
|
import { OrderFee } from '../entity/order_fee.entity';
|
||||||
|
import { OrderRefund } from '../entity/order_refund.entity';
|
||||||
|
import { OrderRefundItem } from '../entity/order_retund_item.entity';
|
||||||
|
import { OrderSale } from '../entity/order_sale.entity';
|
||||||
|
import { OrderSaleOriginal } from '../entity/order_item_original.entity';
|
||||||
|
import { OrderShipping } from '../entity/order_shipping.entity';
|
||||||
|
import { Service } from '../entity/service.entity';
|
||||||
|
import { ShippingAddress } from '../entity/shipping_address.entity';
|
||||||
|
import { OrderNote } from '../entity/order_note.entity';
|
||||||
|
import { OrderShipment } from '../entity/order_shipment.entity';
|
||||||
|
import { Shipment } from '../entity/shipment.entity';
|
||||||
|
import { ShipmentItem } from '../entity/shipment_item.entity';
|
||||||
|
import { Transfer } from '../entity/transfer.entity';
|
||||||
|
import { TransferItem } from '../entity/transfer_item.entity';
|
||||||
|
import { Strength } from '../entity/strength.entity';
|
||||||
|
import { Flavors } from '../entity/flavors.entity';
|
||||||
|
import { CustomerTag } from '../entity/customer_tag.entity';
|
||||||
|
import { Customer } from '../entity/customer.entity';
|
||||||
|
import { DeviceWhitelist } from '../entity/device_whitelist';
|
||||||
|
import { AuthCode } from '../entity/auth_code';
|
||||||
|
import { Subscription } from '../entity/subscription.entity';
|
||||||
|
import { Site } from '../entity/site.entity';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
// use for cookie sign key, should change to your own and keep security
|
||||||
|
keys: '1733728588817_720',
|
||||||
|
typeorm: {
|
||||||
|
default: {
|
||||||
|
entities: [
|
||||||
|
Product,
|
||||||
|
Category,
|
||||||
|
Strength,
|
||||||
|
Flavors,
|
||||||
|
WpProduct,
|
||||||
|
Variation,
|
||||||
|
User,
|
||||||
|
PurchaseOrder,
|
||||||
|
PurchaseOrderItem,
|
||||||
|
Stock,
|
||||||
|
StockPoint,
|
||||||
|
StockRecord,
|
||||||
|
Order,
|
||||||
|
OrderItem,
|
||||||
|
OrderCoupon,
|
||||||
|
OrderFee,
|
||||||
|
OrderRefund,
|
||||||
|
OrderRefundItem,
|
||||||
|
OrderSale,
|
||||||
|
OrderSaleOriginal,
|
||||||
|
OrderShipment,
|
||||||
|
ShipmentItem,
|
||||||
|
Shipment,
|
||||||
|
OrderShipping,
|
||||||
|
Service,
|
||||||
|
ShippingAddress,
|
||||||
|
OrderNote,
|
||||||
|
Transfer,
|
||||||
|
TransferItem,
|
||||||
|
CustomerTag,
|
||||||
|
Customer,
|
||||||
|
DeviceWhitelist,
|
||||||
|
AuthCode,
|
||||||
|
Subscription,
|
||||||
|
Site,
|
||||||
|
],
|
||||||
|
synchronize: true,
|
||||||
|
logging: false,
|
||||||
|
},
|
||||||
|
dataSource: {
|
||||||
|
default: {
|
||||||
|
type: 'mysql',
|
||||||
|
host: 'localhost',
|
||||||
|
port: 3306,
|
||||||
|
username: 'root',
|
||||||
|
password: 'root',
|
||||||
|
database: 'inventory',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// cors: {
|
||||||
|
// origin: '*', // 允许所有来源跨域请求
|
||||||
|
// allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // 允许的 HTTP 方法
|
||||||
|
// allowHeaders: ['Content-Type', 'Authorization'], // 允许的自定义请求头
|
||||||
|
// credentials: true, // 允许携带凭据(cookies等)
|
||||||
|
// },
|
||||||
|
// jwt: {
|
||||||
|
// secret: 'YOONE2024!@abc',
|
||||||
|
// expiresIn: '7d',
|
||||||
|
// },
|
||||||
|
// wpSite: [
|
||||||
|
// {
|
||||||
|
// id: '2',
|
||||||
|
// wpApiUrl: 'http://localhost:10004',
|
||||||
|
// consumerKey: 'ck_dc9e151e9048c8ed3e27f35ac79d2bf7d6840652',
|
||||||
|
// consumerSecret: 'cs_d05d625d7b0ac05c6d765671d8417f41d9477e38',
|
||||||
|
// siteName: 'Local',
|
||||||
|
// email: 'tom@yoonevape.com',
|
||||||
|
// emailPswd: '',
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
swagger: {
|
||||||
|
auth: {
|
||||||
|
name: 'authorization',
|
||||||
|
authType: 'bearer',
|
||||||
|
description: 'Bearer Auth',
|
||||||
|
addSecurityRequirements: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mailer: {
|
||||||
|
host: 'smtphz.qiye.163.com',
|
||||||
|
port: 465,
|
||||||
|
secure: true,
|
||||||
|
auth: {
|
||||||
|
user: 'info@canpouches.com',
|
||||||
|
pass: 'WWqQ4aZq4Jrm9uwz',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} as MidwayConfig;
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
import { MidwayConfig } from '@midwayjs/core';
|
||||||
|
export default {
|
||||||
|
koa: {
|
||||||
|
port: 7001,
|
||||||
|
},
|
||||||
|
// typeorm: {
|
||||||
|
// dataSource: {
|
||||||
|
// default: {
|
||||||
|
// host: '13.212.62.127',
|
||||||
|
// username: 'root',
|
||||||
|
// password: 'Yoone!@.2025',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
typeorm: {
|
||||||
|
dataSource: {
|
||||||
|
default: {
|
||||||
|
host: 'localhost',
|
||||||
|
username: 'root',
|
||||||
|
password: '12345678',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cors: {
|
||||||
|
origin: '*', // 允许所有来源跨域请求
|
||||||
|
allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], // 允许的 HTTP 方法
|
||||||
|
allowHeaders: ['Content-Type', 'Authorization'], // 允许的自定义请求头
|
||||||
|
credentials: true, // 允许携带凭据(cookies等)
|
||||||
|
},
|
||||||
|
jwt: {
|
||||||
|
secret: 'YOONE2024!@abc',
|
||||||
|
expiresIn: '7d',
|
||||||
|
},
|
||||||
|
wpSite: [
|
||||||
|
{
|
||||||
|
id: '-1',
|
||||||
|
siteName: 'Admin',
|
||||||
|
email: '2469687281@qq.com',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '2',
|
||||||
|
wpApiUrl: 'http://t2-shop.local/',
|
||||||
|
consumerKey: 'ck_a369473a6451dbaec63d19cbfd74a074b2c5f742',
|
||||||
|
consumerSecret: 'cs_0946bbbeea1bfefff08a69e817ac62a48412df8c',
|
||||||
|
siteName: 'Local',
|
||||||
|
email: '2469687281@qq.com',
|
||||||
|
emailPswd: 'lulin91.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: '3',
|
||||||
|
wpApiUrl: 'http://t1-shop.local/',
|
||||||
|
consumerKey: 'ck_a369473a6451dbaec63d19cbfd74a074b2c5f742',
|
||||||
|
consumerSecret: 'cs_0946bbbeea1bfefff08a69e817ac62a48412df8c',
|
||||||
|
siteName: 'Local-test-2',
|
||||||
|
email: '2469687281@qq.com',
|
||||||
|
emailPswd: 'lulin91.',
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// id: '2',
|
||||||
|
// wpApiUrl: 'http://localhost:10004',
|
||||||
|
// consumerKey: 'ck_dc9e151e9048c8ed3e27f35ac79d2bf7d6840652',
|
||||||
|
// consumerSecret: 'cs_d05d625d7b0ac05c6d765671d8417f41d9477e38',
|
||||||
|
// siteName: 'Local',
|
||||||
|
// email: 'tom@yoonevape.com',
|
||||||
|
// emailPswd: 'lulin91.',
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
freightcom: {
|
||||||
|
url: 'https://customer-external-api.ssd-test.freightcom.com',
|
||||||
|
token: '6zGj1qPTL1jIkbLmgaiYc6SwHUIXJ2t25htUF8uuFYiCg8ILCY6xnBEbvrX1p79L',
|
||||||
|
},
|
||||||
|
canadaPost: {
|
||||||
|
url: 'https://ct.soa-gw.canadapost.ca',
|
||||||
|
username: '65d23d3a75d7baf7',
|
||||||
|
password: '56443bb98b68dfdd60f52e',
|
||||||
|
customerNumber: '0006122480',
|
||||||
|
contractId: '0044168528',
|
||||||
|
},
|
||||||
|
uniExpress: {
|
||||||
|
url: 'https://sjqa.uniexpress.org', // 测试环境url
|
||||||
|
// url: 'https://sj.uniexpress.ca', //正式环境url
|
||||||
|
clientId: '101018',
|
||||||
|
clientSecret: 'cbcb51bea204f3f69c47b5280064408e',
|
||||||
|
customerNo: 2067,
|
||||||
|
}
|
||||||
|
} as MidwayConfig;
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { MidwayConfig } from '@midwayjs/core';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
koa: {
|
||||||
|
port: null,
|
||||||
|
},
|
||||||
|
} as MidwayConfig;
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
import {
|
||||||
|
Configuration,
|
||||||
|
App,
|
||||||
|
Inject,
|
||||||
|
MidwayDecoratorService,
|
||||||
|
} from '@midwayjs/core';
|
||||||
|
import * as koa from '@midwayjs/koa';
|
||||||
|
import * as validate from '@midwayjs/validate';
|
||||||
|
import * as info from '@midwayjs/info';
|
||||||
|
import * as orm from '@midwayjs/typeorm';
|
||||||
|
import { join } from 'path';
|
||||||
|
// import { DefaultErrorFilter } from './filter/default.filter';
|
||||||
|
// import { NotFoundFilter } from './filter/notfound.filter';
|
||||||
|
import { ReportMiddleware } from './middleware/report.middleware';
|
||||||
|
import * as swagger from '@midwayjs/swagger';
|
||||||
|
import * as crossDomain from '@midwayjs/cross-domain';
|
||||||
|
import * as cron from '@midwayjs/cron';
|
||||||
|
import * as jwt from '@midwayjs/jwt';
|
||||||
|
import { USER_KEY } from './decorator/user.decorator';
|
||||||
|
import { SiteService } from './service/site.service';
|
||||||
|
import { AuthMiddleware } from './middleware/auth.middleware';
|
||||||
|
|
||||||
|
@Configuration({
|
||||||
|
imports: [
|
||||||
|
koa,
|
||||||
|
validate,
|
||||||
|
{
|
||||||
|
component: info,
|
||||||
|
enabledEnvironment: ['local', 'prod'],
|
||||||
|
},
|
||||||
|
orm,
|
||||||
|
swagger,
|
||||||
|
crossDomain,
|
||||||
|
cron,
|
||||||
|
jwt,
|
||||||
|
],
|
||||||
|
importConfigs: [join(__dirname, './config')],
|
||||||
|
})
|
||||||
|
export class MainConfiguration {
|
||||||
|
@App('koa')
|
||||||
|
app: koa.Application;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
decoratorService: MidwayDecoratorService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
jwtService: jwt.JwtService; // 注入 JwtService 实例
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
siteService: SiteService;
|
||||||
|
|
||||||
|
async onReady() {
|
||||||
|
// add middleware
|
||||||
|
this.app.useMiddleware([ReportMiddleware, AuthMiddleware]);
|
||||||
|
// add filter
|
||||||
|
// this.app.useFilter([NotFoundFilter, DefaultErrorFilter]);
|
||||||
|
|
||||||
|
this.decoratorService.registerParameterHandler(
|
||||||
|
USER_KEY,
|
||||||
|
async (
|
||||||
|
options
|
||||||
|
): Promise<{
|
||||||
|
id: number;
|
||||||
|
userName: string;
|
||||||
|
}> => {
|
||||||
|
const ctx = options.originArgs[0];
|
||||||
|
const token = ctx.headers['authorization']?.split(' ')[1];
|
||||||
|
const config = ctx.app.getConfig('jwt'); // 动态获取配置项
|
||||||
|
if (!token) {
|
||||||
|
ctx.throw(401, 'Token not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const decoded: any = this.jwtService.verify(token, config.secret); // 替换为你的密钥
|
||||||
|
return decoded;
|
||||||
|
} catch (error) {
|
||||||
|
ctx.throw(401, 'Invalid token');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,120 +0,0 @@
|
||||||
import { ProSchemaValueEnumObj } from '@ant-design/pro-components';
|
|
||||||
|
|
||||||
export const DEFAULT_NAME = 'YOONE';
|
|
||||||
|
|
||||||
export const PRODUCT_STATUS_ENUM: ProSchemaValueEnumObj = {
|
|
||||||
publish: {
|
|
||||||
text: '已发布',
|
|
||||||
status: 'success',
|
|
||||||
},
|
|
||||||
draft: {
|
|
||||||
text: '草稿',
|
|
||||||
status: 'draft',
|
|
||||||
},
|
|
||||||
pending: {
|
|
||||||
text: '待审核',
|
|
||||||
status: 'pending',
|
|
||||||
},
|
|
||||||
private: {
|
|
||||||
text: '私有',
|
|
||||||
status: 'private',
|
|
||||||
},
|
|
||||||
trash: {
|
|
||||||
text: '已删除',
|
|
||||||
status: 'error',
|
|
||||||
},
|
|
||||||
'auto-draft': {
|
|
||||||
text: '自动草稿',
|
|
||||||
status: 'auto-draft',
|
|
||||||
},
|
|
||||||
future: {
|
|
||||||
text: '定时发布',
|
|
||||||
status: 'success',
|
|
||||||
},
|
|
||||||
inherit: {
|
|
||||||
text: '继承状态',
|
|
||||||
status: 'inherit',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const PRODUCT_STOCK_STATUS_ENUM: ProSchemaValueEnumObj = {
|
|
||||||
instock: {
|
|
||||||
text: '上架',
|
|
||||||
status: 'instock',
|
|
||||||
},
|
|
||||||
outofstock: {
|
|
||||||
text: 'out of stock',
|
|
||||||
status: 'outofstock',
|
|
||||||
},
|
|
||||||
onbackorder: {
|
|
||||||
text: 'on back order',
|
|
||||||
status: 'onbackorder',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Purchase_Order_STATUS_ENUM: ProSchemaValueEnumObj = {
|
|
||||||
draft: {
|
|
||||||
text: '草稿',
|
|
||||||
status: 'default',
|
|
||||||
},
|
|
||||||
submitted: {
|
|
||||||
text: '已发货',
|
|
||||||
status: 'warning',
|
|
||||||
},
|
|
||||||
received: {
|
|
||||||
text: '已到达',
|
|
||||||
status: 'success',
|
|
||||||
disabled: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ORDER_STATUS_ENUM: ProSchemaValueEnumObj = {
|
|
||||||
pending: {
|
|
||||||
text: '待确认',
|
|
||||||
status: 'default',
|
|
||||||
},
|
|
||||||
processing: {
|
|
||||||
text: '待发货',
|
|
||||||
status: 'success',
|
|
||||||
},
|
|
||||||
completed: {
|
|
||||||
text: '已完成',
|
|
||||||
status: 'success',
|
|
||||||
},
|
|
||||||
cancelled: {
|
|
||||||
text: '已取消',
|
|
||||||
status: 'error',
|
|
||||||
},
|
|
||||||
refunded: {
|
|
||||||
text: '已退款',
|
|
||||||
status: 'warning',
|
|
||||||
},
|
|
||||||
failed: {
|
|
||||||
text: '失败',
|
|
||||||
status: 'error',
|
|
||||||
},
|
|
||||||
after_sale_pending: {
|
|
||||||
text: '售后处理中',
|
|
||||||
status: 'warning',
|
|
||||||
},
|
|
||||||
pending_reshipment: {
|
|
||||||
text: '待补发',
|
|
||||||
status: 'warning',
|
|
||||||
},
|
|
||||||
pending_refund: {
|
|
||||||
text: '待退款',
|
|
||||||
status: 'warning',
|
|
||||||
},
|
|
||||||
refund_requested: {
|
|
||||||
text: '已申请退款',
|
|
||||||
status: 'refund_approved',
|
|
||||||
},
|
|
||||||
refund_approved: {
|
|
||||||
text: '退款申请已通过',
|
|
||||||
status: 'refund_approved',
|
|
||||||
},
|
|
||||||
refund_cancelled: {
|
|
||||||
text: '已取消退款',
|
|
||||||
status: 'refund_cancelled',
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Inject, Controller } from '@midwayjs/core';
|
||||||
|
import { Context } from '@midwayjs/koa';
|
||||||
|
|
||||||
|
|
||||||
|
@Controller('/')
|
||||||
|
export class APIController {
|
||||||
|
@Inject()
|
||||||
|
ctx: Context;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Context,
|
||||||
|
Controller,
|
||||||
|
Del,
|
||||||
|
Get,
|
||||||
|
Inject,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Query,
|
||||||
|
} from '@midwayjs/core';
|
||||||
|
import { CustomerService } from '../service/customer.service';
|
||||||
|
import { errorResponse, successResponse } from '../utils/response.util';
|
||||||
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
||||||
|
import { BooleanRes } from '../dto/reponse.dto';
|
||||||
|
import { CustomerTagDTO, QueryCustomerListDTO } from '../dto/customer.dto';
|
||||||
|
|
||||||
|
@Controller('/customer')
|
||||||
|
export class CustomerController {
|
||||||
|
@Inject()
|
||||||
|
ctx: Context;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
customerService: CustomerService;
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/list')
|
||||||
|
async getCustomerList(@Query() param: QueryCustomerListDTO) {
|
||||||
|
try {
|
||||||
|
const data = await this.customerService.getCustomerList(param);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Post('/tag/add')
|
||||||
|
async addTag(@Body() dto: CustomerTagDTO) {
|
||||||
|
try {
|
||||||
|
await this.customerService.addTag(dto.email, dto.tag);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Del('/tag/del')
|
||||||
|
async delTag(@Body() dto: CustomerTagDTO) {
|
||||||
|
try {
|
||||||
|
await this.customerService.delTag(dto.email, dto.tag);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/tags')
|
||||||
|
async getTags() {
|
||||||
|
try {
|
||||||
|
const data = await this.customerService.getTags();
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Put('/rate')
|
||||||
|
async setRate(@Body() params: { id: number; rate: number }) {
|
||||||
|
try {
|
||||||
|
await this.customerService.setRate(params);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,288 @@
|
||||||
|
import {
|
||||||
|
Inject,
|
||||||
|
Controller,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Get,
|
||||||
|
Put,
|
||||||
|
Param,
|
||||||
|
Del,
|
||||||
|
Query,
|
||||||
|
} from '@midwayjs/core';
|
||||||
|
import { Context } from '@midwayjs/koa';
|
||||||
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
||||||
|
import {
|
||||||
|
BooleanRes,
|
||||||
|
RateLitRes,
|
||||||
|
ServiceListRes,
|
||||||
|
ShippingAddressListRes,
|
||||||
|
} from '../dto/reponse.dto';
|
||||||
|
import { FreightcomService } from '../service/freightcom.service';
|
||||||
|
import { errorResponse, successResponse } from '../utils/response.util';
|
||||||
|
import { LogisticsService } from '../service/logistics.service';
|
||||||
|
import { ShippingDetailsDTO } from '../dto/freightcom.dto';
|
||||||
|
import { ShippingAddress } from '../entity/shipping_address.entity';
|
||||||
|
import { QueryServiceDTO, ShipmentBookDTO, ShipmentFeeBookDTO } from '../dto/logistics.dto';
|
||||||
|
import { User } from '../decorator/user.decorator';
|
||||||
|
|
||||||
|
@Controller('/logistics')
|
||||||
|
export class LogisticsController {
|
||||||
|
@Inject()
|
||||||
|
ctx: Context;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
freightcomService: FreightcomService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
logisticsService: LogisticsService;
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Post('/syncServices')
|
||||||
|
async syncServices() {
|
||||||
|
try {
|
||||||
|
await this.freightcomService.syncServices();
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse('同步失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
description: '服务商列表',
|
||||||
|
type: ServiceListRes,
|
||||||
|
})
|
||||||
|
@Get('/getServiceList')
|
||||||
|
async getServiceList(
|
||||||
|
@Query()
|
||||||
|
param: QueryServiceDTO
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const data = await this.logisticsService.getServiceList(param);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/toggleActive')
|
||||||
|
async toggleActive(@Body() body: { id: string; isActive: boolean }) {
|
||||||
|
try {
|
||||||
|
await this.logisticsService.toggleServiceActive(body.id, body.isActive);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: RateLitRes,
|
||||||
|
})
|
||||||
|
@Post('/getRateList')
|
||||||
|
async getRateList(@Body() details: ShippingDetailsDTO) {
|
||||||
|
try {
|
||||||
|
const rates = await this.logisticsService.getRateList(details);
|
||||||
|
return successResponse(rates);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Post('/createShippingAddress')
|
||||||
|
async createShippingAddress(@Body() shippingAddress: ShippingAddress) {
|
||||||
|
try {
|
||||||
|
await this.logisticsService.createShippingAddress(shippingAddress);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Put('/updateShippingAddress/:id')
|
||||||
|
async updateShippingAddress(
|
||||||
|
@Body() shippingAddress: ShippingAddress,
|
||||||
|
@Param('id') id: number
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
await this.logisticsService.updateShippingAddress(id, shippingAddress);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: ShippingAddressListRes,
|
||||||
|
})
|
||||||
|
@Get('/getShippingAddressList')
|
||||||
|
async getShippingAddressList() {
|
||||||
|
try {
|
||||||
|
const data = await this.logisticsService.getShippingAddressList();
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Del('/delShippingAddress/:id')
|
||||||
|
async delShippingAddress(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
const boolen = await this.logisticsService.delShippingAddress(id);
|
||||||
|
return successResponse(boolen);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '删除失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Post('/deleteShipment/:id')
|
||||||
|
async deleteShipment(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
const res = await this.logisticsService.removeShipment(id);
|
||||||
|
return successResponse(res);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '删除运单失败' );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Post('/createShipment/:orderId')
|
||||||
|
async createShipment(
|
||||||
|
@Param('orderId') orderId: number,
|
||||||
|
@Body() data: ShipmentBookDTO,
|
||||||
|
@User() user
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const res: any = await this.logisticsService.createShipment(orderId, data, user.id);
|
||||||
|
return successResponse(res.data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse(
|
||||||
|
{type: BooleanRes}
|
||||||
|
)
|
||||||
|
@Post('/getShipmentFee')
|
||||||
|
async getShipmentFee(
|
||||||
|
@Body() data: ShipmentFeeBookDTO
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const fee = await this.logisticsService.getShipmentFee(data);
|
||||||
|
return successResponse(fee);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse(
|
||||||
|
{type: BooleanRes}
|
||||||
|
)
|
||||||
|
@Post('/getShipmentLabel/:shipmentId')
|
||||||
|
async getShipmentLabel(
|
||||||
|
@Param('shipmentId') shipmentId: number
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const res = await this.logisticsService.getShipmentLabel(shipmentId);
|
||||||
|
|
||||||
|
if (res.data.data[0].status === 'Success') {
|
||||||
|
return successResponse({ content: res.data.data[0].labelContent });
|
||||||
|
} else {
|
||||||
|
return errorResponse(res.data.data[0].errors);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/getPaymentMethods')
|
||||||
|
async getpaymentmethods() {
|
||||||
|
try {
|
||||||
|
const data = await this.freightcomService.getPaymentMethods();
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/updateState/:shipmentId')
|
||||||
|
async updateShipmentState(
|
||||||
|
@Param('shipmentId') shipmentId: number
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const data = await this.logisticsService.updateShipmentStateById(shipmentId);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新运单状态失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Del('/shipment/:id')
|
||||||
|
async delShipment(@Param('id') id: number, @User() user) {
|
||||||
|
try {
|
||||||
|
const data = await this.logisticsService.delShipment(id, user.id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/getOrderList')
|
||||||
|
async getOrderList(@Query('number') number: string) {
|
||||||
|
try {
|
||||||
|
return successResponse(
|
||||||
|
await this.logisticsService.getOrderList(number)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/getListByOrderId')
|
||||||
|
async getListByOrderId(@Query('id') orderId: number) {
|
||||||
|
try {
|
||||||
|
return successResponse(
|
||||||
|
await this.logisticsService.getListByOrderId(orderId)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
description: '物流列表',
|
||||||
|
})
|
||||||
|
@Get('/list')
|
||||||
|
async getList(
|
||||||
|
@Query()
|
||||||
|
param: Record<string, any>
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const data = await this.logisticsService.getList(param);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
import {
|
||||||
|
Body,
|
||||||
|
Controller,
|
||||||
|
Del,
|
||||||
|
Get,
|
||||||
|
Inject,
|
||||||
|
Param,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Query,
|
||||||
|
} from '@midwayjs/core';
|
||||||
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
||||||
|
import {
|
||||||
|
BooleanRes,
|
||||||
|
OrderDetailRes,
|
||||||
|
OrderListRes,
|
||||||
|
OrderSaleListRes,
|
||||||
|
} from '../dto/reponse.dto';
|
||||||
|
import { OrderService } from '../service/order.service';
|
||||||
|
import { errorResponse, successResponse } from '../utils/response.util';
|
||||||
|
import {
|
||||||
|
CreateOrderNoteDTO,
|
||||||
|
QueryOrderDTO,
|
||||||
|
QueryOrderSalesDTO,
|
||||||
|
QueryOrderItemDTO,
|
||||||
|
} from '../dto/order.dto';
|
||||||
|
import { User } from '../decorator/user.decorator';
|
||||||
|
import { ErpOrderStatus } from '../enums/base.enum';
|
||||||
|
|
||||||
|
@Controller('/order')
|
||||||
|
export class OrderController {
|
||||||
|
@Inject()
|
||||||
|
orderService: OrderService;
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Post('/syncOrder/:siteId')
|
||||||
|
async syncOrder(@Param('siteId') siteId: string) {
|
||||||
|
try {
|
||||||
|
await this.orderService.syncOrders(siteId);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return errorResponse('同步失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Post('/syncOrder/:siteId/order/:orderId')
|
||||||
|
async syncOrderById(
|
||||||
|
@Param('siteId') siteId: string,
|
||||||
|
@Param('orderId') orderId: string
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
await this.orderService.syncOrderById(siteId, orderId);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return errorResponse('同步失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: OrderListRes,
|
||||||
|
})
|
||||||
|
@Get('/getOrders')
|
||||||
|
async getOrders(
|
||||||
|
@Query()
|
||||||
|
param: QueryOrderDTO,
|
||||||
|
@User() user
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const count = await this.orderService.getOrderStatus(param);
|
||||||
|
const data = await this.orderService.getOrders(param, user.id);
|
||||||
|
return successResponse({
|
||||||
|
...data,
|
||||||
|
count,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: OrderSaleListRes,
|
||||||
|
})
|
||||||
|
@Get('/getOrderSales')
|
||||||
|
async getOrderSales(@Query() param: QueryOrderSalesDTO) {
|
||||||
|
try {
|
||||||
|
if (param.isSource)
|
||||||
|
return successResponse(await this.orderService.getOrderItems(param));
|
||||||
|
return successResponse(await this.orderService.getOrderSales(param));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/getOrderItems')
|
||||||
|
async getOrderItems(@Query() param: QueryOrderSalesDTO) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.getOrderItems(param));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/getOrderItemList')
|
||||||
|
async getOrderItemList(@Query() param: QueryOrderItemDTO) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.getOrderItemList(param));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: OrderDetailRes,
|
||||||
|
})
|
||||||
|
@Get('/:orderId')
|
||||||
|
async getOrderDetail(@Param('orderId') orderId: number) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.getOrderDetail(orderId));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/:orderId/related')
|
||||||
|
async getRelatedByOrder(@Param('orderId') orderId: number) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.getRelatedByOrder(orderId));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Post('/updateOrderItems/:orderId')
|
||||||
|
async updateOrderItems(
|
||||||
|
@Param('orderId') orderId: number,
|
||||||
|
@Body() data: any,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const res = await this.orderService.updateExchangeOrder(orderId, data);
|
||||||
|
return successResponse(res);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Del('/:id')
|
||||||
|
async delOrder(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.delOrder(id));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '删除失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Post('/createNote')
|
||||||
|
async createNote(@Body() data: CreateOrderNoteDTO, @User() user) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.createNote(user.id, data));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/getOrderByNumber')
|
||||||
|
async getOrderByNumber(@Body('number') number: string) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.getOrderByNumber(number));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/order/cancel/:id')
|
||||||
|
async cancelOrder(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.cancelOrder(id));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/order/refund/:id')
|
||||||
|
async refundOrder(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.refundOrder(id));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/order/completed/:id')
|
||||||
|
async completedOrder(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.completedOrder(id));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Put('/order/status/:id')
|
||||||
|
async changeStatus(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Body('status') status: ErpOrderStatus
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.changeStatus(id, status));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/order/create')
|
||||||
|
async createOrder(@Body() data: Record<string, any>) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.createOrder(data));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/order/pengding/items')
|
||||||
|
async pengdingItems(@Body() data: Record<string, any>) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.orderService.pengdingItems(data));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,405 @@
|
||||||
|
import {
|
||||||
|
Inject,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
Get,
|
||||||
|
Body,
|
||||||
|
Param,
|
||||||
|
Del,
|
||||||
|
Query,
|
||||||
|
Controller,
|
||||||
|
} from '@midwayjs/core';
|
||||||
|
import { ProductService } from '../service/product.service';
|
||||||
|
import { errorResponse, successResponse } from '../utils/response.util';
|
||||||
|
import {
|
||||||
|
BatchSetSkuDTO,
|
||||||
|
CreateCategoryDTO,
|
||||||
|
CreateFlavorsDTO,
|
||||||
|
CreateProductDTO,
|
||||||
|
CreateStrengthDTO,
|
||||||
|
QueryCategoryDTO,
|
||||||
|
QueryFlavorsDTO,
|
||||||
|
QueryProductDTO,
|
||||||
|
QueryStrengthDTO,
|
||||||
|
UpdateCategoryDTO,
|
||||||
|
UpdateFlavorsDTO,
|
||||||
|
UpdateProductDTO,
|
||||||
|
UpdateStrengthDTO,
|
||||||
|
} from '../dto/product.dto';
|
||||||
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
||||||
|
import {
|
||||||
|
BooleanRes,
|
||||||
|
ProductCatListRes,
|
||||||
|
ProductCatRes,
|
||||||
|
ProductListRes,
|
||||||
|
ProductRes,
|
||||||
|
ProductsRes,
|
||||||
|
} from '../dto/reponse.dto';
|
||||||
|
|
||||||
|
@Controller('/product')
|
||||||
|
export class ProductController {
|
||||||
|
@Inject()
|
||||||
|
productService: ProductService;
|
||||||
|
ProductRes;
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
description: '通过name搜索产品',
|
||||||
|
type: ProductsRes,
|
||||||
|
})
|
||||||
|
@Get('/search')
|
||||||
|
async searchProducts(@Query('name') name: string) {
|
||||||
|
try {
|
||||||
|
// 调用服务获取产品数据
|
||||||
|
const products = await this.productService.findProductsByName(name);
|
||||||
|
return successResponse(products);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error.message || '获取数据失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: ProductRes,
|
||||||
|
})
|
||||||
|
@Get('/sku/:sku')
|
||||||
|
async productBySku(@Param('sku') sku: string) {
|
||||||
|
try {
|
||||||
|
// 调用服务获取产品数据
|
||||||
|
const product = await this.productService.findProductBySku(sku);
|
||||||
|
return successResponse(product);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error.message || '获取数据失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
description: '成功返回产品列表',
|
||||||
|
type: ProductListRes,
|
||||||
|
})
|
||||||
|
@Get('/list')
|
||||||
|
async getProductList(
|
||||||
|
@Query() query: QueryProductDTO
|
||||||
|
): Promise<ProductListRes> {
|
||||||
|
const { current = 1, pageSize = 10, name, categoryId } = query;
|
||||||
|
try {
|
||||||
|
const data = await this.productService.getProductList(
|
||||||
|
{ current, pageSize },
|
||||||
|
name,
|
||||||
|
categoryId
|
||||||
|
);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: ProductRes,
|
||||||
|
})
|
||||||
|
@Post('/')
|
||||||
|
async createProduct(@Body() productData: CreateProductDTO) {
|
||||||
|
try {
|
||||||
|
const data = this.productService.createProduct(productData);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: ProductRes,
|
||||||
|
})
|
||||||
|
@Put('/:id')
|
||||||
|
async updateProduct(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Body() productData: UpdateProductDTO
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const data = this.productService.updateProduct(id, productData);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: ProductRes,
|
||||||
|
})
|
||||||
|
@Put('updateNameCn/:id/:nameCn')
|
||||||
|
async updateProductNameCn(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Param('nameCn') nameCn: string
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const data = this.productService.updateProductNameCn(id, nameCn);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Del('/:id')
|
||||||
|
async deleteProduct(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
const data = await this.productService.deleteProduct(id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: ProductCatListRes,
|
||||||
|
})
|
||||||
|
@Get('/categories')
|
||||||
|
async getCategories(@Query() query: QueryCategoryDTO) {
|
||||||
|
const { current = 1, pageSize = 10, name } = query;
|
||||||
|
try {
|
||||||
|
let data = await this.productService.getCategoryList(
|
||||||
|
{ current, pageSize },
|
||||||
|
name
|
||||||
|
);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/categorieAll')
|
||||||
|
async getCategorieAll() {
|
||||||
|
try {
|
||||||
|
let data = await this.productService.getCategoryAll();
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: ProductCatRes,
|
||||||
|
})
|
||||||
|
@Post('/category')
|
||||||
|
async createCategory(@Body() categoryData: CreateCategoryDTO) {
|
||||||
|
try {
|
||||||
|
const hasCategory = await this.productService.hasCategory(
|
||||||
|
categoryData.name
|
||||||
|
);
|
||||||
|
if (hasCategory) {
|
||||||
|
return errorResponse('分类已存在');
|
||||||
|
}
|
||||||
|
let data = await this.productService.createCategory(categoryData);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: ProductCatRes,
|
||||||
|
})
|
||||||
|
@Put('/category/:id')
|
||||||
|
async updateCategory(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Body() categoryData: UpdateCategoryDTO
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const hasCategory = await this.productService.hasCategory(
|
||||||
|
categoryData.name
|
||||||
|
);
|
||||||
|
if (hasCategory) {
|
||||||
|
return errorResponse('分类已存在');
|
||||||
|
}
|
||||||
|
const data = this.productService.updateCategory(id, categoryData);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Del('/category/:id')
|
||||||
|
async deleteCategory(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
const hasProducts = await this.productService.hasProductsInCategory(id);
|
||||||
|
if (hasProducts) throw new Error('该分类下有商品,无法删除');
|
||||||
|
const data = await this.productService.deleteCategory(id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/batchSetSku')
|
||||||
|
@ApiOkResponse({
|
||||||
|
description: '批量设置 sku 的响应结果',
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
async batchSetSku(@Body() body: BatchSetSkuDTO) {
|
||||||
|
try {
|
||||||
|
const result = await this.productService.batchSetSku(body.skus);
|
||||||
|
return successResponse(result, '批量设置 sku 成功');
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error.message, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/flavorsAll')
|
||||||
|
async getFlavorsAll() {
|
||||||
|
try {
|
||||||
|
let data = await this.productService.getFlavorsAll();
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/flavors')
|
||||||
|
async getFlavors(@Query() query: QueryFlavorsDTO) {
|
||||||
|
const { current = 1, pageSize = 10, name } = query;
|
||||||
|
try {
|
||||||
|
let data = await this.productService.getFlavorsList(
|
||||||
|
{ current, pageSize },
|
||||||
|
name
|
||||||
|
);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/flavors')
|
||||||
|
async createFlavors(@Body() flavorsData: CreateFlavorsDTO) {
|
||||||
|
try {
|
||||||
|
const hasFlavors = await this.productService.hasFlavors(flavorsData.name);
|
||||||
|
if (hasFlavors) {
|
||||||
|
return errorResponse('分类已存在');
|
||||||
|
}
|
||||||
|
let data = await this.productService.createFlavors(flavorsData);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Put('/flavors/:id')
|
||||||
|
async updateFlavors(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Body() flavorsData: UpdateFlavorsDTO
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const hasFlavors = await this.productService.hasFlavors(flavorsData.name);
|
||||||
|
if (hasFlavors) {
|
||||||
|
return errorResponse('分类已存在');
|
||||||
|
}
|
||||||
|
const data = this.productService.updateFlavors(id, flavorsData);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Del('/flavors/:id')
|
||||||
|
async deleteFlavors(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
const hasProducts = await this.productService.hasProductsInFlavors(id);
|
||||||
|
if (hasProducts) throw new Error('该分类下有商品,无法删除');
|
||||||
|
const data = await this.productService.deleteFlavors(id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/strengthAll')
|
||||||
|
async getStrengthAll() {
|
||||||
|
try {
|
||||||
|
let data = await this.productService.getStrengthAll();
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/strength')
|
||||||
|
async getStrength(@Query() query: QueryStrengthDTO) {
|
||||||
|
const { current = 1, pageSize = 10, name } = query;
|
||||||
|
try {
|
||||||
|
let data = await this.productService.getStrengthList(
|
||||||
|
{ current, pageSize },
|
||||||
|
name
|
||||||
|
);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/strength')
|
||||||
|
async createStrength(@Body() strengthData: CreateStrengthDTO) {
|
||||||
|
try {
|
||||||
|
const hasStrength = await this.productService.hasStrength(
|
||||||
|
strengthData.name
|
||||||
|
);
|
||||||
|
if (hasStrength) {
|
||||||
|
return errorResponse('分类已存在');
|
||||||
|
}
|
||||||
|
let data = await this.productService.createStrength(strengthData);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Put('/strength/:id')
|
||||||
|
async updateStrength(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Body() strengthData: UpdateStrengthDTO
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const hasStrength = await this.productService.hasStrength(
|
||||||
|
strengthData.name
|
||||||
|
);
|
||||||
|
if (hasStrength) {
|
||||||
|
return errorResponse('分类已存在');
|
||||||
|
}
|
||||||
|
const data = this.productService.updateStrength(id, strengthData);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Del('/strength/:id')
|
||||||
|
async deleteStrength(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
const hasProducts = await this.productService.hasProductsInStrength(id);
|
||||||
|
if (hasProducts) throw new Error('该分类下有商品,无法删除');
|
||||||
|
const data = await this.productService.deleteStrength(id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { Body, Controller, Get, Inject, Param, Put, Post, Query } from '@midwayjs/core';
|
||||||
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
||||||
|
import { WpSitesResponse } from '../dto/reponse.dto';
|
||||||
|
import { errorResponse, successResponse } from '../utils/response.util';
|
||||||
|
import { SiteService } from '../service/site.service';
|
||||||
|
import { CreateSiteDTO, DisableSiteDTO, QuerySiteDTO, UpdateSiteDTO } from '../dto/site.dto';
|
||||||
|
|
||||||
|
@Controller('/site')
|
||||||
|
export class SiteController {
|
||||||
|
@Inject()
|
||||||
|
siteService: SiteService;
|
||||||
|
|
||||||
|
@ApiOkResponse({ description: '关联网站', type: WpSitesResponse })
|
||||||
|
@Get('/all')
|
||||||
|
async all() {
|
||||||
|
try {
|
||||||
|
const { items } = await this.siteService.list({ current: 1, pageSize: 1000, isDisabled: false });
|
||||||
|
return successResponse(items.map((v: any) => ({ id: v.id, siteName: v.siteName })));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/create')
|
||||||
|
async create(@Body() body: CreateSiteDTO) {
|
||||||
|
try {
|
||||||
|
await this.siteService.create(body);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Put('/update/:id')
|
||||||
|
async update(@Param('id') id: string, @Body() body: UpdateSiteDTO) {
|
||||||
|
try {
|
||||||
|
await this.siteService.update(Number(id), body);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('/get/:id')
|
||||||
|
async get(@Param('id') id: string) {
|
||||||
|
try {
|
||||||
|
const data = await this.siteService.get(Number(id), false);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('/list')
|
||||||
|
async list(@Query() query: QuerySiteDTO) {
|
||||||
|
try {
|
||||||
|
const data = await this.siteService.list(query, false);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量查询改为使用 /site/list?ids=1,2,3
|
||||||
|
|
||||||
|
@Put('/disable/:id')
|
||||||
|
async disable(@Param('id') id: string, @Body() body: DisableSiteDTO) {
|
||||||
|
try {
|
||||||
|
await this.siteService.disable(Number(id), body.disabled);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
import { Body, Controller, Get, Inject, Post, Query } from '@midwayjs/core';
|
||||||
|
import { StatisticsService } from '../service/statistics.service';
|
||||||
|
import { OrderStatisticsParams } from '../dto/statistics.dto';
|
||||||
|
import { errorResponse, successResponse } from '../utils/response.util';
|
||||||
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
||||||
|
|
||||||
|
@Controller('/statistics')
|
||||||
|
export class StatisticsController {
|
||||||
|
@Inject()
|
||||||
|
statisticsService: StatisticsService;
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/order')
|
||||||
|
async getOrderStatistics(@Body() params: OrderStatisticsParams) {
|
||||||
|
try {
|
||||||
|
return successResponse(
|
||||||
|
await this.statisticsService.getOrderStatistics(params)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/orderByDate')
|
||||||
|
async getOrderByDate(@Body('date') date: string) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.statisticsService.getOrderByDate(date));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/orderByEmail')
|
||||||
|
async getOrderByEmail(@Body('email') email: string) {
|
||||||
|
try {
|
||||||
|
return successResponse(
|
||||||
|
await this.statisticsService.getOrderByEmail(email)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/getCustomerOrders')
|
||||||
|
async getCustomerOrders(@Body('month') month) {
|
||||||
|
try {
|
||||||
|
return successResponse(
|
||||||
|
await this.statisticsService.getCustomerOrders(month)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/stockForecast')
|
||||||
|
async stockForecast(@Body() params) {
|
||||||
|
try {
|
||||||
|
return successResponse(
|
||||||
|
await this.statisticsService.stockForecast(params)
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Post('/restocking')
|
||||||
|
async restocking(@Body() params) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.statisticsService.restocking(params));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/orderSource')
|
||||||
|
async getOrderSorce(@Query() params) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.statisticsService.getOrderSorce(params));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/inactiveUsersByMonth')
|
||||||
|
async getInativeUsersByMonth(@Query('month') month: string) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.statisticsService.getInativeUsersByMonth(month));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,273 @@
|
||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
Post,
|
||||||
|
Get,
|
||||||
|
Body,
|
||||||
|
Inject,
|
||||||
|
Del,
|
||||||
|
Param,
|
||||||
|
Query,
|
||||||
|
Put,
|
||||||
|
} from '@midwayjs/core';
|
||||||
|
import { StockService } from '../service/stock.service';
|
||||||
|
import { errorResponse, successResponse } from '../utils/response.util';
|
||||||
|
import {
|
||||||
|
CreatePurchaseOrderDTO,
|
||||||
|
CreateStockPointDTO,
|
||||||
|
QueryPointDTO,
|
||||||
|
QueryPurchaseOrderDTO,
|
||||||
|
QueryStockDTO,
|
||||||
|
QueryStockRecordDTO,
|
||||||
|
UpdatePurchaseOrderDTO,
|
||||||
|
UpdateStockDTO,
|
||||||
|
UpdateStockPointDTO,
|
||||||
|
} from '../dto/stock.dto';
|
||||||
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
||||||
|
import {
|
||||||
|
BooleanRes,
|
||||||
|
PurchaseOrderListRes,
|
||||||
|
StockListRes,
|
||||||
|
StockPointAllRespone,
|
||||||
|
StockPointListRes,
|
||||||
|
StockRecordListRes,
|
||||||
|
} from '../dto/reponse.dto';
|
||||||
|
import { User } from '../decorator/user.decorator';
|
||||||
|
|
||||||
|
@Controller('/stock')
|
||||||
|
export class StockController {
|
||||||
|
@Inject()
|
||||||
|
private readonly stockService: StockService;
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes, description: '创建库存点' })
|
||||||
|
@Post('/stock-point')
|
||||||
|
async createStockPoint(@Body() body: CreateStockPointDTO) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.createStockPoint(body);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取库存列表失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes, description: '创建库存点' })
|
||||||
|
@Put('/stock-point/:id')
|
||||||
|
async updateStockPoint(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Body() body: UpdateStockPointDTO
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.updateStockPoint(id, body);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取库存列表失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: StockPointListRes, description: '获取库存点列表' })
|
||||||
|
@Get('/stock-point')
|
||||||
|
async getStockPoints(@Query() query: QueryPointDTO) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.getStockPoints(query);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取库存列表失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: StockPointAllRespone, description: '获取所有库存' })
|
||||||
|
@Get('/stock-point/all')
|
||||||
|
async getAllStockPoints() {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.getAllStockPoints();
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes, description: '删除库存点' })
|
||||||
|
@Del('/stock-point/:id')
|
||||||
|
async delStockPoints(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
await this.stockService.delStockPoints(id);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '删除库存点失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Post('/purchase-order')
|
||||||
|
async createPurchaseOrder(@Body() body: CreatePurchaseOrderDTO) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.createPurchaseOrder(body);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Put('/purchase-order/:id')
|
||||||
|
async updatePurchaseOrder(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Body() body: UpdatePurchaseOrderDTO
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.updatePurchaseOrder(id, body);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: PurchaseOrderListRes, description: '获取采购列表' })
|
||||||
|
@Get('/purchase-order')
|
||||||
|
async getPurchaseOrders(@Query() query: QueryPurchaseOrderDTO) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.getPurchaseOrders(query);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取库存记录列表失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Del('/purchase-order/:id')
|
||||||
|
async delPurchaseOrder(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.delPurchaseOrder(id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '删除失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Post('/purchase-order/:id')
|
||||||
|
async receivePurchaseOrder(@Param('id') id: number, @User() user) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.receivePurchaseOrder(id, user.id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Get('/purchase-order/:orderNumber')
|
||||||
|
async getPurchaseOrder(@Param('orderNumber') orderNumber: string) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.getPurchaseOrder(orderNumber);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: StockListRes, description: '获取库存列表' })
|
||||||
|
@Get('/')
|
||||||
|
async getStocks(@Query() query: QueryStockDTO) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.getStocks(query);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取库存列表失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
description: '更新库存(入库、出库、调整)',
|
||||||
|
})
|
||||||
|
@Post('/update')
|
||||||
|
async updateStock(@Body() body: UpdateStockDTO) {
|
||||||
|
try {
|
||||||
|
await this.stockService.updateStock(body);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新库存失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: StockRecordListRes, description: '获取库存记录列表' })
|
||||||
|
@Get('/records')
|
||||||
|
async getStockRecords(@Query() query: QueryStockRecordDTO) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.getStockRecords(query);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取库存记录列表失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Post('/transfer')
|
||||||
|
async createTransfer(@Body() body: Record<string, any>, @User() user) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.createTransfer(body, user.id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '创建失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get('/transfer')
|
||||||
|
async getTransfers(@Query() query: Record<string, any>) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.getTransfers(query);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取调拨列表失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Post('/cancelTransfer/:id')
|
||||||
|
async cancelTransfer(@Param('id') id: number, @User() user) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.cancelTransfer(id, user.id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '删除失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Post('/receiveTransfer/:id')
|
||||||
|
async receiveTransfer(@Param('id') id: number, @User() user) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.receiveTransfer(id, user.id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Post('/lostTransfer/:id')
|
||||||
|
async lostTransfer(@Param('id') id: number) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.lostTransfer(id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Put('/receiveTransfer/:id')
|
||||||
|
async updateTransfer(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Body() body: Record<string, any>,
|
||||||
|
@User() user
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const data = await this.stockService.updateTransfer(id, body, user.id);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { Controller, Inject, Param, Post, Get, Query } from '@midwayjs/core';
|
||||||
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
||||||
|
import { SubscriptionService } from '../service/subscription.service';
|
||||||
|
import { errorResponse, successResponse } from '../utils/response.util';
|
||||||
|
import { BooleanRes, SubscriptionListRes } from '../dto/reponse.dto';
|
||||||
|
import { QuerySubscriptionDTO } from '../dto/subscription.dto';
|
||||||
|
|
||||||
|
@Controller('/subscription')
|
||||||
|
export class SubscriptionController {
|
||||||
|
@Inject()
|
||||||
|
subscriptionService: SubscriptionService;
|
||||||
|
|
||||||
|
// 同步订阅:根据站点 ID 拉取并更新本地订阅数据
|
||||||
|
@ApiOkResponse({ type: BooleanRes })
|
||||||
|
@Post('/sync/:siteId')
|
||||||
|
async sync(@Param('siteId') siteId: string) {
|
||||||
|
try {
|
||||||
|
await this.subscriptionService.syncSubscriptions(siteId);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '同步失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订阅列表:分页 + 筛选
|
||||||
|
@ApiOkResponse({ type: SubscriptionListRes })
|
||||||
|
@Get('/list')
|
||||||
|
async list(@Query() query: QuerySubscriptionDTO) {
|
||||||
|
try {
|
||||||
|
const data = await this.subscriptionService.getSubscriptionList(query);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
// src/controller/user.controller.ts
|
||||||
|
import { Controller, Post, Get, Body, Query } from '@midwayjs/core';
|
||||||
|
import { Inject } from '@midwayjs/decorator';
|
||||||
|
import { UserService } from '../service/user.service';
|
||||||
|
import { errorResponse, successResponse } from '../utils/response.util';
|
||||||
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
||||||
|
import { BooleanRes, LoginRes } from '../dto/reponse.dto';
|
||||||
|
import { User } from '../decorator/user.decorator';
|
||||||
|
|
||||||
|
@Controller('/user')
|
||||||
|
export class UserController {
|
||||||
|
@Inject()
|
||||||
|
userService: UserService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
ctx;
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: LoginRes,
|
||||||
|
})
|
||||||
|
@Post('/login')
|
||||||
|
async login(@Body() body) {
|
||||||
|
this.ctx.logger.info('ip:', this.ctx.ip, '; path:', this.ctx.path, '; user:', body?.username);
|
||||||
|
try {
|
||||||
|
const result = await this.userService.login(body);
|
||||||
|
return successResponse(result, '登录成功');
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error?.message || '登录失败', error?.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Post('/logout')
|
||||||
|
async logout() {
|
||||||
|
// 可选:在这里处理服务端缓存的 token 或 session
|
||||||
|
|
||||||
|
return successResponse(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/add')
|
||||||
|
async addUser(@Body() body: { username: string; password: string }) {
|
||||||
|
const { username, password } = body;
|
||||||
|
try {
|
||||||
|
await this.userService.addUser(username, password);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return errorResponse('添加用户失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get('/list')
|
||||||
|
async listUsers(@Query() query: { current: number; pageSize: number }) {
|
||||||
|
const { current = 1, pageSize = 10 } = query;
|
||||||
|
return successResponse(await this.userService.listUsers(current, pageSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/toggleActive')
|
||||||
|
async toggleActive(@Body() body: { userId: number; isActive: boolean }) {
|
||||||
|
return this.userService.toggleUserActive(body.userId, body.isActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse()
|
||||||
|
@Get()
|
||||||
|
async getUser(@User() user) {
|
||||||
|
try {
|
||||||
|
return successResponse(await this.userService.getUser(user.id));
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse('获取失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
import { HttpStatus, Inject } from '@midwayjs/core';
|
||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
Post,
|
||||||
|
Body,
|
||||||
|
Headers,
|
||||||
|
Get,
|
||||||
|
Query,
|
||||||
|
} from '@midwayjs/decorator';
|
||||||
|
import { Context } from '@midwayjs/koa';
|
||||||
|
import * as crypto from 'crypto';
|
||||||
|
import { WpProductService } from '../service/wp_product.service';
|
||||||
|
import { WPService } from '../service/wp.service';
|
||||||
|
import { SiteService } from '../service/site.service';
|
||||||
|
import { OrderService } from '../service/order.service';
|
||||||
|
|
||||||
|
@Controller('/webhook')
|
||||||
|
export class WebhookController {
|
||||||
|
private secret = 'YOONE24kd$kjcdjflddd';
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private readonly wpProductService: WpProductService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private readonly wpApiService: WPService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private readonly orderService: OrderService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
ctx: Context;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private readonly siteService: SiteService;
|
||||||
|
|
||||||
|
// 移除配置中的站点数组,来源统一改为数据库
|
||||||
|
|
||||||
|
@Get('/')
|
||||||
|
async test() {
|
||||||
|
return 'webhook';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post('/woocommerce')
|
||||||
|
async handleWooWebhook(
|
||||||
|
@Body() body: any,
|
||||||
|
@Query('siteId') siteId: string,
|
||||||
|
@Headers() header: any
|
||||||
|
) {
|
||||||
|
const signature = header['x-wc-webhook-signature'];
|
||||||
|
const topic = header['x-wc-webhook-topic'];
|
||||||
|
const source = header['x-wc-webhook-source'];
|
||||||
|
// 从数据库获取站点配置
|
||||||
|
const site = await this.siteService.get(Number(siteId), true);
|
||||||
|
|
||||||
|
if (!site || !source.includes(site.apiUrl)) {
|
||||||
|
console.log('domain not match');
|
||||||
|
return {
|
||||||
|
code: HttpStatus.BAD_REQUEST,
|
||||||
|
success: false,
|
||||||
|
message: 'domain not match',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!signature) {
|
||||||
|
return {
|
||||||
|
code: HttpStatus.BAD_REQUEST,
|
||||||
|
success: false,
|
||||||
|
message: 'Signature missing',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const rawBody = this.ctx.request.rawBody;
|
||||||
|
const hash = crypto
|
||||||
|
.createHmac('sha256', this.secret)
|
||||||
|
.update(rawBody)
|
||||||
|
.digest('base64');
|
||||||
|
try {
|
||||||
|
if (hash === signature) {
|
||||||
|
switch (topic) {
|
||||||
|
case 'product.created':
|
||||||
|
case 'product.updated':
|
||||||
|
// 变体更新
|
||||||
|
if (body.type === 'variation') {
|
||||||
|
const variation = await this.wpApiService.getVariation(
|
||||||
|
site,
|
||||||
|
body.parent_id,
|
||||||
|
body.id
|
||||||
|
);
|
||||||
|
this.wpProductService.syncVariation(
|
||||||
|
siteId,
|
||||||
|
body.parent_id,
|
||||||
|
variation
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const variations =
|
||||||
|
body.type === 'variable'
|
||||||
|
? await this.wpApiService.getVariations(site, body.id)
|
||||||
|
: [];
|
||||||
|
await this.wpProductService.syncProductAndVariations(
|
||||||
|
String(site.id),
|
||||||
|
body,
|
||||||
|
variations
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case 'product.deleted':
|
||||||
|
await this.wpProductService.delWpProduct(String(site.id), body.id);
|
||||||
|
break;
|
||||||
|
case 'order.created':
|
||||||
|
case 'order.updated':
|
||||||
|
await this.orderService.syncSingleOrder(siteId, body);
|
||||||
|
break;
|
||||||
|
case 'order.deleted':
|
||||||
|
break;
|
||||||
|
case 'customer.created':
|
||||||
|
break;
|
||||||
|
case 'customer.updated':
|
||||||
|
break;
|
||||||
|
case 'customer.deleted':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log('Unhandled event:', body.event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: 200,
|
||||||
|
success: true,
|
||||||
|
message: 'Webhook processed successfully',
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
code: 403,
|
||||||
|
success: false,
|
||||||
|
message: 'Webhook verification failed',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,200 @@
|
||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
Param,
|
||||||
|
Post,
|
||||||
|
Inject,
|
||||||
|
Get,
|
||||||
|
Query,
|
||||||
|
Put,
|
||||||
|
Body,
|
||||||
|
} from '@midwayjs/core';
|
||||||
|
import { WpProductService } from '../service/wp_product.service';
|
||||||
|
import { errorResponse, successResponse } from '../utils/response.util';
|
||||||
|
import { ApiOkResponse } from '@midwayjs/swagger';
|
||||||
|
import { BooleanRes, WpProductListRes } from '../dto/reponse.dto';
|
||||||
|
import {
|
||||||
|
QueryWpProductDTO,
|
||||||
|
SetConstitutionDTO,
|
||||||
|
UpdateVariationDTO,
|
||||||
|
UpdateWpProductDTO,
|
||||||
|
} from '../dto/wp_product.dto';
|
||||||
|
import { WPService } from '../service/wp.service';
|
||||||
|
import { SiteService } from '../service/site.service';
|
||||||
|
import {
|
||||||
|
ProductsRes,
|
||||||
|
} from '../dto/reponse.dto';
|
||||||
|
@Controller('/wp_product')
|
||||||
|
export class WpProductController {
|
||||||
|
// 移除控制器内的配置站点引用,统一由服务层处理站点数据
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private readonly wpProductService: WpProductService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private readonly wpApiService: WPService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private readonly siteService: SiteService;
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Post('/sync/:siteId')
|
||||||
|
async syncProducts(@Param('siteId') siteId: string) {
|
||||||
|
try {
|
||||||
|
await this.wpProductService.syncSite(siteId);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return errorResponse('同步失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: WpProductListRes,
|
||||||
|
})
|
||||||
|
@Get('/list')
|
||||||
|
async getWpProducts(@Query() query: QueryWpProductDTO) {
|
||||||
|
try {
|
||||||
|
const data = await this.wpProductService.getProductList(query);
|
||||||
|
return successResponse(data);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Put('/:id/constitution')
|
||||||
|
async setConstitution(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Body()
|
||||||
|
body: SetConstitutionDTO
|
||||||
|
) {
|
||||||
|
const { isProduct, constitution } = body;
|
||||||
|
try {
|
||||||
|
await this.wpProductService.setConstitution(id, isProduct, constitution);
|
||||||
|
return successResponse(true);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes
|
||||||
|
})
|
||||||
|
@Post('/updateState/:id')
|
||||||
|
async updateWPProductState(
|
||||||
|
@Param('id') id: number,
|
||||||
|
@Body() body: any, // todo
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const res = await this.wpProductService.updateProductStatus(id, body?.status, body?.stock_status);
|
||||||
|
return successResponse(res);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新产品接口
|
||||||
|
* @param productId 产品 ID
|
||||||
|
* @param body 更新数据
|
||||||
|
*/
|
||||||
|
@ApiOkResponse({
|
||||||
|
type: BooleanRes,
|
||||||
|
})
|
||||||
|
@Put('/siteId/:siteId/products/:productId')
|
||||||
|
async updateProduct(
|
||||||
|
@Param('siteId') siteId: string,
|
||||||
|
@Param('productId') productId: string,
|
||||||
|
@Body() body: UpdateWpProductDTO
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const isDuplicate = await this.wpProductService.isSkuDuplicate(
|
||||||
|
body.sku,
|
||||||
|
siteId,
|
||||||
|
productId
|
||||||
|
);
|
||||||
|
if (isDuplicate) {
|
||||||
|
return errorResponse('SKU已存在');
|
||||||
|
}
|
||||||
|
const site = await this.siteService.get(Number(siteId), true);
|
||||||
|
const result = await this.wpApiService.updateProduct(
|
||||||
|
site,
|
||||||
|
productId,
|
||||||
|
body
|
||||||
|
);
|
||||||
|
if (result) {
|
||||||
|
this.wpProductService.updateWpProduct(siteId, productId, body);
|
||||||
|
return successResponse(result, '产品更新成功');
|
||||||
|
}
|
||||||
|
return errorResponse('产品更新失败');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新产品失败:', error);
|
||||||
|
return errorResponse(error.message || '产品更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新变体接口
|
||||||
|
* @param productId 产品 ID
|
||||||
|
* @param variationId 变体 ID
|
||||||
|
* @param body 更新数据
|
||||||
|
*/
|
||||||
|
@Put('/siteId/:siteId/products/:productId/variations/:variationId')
|
||||||
|
async updateVariation(
|
||||||
|
@Param('siteId') siteId: string,
|
||||||
|
@Param('productId') productId: string,
|
||||||
|
@Param('variationId') variationId: string,
|
||||||
|
@Body() body: UpdateVariationDTO
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const isDuplicate = await this.wpProductService.isSkuDuplicate(
|
||||||
|
body.sku,
|
||||||
|
siteId,
|
||||||
|
productId,
|
||||||
|
variationId
|
||||||
|
);
|
||||||
|
if (isDuplicate) {
|
||||||
|
return errorResponse('SKU已存在');
|
||||||
|
}
|
||||||
|
const site = await this.siteService.get(Number(siteId), true);
|
||||||
|
const result = await this.wpApiService.updateVariation(
|
||||||
|
site,
|
||||||
|
productId,
|
||||||
|
variationId,
|
||||||
|
body
|
||||||
|
);
|
||||||
|
if (result) {
|
||||||
|
this.wpProductService.updateWpProductVaritation(
|
||||||
|
siteId,
|
||||||
|
productId,
|
||||||
|
variationId,
|
||||||
|
body
|
||||||
|
);
|
||||||
|
return successResponse(result, '产品变体更新成功');
|
||||||
|
}
|
||||||
|
return errorResponse('变体更新失败');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('更新变体失败:', error);
|
||||||
|
return errorResponse(error.message || '产品变体更新失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOkResponse({
|
||||||
|
description: '通过name搜索产品/订单',
|
||||||
|
type: ProductsRes,
|
||||||
|
})
|
||||||
|
@Get('/search')
|
||||||
|
async searchProducts(@Query('name') name: string) {
|
||||||
|
try {
|
||||||
|
// 调用服务获取产品数据
|
||||||
|
const products = await this.wpProductService.findProductsByName(name);
|
||||||
|
return successResponse(products);
|
||||||
|
} catch (error) {
|
||||||
|
return errorResponse(error.message || '获取数据失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { createCustomParamDecorator } from '@midwayjs/core';
|
||||||
|
|
||||||
|
export const USER_KEY = 'USER_KEY';
|
||||||
|
|
||||||
|
// 定义装饰器
|
||||||
|
export function User(): ParameterDecorator {
|
||||||
|
return createCustomParamDecorator(USER_KEY, {});
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
|
||||||
|
export class QueryCustomerListDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
current: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
pageSize: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
tags: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
sorterKey: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
sorterValue: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
state: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
first_purchase_date: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
customerId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
phone: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CustomerTagDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
tag: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,306 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
|
|
||||||
|
// 定义包装类型的联合类型
|
||||||
|
export type PackagingType =
|
||||||
|
// | PackagingPallet
|
||||||
|
PackagingPackage;
|
||||||
|
// | PackagingCourierPak
|
||||||
|
// | PackagingEnvelope;
|
||||||
|
|
||||||
|
// 定义包装类型的枚举,用于 API 文档描述
|
||||||
|
export enum PackagingTypeEnum {
|
||||||
|
Pallet = 'pallet',
|
||||||
|
Package = 'package',
|
||||||
|
CourierPak = 'courier-pak',
|
||||||
|
Envelope = 'envelope',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Address {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
address_line_1: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
city: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
region: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
country: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
postal_code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PhoneNumber {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
number: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
extension: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Location {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Address })
|
||||||
|
@Rule(RuleType.object<Address>())
|
||||||
|
address: Address;
|
||||||
|
|
||||||
|
@ApiProperty({ type: PhoneNumber })
|
||||||
|
@Rule(RuleType.object<PhoneNumber>())
|
||||||
|
phone_number: PhoneNumber;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.array<string>())
|
||||||
|
email_addresses: string[];
|
||||||
|
|
||||||
|
contact_name?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Time {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
hour: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
minute: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum SignatureRequirementEnum {
|
||||||
|
NOTREQUIRED = 'not-required',
|
||||||
|
REQUIRED = 'required',
|
||||||
|
ADULTREQUIRED = 'adult-required',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Destination extends Location {
|
||||||
|
@ApiProperty({ type: Time })
|
||||||
|
@Rule(RuleType.object<Time>())
|
||||||
|
ready_at: Time;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Time })
|
||||||
|
@Rule(RuleType.object<Time>())
|
||||||
|
ready_until: Time;
|
||||||
|
|
||||||
|
@ApiProperty({ type: SignatureRequirementEnum })
|
||||||
|
@Rule(RuleType.string().valid(...Object.values(SignatureRequirementEnum)))
|
||||||
|
SignatureRequirementEnum: SignatureRequirementEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Date {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
year: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
month: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
day: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum UnitEnum {
|
||||||
|
KG = 'kg',
|
||||||
|
LB = 'lb',
|
||||||
|
G = 'g',
|
||||||
|
OZ = 'oz',
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Cubid {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
w: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
h: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
l: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
unit: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Weight {
|
||||||
|
@ApiProperty({ enum: UnitEnum })
|
||||||
|
@Rule(RuleType.string().valid(...Object.values(UnitEnum)))
|
||||||
|
unit: UnitEnum;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Measurements {
|
||||||
|
@ApiProperty({ type: Cubid })
|
||||||
|
cuboid: Cubid;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Cubid })
|
||||||
|
weight: Weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Pallets {
|
||||||
|
@ApiProperty({ type: Measurements })
|
||||||
|
@Rule(RuleType.object<Measurements>())
|
||||||
|
measurements: Measurements;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
freight_class: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PackagingPallet {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
pallet_type: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Pallets })
|
||||||
|
@Rule(RuleType.object<Pallets>())
|
||||||
|
pallets: Pallets;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Package {
|
||||||
|
@ApiProperty({ type: Measurements })
|
||||||
|
@Rule(RuleType.object<Measurements>())
|
||||||
|
measurements: Measurements;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PackagingPackage {
|
||||||
|
@ApiProperty({ type: Package, isArray: true })
|
||||||
|
@Rule(RuleType.array<Package>())
|
||||||
|
packages: Package[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PackagingCourierPak {
|
||||||
|
@ApiProperty({ type: Package, isArray: true })
|
||||||
|
@Rule(RuleType.array<Package>())
|
||||||
|
courier_paks: Package[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PackagingEnvelope {
|
||||||
|
// 添加必要的属性和装饰器
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.boolean())
|
||||||
|
includes_return_label?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
// export enum InsuranceTypeEnum {
|
||||||
|
// INTERNAL = 'internal',
|
||||||
|
// CARRIER = 'carrier',
|
||||||
|
// }
|
||||||
|
// export class Insurance {
|
||||||
|
// @ApiProperty({ enum: InsuranceTypeEnum })
|
||||||
|
// @Rule(RuleType.string().valid(...Object.values(InsuranceTypeEnum)))
|
||||||
|
// type: InsuranceTypeEnum;
|
||||||
|
// }
|
||||||
|
|
||||||
|
export class ShippingDetailsDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
shipmentFee: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Location })
|
||||||
|
@Rule(RuleType.object<Location>())
|
||||||
|
origin: Location;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Destination })
|
||||||
|
@Rule(RuleType.object<Destination>())
|
||||||
|
destination: Destination;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Date })
|
||||||
|
@Rule(RuleType.object<Date>())
|
||||||
|
expected_ship_date: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: PackagingTypeEnum })
|
||||||
|
@Rule(RuleType.string().valid(...Object.values(PackagingTypeEnum)))
|
||||||
|
packaging_type: PackagingTypeEnum;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
type: () => [
|
||||||
|
// PackagingPallet,
|
||||||
|
PackagingPackage,
|
||||||
|
// PackagingCourierPak,
|
||||||
|
// PackagingEnvelope,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
@Rule(RuleType.object<PackagingType>())
|
||||||
|
packaging_properties: PackagingType;
|
||||||
|
|
||||||
|
// @ApiProperty({ type: Insurance })
|
||||||
|
// @Rule(RuleType.object<Insurance>())
|
||||||
|
// insurance?: Insurance;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
reference_codes: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Money {
|
||||||
|
@ApiProperty()
|
||||||
|
currency: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Surcharges {
|
||||||
|
@ApiProperty()
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Money })
|
||||||
|
amount: Money;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RateDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
carrier_name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
service_name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
service_id: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Date })
|
||||||
|
valid_until: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Money })
|
||||||
|
total: Money;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Money })
|
||||||
|
base: Money;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Surcharges, isArray: true })
|
||||||
|
surcharges: Surcharges[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: Money, isArray: true })
|
||||||
|
taxes: Money[];
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
transit_time_days: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
transit_time_not_available: boolean;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { ShippingDetailsDTO } from './freightcom.dto';
|
||||||
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
|
import { OrderSale } from '../entity/order_sale.entity';
|
||||||
|
|
||||||
|
export class ShipmentBookDTO {
|
||||||
|
@ApiProperty({ type: OrderSale, isArray: true })
|
||||||
|
@Rule(RuleType.array<OrderSale>())
|
||||||
|
sales: OrderSale[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: ShippingDetailsDTO })
|
||||||
|
@Rule(RuleType.object<ShippingDetailsDTO>())
|
||||||
|
details: ShippingDetailsDTO;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
stockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'number', isArray: true })
|
||||||
|
@Rule(RuleType.array<number>().default([]))
|
||||||
|
orderIds?: number[];
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
shipmentPlatform: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.any())
|
||||||
|
courierCompany: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ShipmentFeeBookDTO {
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
shipmentPlatform: string;
|
||||||
|
@ApiProperty()
|
||||||
|
courierCompany: string;
|
||||||
|
@ApiProperty()
|
||||||
|
stockPointId: number;
|
||||||
|
@ApiProperty()
|
||||||
|
sender: string;
|
||||||
|
@ApiProperty()
|
||||||
|
startPhone: string|any;
|
||||||
|
@ApiProperty()
|
||||||
|
startPostalCode: string;
|
||||||
|
@ApiProperty()
|
||||||
|
pickupAddress: string;
|
||||||
|
// pickupWarehouse: number; // 此处用 stockPointId 到后端解析
|
||||||
|
@ApiProperty()
|
||||||
|
shipperCountryCode: string;
|
||||||
|
@ApiProperty()
|
||||||
|
receiver: string;
|
||||||
|
@ApiProperty()
|
||||||
|
city: string;
|
||||||
|
@ApiProperty()
|
||||||
|
province: string;
|
||||||
|
@ApiProperty()
|
||||||
|
country: string;
|
||||||
|
@ApiProperty()
|
||||||
|
postalCode: string;
|
||||||
|
@ApiProperty()
|
||||||
|
deliveryAddress: string;
|
||||||
|
@ApiProperty()
|
||||||
|
receiverPhone: string;
|
||||||
|
@ApiProperty()
|
||||||
|
receiverEmail: string;
|
||||||
|
@ApiProperty()
|
||||||
|
length: number;
|
||||||
|
@ApiProperty()
|
||||||
|
width: number;
|
||||||
|
@ApiProperty()
|
||||||
|
height: number;
|
||||||
|
@ApiProperty()
|
||||||
|
dimensionUom: string;
|
||||||
|
@ApiProperty()
|
||||||
|
weight: number;
|
||||||
|
@ApiProperty()
|
||||||
|
weightUom: string;
|
||||||
|
@ApiProperty()
|
||||||
|
address_id: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PaymentMethodDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
export class QueryServiceDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
carrier_name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.bool())
|
||||||
|
isActive: boolean;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,181 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { ErpOrderStatus } from '../enums/base.enum';
|
||||||
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
|
// import { Shipment } from '../entity/shipment.entity';
|
||||||
|
// import { ShipmentItem } from '../entity/shipment_item.entity';
|
||||||
|
|
||||||
|
export class OrderAddress {
|
||||||
|
@ApiProperty()
|
||||||
|
first_name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
last_name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
company: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
address_1: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
address_2: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
city: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
state: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
postcode: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
country: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
phone: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OrderStatusCountDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
status: ErpOrderStatus;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class QueryOrderDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
externalOrderId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
siteId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
customer_email: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
billing_phone: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string().allow(null))
|
||||||
|
keyword: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date())
|
||||||
|
startDate: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date())
|
||||||
|
endDate: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'enum', enum: ErpOrderStatus })
|
||||||
|
@Rule(RuleType.string().valid(...Object.values(ErpOrderStatus)))
|
||||||
|
status: ErpOrderStatus;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
payment_method: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '仅订阅订单(父订阅订单或包含订阅商品)' })
|
||||||
|
@Rule(RuleType.bool().default(false))
|
||||||
|
isSubscriptionOnly?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class QueryOrderSalesDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.bool().default(false))
|
||||||
|
isSource: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.bool().default(false))
|
||||||
|
exceptPackage: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
siteId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date())
|
||||||
|
startDate: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date())
|
||||||
|
endDate: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
// export class Tracking extends Shipment {
|
||||||
|
// @ApiProperty({ type: ShipmentItem, isArray: true })
|
||||||
|
// products?: ShipmentItem[];
|
||||||
|
// }
|
||||||
|
|
||||||
|
export class CreateOrderNoteDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
orderId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
content: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class QueryOrderItemDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
siteId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
name: string; // 商品名称关键字
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
externalProductId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
externalVariationId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date())
|
||||||
|
startDate: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date())
|
||||||
|
endDate: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,174 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO 用于创建产品
|
||||||
|
*/
|
||||||
|
export class CreateProductDTO {
|
||||||
|
@ApiProperty({
|
||||||
|
example: 'ZYN 6MG WINTERGREEN',
|
||||||
|
description: '产品名称',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Rule(RuleType.string().required().empty({ message: '产品名称不能为空' }))
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '产品描述', description: '产品描述' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '1', description: '分类 ID' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
categoryId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
strengthId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
flavorsId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
humidity: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO 用于更新产品
|
||||||
|
*/
|
||||||
|
export class UpdateProductDTO extends CreateProductDTO {
|
||||||
|
@ApiProperty({ example: 'ZYN 6MG WINTERGREEN', description: '产品名称' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO 用于分页查询产品
|
||||||
|
*/
|
||||||
|
export class QueryProductDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number;
|
||||||
|
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '关键字' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '1', description: '分类 ID' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
categoryId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO 用于创建分类
|
||||||
|
*/
|
||||||
|
export class CreateCategoryDTO {
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '分类名称', required: true })
|
||||||
|
@Rule(RuleType.string().required().empty({ message: '分类名称不能为空' }))
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@Rule(RuleType.string().required().empty({ message: 'key不能为空' }))
|
||||||
|
unique_key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO 用于更新分类
|
||||||
|
*/
|
||||||
|
export class UpdateCategoryDTO {
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '分类名称' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DTO 用于查询分类(支持分页)
|
||||||
|
*/
|
||||||
|
export class QueryCategoryDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number; // 页码
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number; // 每页大小
|
||||||
|
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '关键字' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string; // 搜索关键字(支持模糊查询)
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateFlavorsDTO {
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '分类名称', required: true })
|
||||||
|
@Rule(RuleType.string().required().empty({ message: '分类名称不能为空' }))
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@Rule(RuleType.string().required().empty({ message: 'key不能为空' }))
|
||||||
|
unique_key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateFlavorsDTO {
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '分类名称' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class QueryFlavorsDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number; // 页码
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number; // 每页大小
|
||||||
|
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '关键字' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string; // 搜索关键字(支持模糊查询)
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateStrengthDTO {
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '分类名称', required: true })
|
||||||
|
@Rule(RuleType.string().required().empty({ message: '分类名称不能为空' }))
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@Rule(RuleType.string().required().empty({ message: 'key不能为空' }))
|
||||||
|
unique_key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateStrengthDTO {
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '分类名称' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class QueryStrengthDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number; // 页码
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number; // 每页大小
|
||||||
|
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '关键字' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string; // 搜索关键字(支持模糊查询)
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SkuItemDTO {
|
||||||
|
@ApiProperty({ description: '产品 ID' })
|
||||||
|
productId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'sku 编码' })
|
||||||
|
sku: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BatchSetSkuDTO {
|
||||||
|
@ApiProperty({ description: 'sku 数据列表', type: [SkuItemDTO] })
|
||||||
|
skus: SkuItemDTO[];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Category } from '../entity/category.entity';
|
||||||
|
import { Order } from '../entity/order.entity';
|
||||||
|
import { Product } from '../entity/product.entity';
|
||||||
|
import { StockPoint } from '../entity/stock_point.entity';
|
||||||
|
import { PaginatedWrapper } from '../utils/paginated-response.util';
|
||||||
|
import {
|
||||||
|
SuccessArrayWrapper,
|
||||||
|
SuccessWrapper,
|
||||||
|
} from '../utils/response-wrapper.util';
|
||||||
|
import { OrderStatusCountDTO } from './order.dto';
|
||||||
|
import { SiteConfig } from './site.dto';
|
||||||
|
import { PurchaseOrderDTO, StockDTO, StockRecordDTO } from './stock.dto';
|
||||||
|
import { LoginResDTO } from './user.dto';
|
||||||
|
import { WpProductDTO } from './wp_product.dto';
|
||||||
|
import { OrderSale } from '../entity/order_sale.entity';
|
||||||
|
import { Service } from '../entity/service.entity';
|
||||||
|
import { RateDTO } from './freightcom.dto';
|
||||||
|
import { ShippingAddress } from '../entity/shipping_address.entity';
|
||||||
|
import { OrderItem } from '../entity/order_item.entity';
|
||||||
|
import { OrderRefundItem } from '../entity/order_retund_item.entity';
|
||||||
|
import { OrderNote } from '../entity/order_note.entity';
|
||||||
|
import { PaymentMethodDTO } from './logistics.dto';
|
||||||
|
import { Flavors } from '../entity/flavors.entity';
|
||||||
|
import { Strength } from '../entity/strength.entity';
|
||||||
|
import { Subscription } from '../entity/subscription.entity';
|
||||||
|
|
||||||
|
export class BooleanRes extends SuccessWrapper(Boolean) {}
|
||||||
|
//网站配置返回数据
|
||||||
|
export class WpSitesResponse extends SuccessArrayWrapper(SiteConfig) {}
|
||||||
|
//产品分页数据
|
||||||
|
export class ProductPaginatedResponse extends PaginatedWrapper(Product) {}
|
||||||
|
//产品分页返回数据
|
||||||
|
export class ProductListRes extends SuccessWrapper(ProductPaginatedResponse) {}
|
||||||
|
//产品返回数据
|
||||||
|
export class ProductRes extends SuccessWrapper(Product) {}
|
||||||
|
export class ProductsRes extends SuccessArrayWrapper(Product) {}
|
||||||
|
//产品分类返分页数据
|
||||||
|
export class CategoryPaginatedResponse extends PaginatedWrapper(Category) {}
|
||||||
|
export class FlavorsPaginatedResponse extends PaginatedWrapper(Flavors) {}
|
||||||
|
export class StrengthPaginatedResponse extends PaginatedWrapper(Strength) {}
|
||||||
|
//产品分类返分页返回数据
|
||||||
|
export class ProductCatListRes extends SuccessWrapper(
|
||||||
|
CategoryPaginatedResponse
|
||||||
|
) {}
|
||||||
|
//产品分类返所有数据
|
||||||
|
export class ProductCatAllRes extends SuccessArrayWrapper(Category) {}
|
||||||
|
//产品分类返回数据
|
||||||
|
export class ProductCatRes extends SuccessWrapper(Category) {}
|
||||||
|
|
||||||
|
//产品分页数据
|
||||||
|
export class WpProductPaginatedResponse extends PaginatedWrapper(
|
||||||
|
WpProductDTO
|
||||||
|
) {}
|
||||||
|
//产品分页返回数据
|
||||||
|
export class WpProductListRes extends SuccessWrapper(
|
||||||
|
WpProductPaginatedResponse
|
||||||
|
) {}
|
||||||
|
|
||||||
|
export class LoginRes extends SuccessWrapper(LoginResDTO) {}
|
||||||
|
export class StockPaginatedRespone extends PaginatedWrapper(StockDTO) {}
|
||||||
|
export class StockListRes extends SuccessWrapper(StockPaginatedRespone) {}
|
||||||
|
export class StockRecordPaginatedRespone extends PaginatedWrapper(
|
||||||
|
StockRecordDTO
|
||||||
|
) {}
|
||||||
|
export class StockRecordListRes extends SuccessWrapper(
|
||||||
|
StockRecordPaginatedRespone
|
||||||
|
) {}
|
||||||
|
export class StockPointAllRespone extends SuccessArrayWrapper(StockPoint) {}
|
||||||
|
export class StockPointPaginatedRespone extends PaginatedWrapper(StockPoint) {}
|
||||||
|
export class StockPointListRes extends SuccessWrapper(
|
||||||
|
StockPointPaginatedRespone
|
||||||
|
) {}
|
||||||
|
export class PurchaseOrderPaginatedRespone extends PaginatedWrapper(
|
||||||
|
PurchaseOrderDTO
|
||||||
|
) {}
|
||||||
|
export class PurchaseOrderListRes extends SuccessWrapper(
|
||||||
|
PurchaseOrderPaginatedRespone
|
||||||
|
) {}
|
||||||
|
export class OrderStatusCountRes extends SuccessArrayWrapper(
|
||||||
|
OrderStatusCountDTO
|
||||||
|
) {}
|
||||||
|
export class OrderPaginatedRespone extends PaginatedWrapper(Order) {
|
||||||
|
@ApiProperty({ type: OrderStatusCountDTO, isArray: true })
|
||||||
|
count: OrderStatusCountDTO;
|
||||||
|
}
|
||||||
|
export class OrderListRes extends SuccessWrapper(OrderPaginatedRespone) {}
|
||||||
|
export class OrderSaleDTO extends OrderSale {
|
||||||
|
@ApiProperty()
|
||||||
|
totalQuantity: number;
|
||||||
|
}
|
||||||
|
export class OrderSalePaginatedRespone extends PaginatedWrapper(OrderSaleDTO) {}
|
||||||
|
export class OrderSaleListRes extends SuccessWrapper(
|
||||||
|
OrderSalePaginatedRespone
|
||||||
|
) {}
|
||||||
|
export class ServiceListRes extends SuccessArrayWrapper(Service) {}
|
||||||
|
export class RateLitRes extends SuccessArrayWrapper(RateDTO) {}
|
||||||
|
export class ShippingAddressListRes extends SuccessArrayWrapper(
|
||||||
|
ShippingAddress
|
||||||
|
) {}
|
||||||
|
export class OrderDetail extends Order {
|
||||||
|
@ApiProperty({ type: OrderItem, isArray: true })
|
||||||
|
items: OrderItem[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: OrderSale, isArray: true })
|
||||||
|
sales: OrderSale[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: OrderRefundItem, isArray: true })
|
||||||
|
refundItems: OrderRefundItem[];
|
||||||
|
|
||||||
|
// @ApiProperty({ type: Tracking, isArray: true })
|
||||||
|
// trackings: Tracking[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: OrderNote, isArray: true })
|
||||||
|
notes: OrderNote[];
|
||||||
|
}
|
||||||
|
export class OrderDetailRes extends SuccessWrapper(OrderDetail) {}
|
||||||
|
export class PaymentMethodListRes extends SuccessArrayWrapper(
|
||||||
|
PaymentMethodDTO
|
||||||
|
) {}
|
||||||
|
|
||||||
|
// 订阅分页数据(列表 + 总数等分页信息)
|
||||||
|
export class SubscriptionPaginatedResponse extends PaginatedWrapper(Subscription) {}
|
||||||
|
// 订阅分页返回数据(统一成功包装)
|
||||||
|
export class SubscriptionListRes extends SuccessWrapper(SubscriptionPaginatedResponse) {}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
|
|
||||||
|
export class SiteConfig {
|
||||||
|
@ApiProperty({ example: '1', description: '站点 ID' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '站点 URL' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
apiUrl: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '站点 rest key' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
consumerKey: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '站点 rest 秘钥' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
consumerSecret: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '站点名' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
siteName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '平台类型', enum: ['woocommerce', 'shopyy'] })
|
||||||
|
@Rule(RuleType.string().valid('woocommerce', 'shopyy'))
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'SKU 前缀' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
skuPrefix: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateSiteDTO {
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
apiUrl?: string;
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
consumerKey?: string;
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
consumerSecret?: string;
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
siteName: string;
|
||||||
|
@Rule(RuleType.string().valid('woocommerce', 'shopyy').optional())
|
||||||
|
type?: string;
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
skuPrefix?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateSiteDTO {
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
apiUrl?: string;
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
consumerKey?: string;
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
consumerSecret?: string;
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
siteName?: string;
|
||||||
|
@Rule(RuleType.boolean().optional())
|
||||||
|
isDisabled?: boolean;
|
||||||
|
@Rule(RuleType.string().valid('woocommerce', 'shopyy').optional())
|
||||||
|
type?: string;
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
skuPrefix?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class QuerySiteDTO {
|
||||||
|
@Rule(RuleType.number().optional())
|
||||||
|
current?: number;
|
||||||
|
@Rule(RuleType.number().optional())
|
||||||
|
pageSize?: number;
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
keyword?: string;
|
||||||
|
@Rule(RuleType.boolean().optional())
|
||||||
|
isDisabled?: boolean;
|
||||||
|
@Rule(RuleType.string().optional())
|
||||||
|
ids?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DisableSiteDTO {
|
||||||
|
@Rule(RuleType.boolean())
|
||||||
|
disabled: boolean;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
|
import dayjs = require('dayjs');
|
||||||
|
|
||||||
|
export class OrderStatisticsParams {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date().default(dayjs().subtract(1, 'month')))
|
||||||
|
startDate: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date().default(dayjs().subtract(1, 'month')))
|
||||||
|
endDate: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string().allow(null))
|
||||||
|
keyword?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number().allow(null))
|
||||||
|
siteId?: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
enum: ['all', 'first_purchase', 'repeat_purchase'],
|
||||||
|
default: 'all',
|
||||||
|
})
|
||||||
|
@Rule(RuleType.string().valid('all', 'first_purchase', 'repeat_purchase'))
|
||||||
|
purchaseType: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ['all', 'cpc', 'non_cpc'], default: 'all' })
|
||||||
|
@Rule(RuleType.string().valid('all', 'cpc', 'non_cpc'))
|
||||||
|
orderType: string;
|
||||||
|
|
||||||
|
@ApiProperty({ enum: ['all', 'zyn', 'yoone', 'zolt'], default: 'all' })
|
||||||
|
@Rule(RuleType.string().valid('all', 'zyn', 'yoone', 'zolt'))
|
||||||
|
brand: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,185 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
|
import { Stock } from '../entity/stock.entity';
|
||||||
|
import {
|
||||||
|
PurchaseOrderStatus,
|
||||||
|
StockRecordOperationType,
|
||||||
|
} from '../enums/base.enum';
|
||||||
|
import { PurchaseOrderItem } from '../entity/purchase_order_item.entity';
|
||||||
|
import { PurchaseOrder } from '../entity/purchase_order.entity';
|
||||||
|
import { StockRecord } from '../entity/stock_record.entity';
|
||||||
|
|
||||||
|
export class QueryStockDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number; // 页码
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number; // 每页大小
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
productName: string;
|
||||||
|
}
|
||||||
|
export class QueryPointDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number; // 页码
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number; // 每页大小
|
||||||
|
}
|
||||||
|
export class QueryStockRecordDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number; // 页码
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number; // 每页大小
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
stockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
productSku: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
productName: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
operationType: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date())
|
||||||
|
startDate: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date())
|
||||||
|
endDate: Date;
|
||||||
|
}
|
||||||
|
export class QueryPurchaseOrderDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number; // 页码
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number; // 每页大小
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
orderNumber?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
stockPointId?: number;
|
||||||
|
}
|
||||||
|
export class StockDTO extends Stock {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
productName: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
id: { type: 'number' },
|
||||||
|
name: { type: 'string' },
|
||||||
|
quantity: { type: 'number' },
|
||||||
|
},
|
||||||
|
isArray: true,
|
||||||
|
})
|
||||||
|
@Rule(RuleType.array())
|
||||||
|
stockPoint: Array<{
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
quantity: number;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
export class StockRecordDTO extends StockRecord {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
productName: string;
|
||||||
|
}
|
||||||
|
export class PurchaseOrderDTO extends PurchaseOrder {
|
||||||
|
@ApiProperty({ type: PurchaseOrderItem, isArray: true })
|
||||||
|
@Rule(RuleType.array())
|
||||||
|
items: PurchaseOrderItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateStockDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
stockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
productSku: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
quantityChange: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'enum', enum: StockRecordOperationType })
|
||||||
|
@Rule(RuleType.string().valid(...Object.values(StockRecordOperationType)))
|
||||||
|
operationType: StockRecordOperationType;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
operatorId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
note: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateStockPointDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
location: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
contactPerson: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
contactPhone: string;
|
||||||
|
}
|
||||||
|
export class UpdateStockPointDTO extends CreateStockPointDTO {}
|
||||||
|
|
||||||
|
export class CreatePurchaseOrderDTO {
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
stockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.date())
|
||||||
|
expectedArrivalTime: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'enum', enum: PurchaseOrderStatus })
|
||||||
|
@Rule(RuleType.string().valid(...Object.values(PurchaseOrderStatus)))
|
||||||
|
status: PurchaseOrderStatus;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
note?: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
type: PurchaseOrderItem,
|
||||||
|
isArray: true,
|
||||||
|
})
|
||||||
|
@Rule(RuleType.array())
|
||||||
|
items: PurchaseOrderItem[];
|
||||||
|
}
|
||||||
|
export class UpdatePurchaseOrderDTO extends CreatePurchaseOrderDTO {}
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
|
import { SubscriptionStatus } from '../enums/base.enum';
|
||||||
|
|
||||||
|
// 订阅列表查询参数(分页与筛选)
|
||||||
|
export class QuerySubscriptionDTO {
|
||||||
|
// 当前页码(从 1 开始)
|
||||||
|
@ApiProperty({ example: 1, description: '页码' })
|
||||||
|
@Rule(RuleType.number().default(1))
|
||||||
|
current: number;
|
||||||
|
|
||||||
|
// 每页数量
|
||||||
|
@ApiProperty({ example: 10, description: '每页大小' })
|
||||||
|
@Rule(RuleType.number().default(10))
|
||||||
|
pageSize: number;
|
||||||
|
|
||||||
|
// 站点 ID(可选)
|
||||||
|
@ApiProperty({ description: '站点ID' })
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
siteId: string;
|
||||||
|
|
||||||
|
// 订阅状态筛选(可选),支持枚举值
|
||||||
|
@ApiProperty({ description: '订阅状态', enum: SubscriptionStatus })
|
||||||
|
@Rule(RuleType.string().valid(...Object.values(SubscriptionStatus)).allow(''))
|
||||||
|
status: SubscriptionStatus | '';
|
||||||
|
|
||||||
|
// 客户邮箱(模糊匹配,可选)
|
||||||
|
@ApiProperty({ description: '客户邮箱' })
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
customer_email: string;
|
||||||
|
|
||||||
|
// 关键字(订阅ID、邮箱等,模糊匹配,可选)
|
||||||
|
@ApiProperty({ description: '关键字(订阅ID、邮箱等)' })
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
keyword: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
|
|
||||||
|
export class LoginResDTO {
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
token: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
userId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String, isArray: true })
|
||||||
|
permissions: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LoginDTO {
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Variation } from '../entity/variation.entity';
|
||||||
|
import { WpProduct } from '../entity/wp_product.entity';
|
||||||
|
import { Rule, RuleType } from '@midwayjs/validate';
|
||||||
|
import { ProductStatus } from '../enums/base.enum';
|
||||||
|
|
||||||
|
export class VariationDTO extends Variation {}
|
||||||
|
|
||||||
|
export class WpProductDTO extends WpProduct {
|
||||||
|
@ApiProperty({ description: '变体列表', type: VariationDTO, isArray: true })
|
||||||
|
variations?: VariationDTO[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateVariationDTO {
|
||||||
|
@ApiProperty({ description: '产品名称' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'SKU' })
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
sku: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '常规价格', type: Number })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
regular_price: number; // 常规价格
|
||||||
|
|
||||||
|
@ApiProperty({ description: '销售价格', type: Number })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
sale_price: number; // 销售价格
|
||||||
|
|
||||||
|
@ApiProperty({ description: '是否促销中', type: Boolean })
|
||||||
|
@Rule(RuleType.boolean())
|
||||||
|
on_sale: boolean; // 是否促销中
|
||||||
|
}
|
||||||
|
|
||||||
|
export class UpdateWpProductDTO {
|
||||||
|
@ApiProperty({ description: '变体名称' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'SKU' })
|
||||||
|
@Rule(RuleType.string().allow(''))
|
||||||
|
sku: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '常规价格', type: Number })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
regular_price: number; // 常规价格
|
||||||
|
|
||||||
|
@ApiProperty({ description: '销售价格', type: Number })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
sale_price: number; // 销售价格
|
||||||
|
|
||||||
|
@ApiProperty({ description: '是否促销中', type: Boolean })
|
||||||
|
@Rule(RuleType.boolean())
|
||||||
|
on_sale: boolean; // 是否促销中
|
||||||
|
}
|
||||||
|
|
||||||
|
export class QueryWpProductDTO {
|
||||||
|
@ApiProperty({ example: '1', description: '页码' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
current: number;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '10', description: '每页大小' })
|
||||||
|
@Rule(RuleType.number())
|
||||||
|
pageSize: number;
|
||||||
|
|
||||||
|
@ApiProperty({ example: 'ZYN', description: '产品名' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '1', description: '站点ID' })
|
||||||
|
@Rule(RuleType.string())
|
||||||
|
siteId?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '产品状态', enum: ProductStatus })
|
||||||
|
@Rule(RuleType.string().valid(...Object.values(ProductStatus)))
|
||||||
|
status?: ProductStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SetConstitutionDTO {
|
||||||
|
@ApiProperty({ type: Boolean })
|
||||||
|
@Rule(RuleType.boolean())
|
||||||
|
isProduct: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: '构成成分',
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
sku: { type: 'string' },
|
||||||
|
quantity: { type: 'number' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
@Rule(RuleType.array())
|
||||||
|
constitution: { sku: string; quantity: number }[] | null;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { Entity, Column, PrimaryColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('auth_code')
|
||||||
|
export class AuthCode {
|
||||||
|
@PrimaryColumn({ length: 255 })
|
||||||
|
device_id: string;
|
||||||
|
|
||||||
|
@Column({ length: 10 })
|
||||||
|
code: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
expires_at: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
import {
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
Entity,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class Category {
|
||||||
|
@ApiProperty({
|
||||||
|
example: '1',
|
||||||
|
description: '分类 ID',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '分类名称',
|
||||||
|
description: '分类名称',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: '唯一识别key',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
unique_key: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('customer')
|
||||||
|
export class Customer {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column({ unique: true })
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@Column({ default: 0})
|
||||||
|
rate: number;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('customer_tag')
|
||||||
|
export class CustomerTag {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
tag: string;
|
||||||
|
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||||
|
|
||||||
|
@Entity('device_whitelist')
|
||||||
|
export class DeviceWhitelist {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column({ name: 'device_id', unique: true })
|
||||||
|
deviceId: string;
|
||||||
|
|
||||||
|
|
||||||
|
@CreateDateColumn({ name: 'created_at' })
|
||||||
|
createdAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
import {
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
Entity,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class Flavors {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: '唯一识别key',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
unique_key: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,290 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import {
|
||||||
|
BeforeInsert,
|
||||||
|
BeforeUpdate,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
OneToOne,
|
||||||
|
JoinColumn
|
||||||
|
} from 'typeorm';
|
||||||
|
import { ErpOrderStatus, OrderStatus } from '../enums/base.enum';
|
||||||
|
import { OrderAddress } from '../dto/order.dto';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import { Shipment } from './shipment.entity';
|
||||||
|
|
||||||
|
@Entity('order')
|
||||||
|
@Exclude()
|
||||||
|
export class Order {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string; // 来源站点唯一标识
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalOrderId: string; // WooCommerce 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty({ type: OrderStatus })
|
||||||
|
@Column({ type: 'enum', enum: OrderStatus })
|
||||||
|
@Expose()
|
||||||
|
status: OrderStatus; // WooCommerce 订单 状态
|
||||||
|
|
||||||
|
@ApiProperty({ type: ErpOrderStatus })
|
||||||
|
@Column({
|
||||||
|
type: 'enum',
|
||||||
|
enum: ErpOrderStatus,
|
||||||
|
default: ErpOrderStatus.PENDING,
|
||||||
|
})
|
||||||
|
@Expose()
|
||||||
|
orderStatus: ErpOrderStatus; // 订单状态
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ name: 'shipment_id', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
shipmentId: number;
|
||||||
|
|
||||||
|
@OneToOne(() => Shipment)
|
||||||
|
@JoinColumn({ name: 'shipment_id' })
|
||||||
|
shipment: Shipment;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
currency: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
currency_symbol: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
prices_include_tax: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'timestamp', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
date_created: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'timestamp', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
date_modified: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, default: 0 })
|
||||||
|
@Expose()
|
||||||
|
discount_total: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, default: 0 })
|
||||||
|
@Expose()
|
||||||
|
discount_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, default: 0 })
|
||||||
|
@Expose()
|
||||||
|
shipping_total: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, default: 0 })
|
||||||
|
@Expose()
|
||||||
|
shipping_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, default: 0 })
|
||||||
|
@Expose()
|
||||||
|
cart_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, default: 0 })
|
||||||
|
@Expose()
|
||||||
|
total: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, default: 0 })
|
||||||
|
@Expose()
|
||||||
|
total_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: 0 })
|
||||||
|
@Expose()
|
||||||
|
customer_id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
customer_email: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
order_key: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: OrderAddress })
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
billing: OrderAddress;
|
||||||
|
|
||||||
|
@ApiProperty({ type: OrderAddress })
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
shipping: OrderAddress;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
payment_method: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
payment_method_title: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
transaction_id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
customer_ip_address: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({
|
||||||
|
type: 'varchar',
|
||||||
|
length: 1024,
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
@Expose()
|
||||||
|
customer_user_agent: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
created_via: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({
|
||||||
|
type: 'mediumtext', // 设置字段类型为 MEDIUMTEXT
|
||||||
|
nullable: true, // 可选:是否允许为 NULL
|
||||||
|
})
|
||||||
|
@Expose()
|
||||||
|
customer_note: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'timestamp', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
date_completed: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'timestamp', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
date_paid: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
cart_hash: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
number: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
meta_data: any[];
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
payment_url: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
is_editable: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
needs_payment: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
needs_processing: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
device_type: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
source_type: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
utm_source: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
is_exchange: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 0, default: 0 })
|
||||||
|
@Expose()
|
||||||
|
exchange_frequency: number;
|
||||||
|
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt: Date;
|
||||||
|
|
||||||
|
// 在插入或更新前处理用户代理字符串
|
||||||
|
@BeforeInsert()
|
||||||
|
@BeforeUpdate()
|
||||||
|
truncateUserAgent() {
|
||||||
|
const maxLength = 1024; // 根据数据库限制的实际长度
|
||||||
|
if (
|
||||||
|
this.customer_user_agent &&
|
||||||
|
this.customer_user_agent.length > maxLength
|
||||||
|
) {
|
||||||
|
this.customer_user_agent = this.customer_user_agent.substring(
|
||||||
|
0,
|
||||||
|
maxLength
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('order_coupon')
|
||||||
|
@Exclude()
|
||||||
|
export class OrderCoupon {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
orderId: number; // 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string; // 来源站点唯一标识
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalOrderId: string; // WooCommerce 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalOrderCouponId: string; // WooCommerce 订单coupon ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
code: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
discount: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
discount_tax: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
discount_type: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
nominal_amount: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
free_shipping: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('order_fee')
|
||||||
|
@Exclude()
|
||||||
|
export class OrderFee {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
orderId: number; // 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalOrderId: string; // WooCommerce 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalOrderFeeId: string; // WooCommerce 订单fee ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
tax_class: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
tax_status: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
amount: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
total: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
total_tax: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt?: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt?: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,151 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('order_item')
|
||||||
|
@Exclude()
|
||||||
|
export class OrderItem {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string; // 来源站点唯一标识
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
orderId: number; // 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalOrderId: string; // WooCommerce 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
externalOrderItemId: string; // WooCommerce 订单item ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalProductId: string; // WooCommerce 产品 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalVariationId: string; // WooCommerce 变体 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
@Expose()
|
||||||
|
subtotal: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
@Expose()
|
||||||
|
subtotal_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
@Expose()
|
||||||
|
total: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
@Expose()
|
||||||
|
total_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
tax_class?: string; // 税类(来自 line_items.tax_class)
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
taxes?: any[]; // 税明细(来自 line_items.taxes,数组)
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
meta_data?: any[]; // 行项目元数据(包含订阅相关键值)
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
sku?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
global_unique_id?: string; // 全局唯一ID(部分主题/插件会提供)
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
price: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
image?: { id?: string | number; src?: string }; // 商品图片(对象,包含 id/src)
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
parent_name?: string; // 父商品名称(组合/捆绑时可能使用)
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
bundled_by?: string; // 捆绑来源标识(bundled_by)
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
bundled_item_title?: string; // 捆绑项标题
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
bundled_items?: any[]; // 捆绑项列表(数组)
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
JoinColumn,
|
||||||
|
ManyToOne,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { Order } from './order.entity';
|
||||||
|
|
||||||
|
@Entity('order_sale_original')
|
||||||
|
@Exclude()
|
||||||
|
export class OrderSaleOriginal {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@ManyToOne(() => Order)
|
||||||
|
@JoinColumn({ name: 'order_id' })
|
||||||
|
@Column({ name: 'order_id' })
|
||||||
|
@Expose()
|
||||||
|
orderId: number; // 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string; // 来源站点唯一标识
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
externalOrderItemId: string; // WooCommerce 订单item ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
productId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'sku', type: 'string' })
|
||||||
|
@Expose()
|
||||||
|
@Column()
|
||||||
|
sku: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
isPackage: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt?: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt?: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,113 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
JoinColumn,
|
||||||
|
ManyToOne,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { Order } from './order.entity';
|
||||||
|
|
||||||
|
|
||||||
|
@Entity('order_item_original')
|
||||||
|
@Exclude()
|
||||||
|
export class OrderItemOriginal {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@ManyToOne(() => Order)
|
||||||
|
@JoinColumn({ name: 'order_id' })
|
||||||
|
@Column({ name: 'order_id' })
|
||||||
|
@Expose()
|
||||||
|
orderId: number; // 订单 ID
|
||||||
|
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string; // 来源站点唯一标识
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalOrderId: string; // WooCommerce 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
externalOrderItemId: string; // WooCommerce 订单item ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalProductId: string; // WooCommerce 产品 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalVariationId: string; // WooCommerce 变体 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
@Expose()
|
||||||
|
subtotal: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
@Expose()
|
||||||
|
subtotal_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
@Expose()
|
||||||
|
total: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
@Expose()
|
||||||
|
total_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
sku?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
price: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('order_note')
|
||||||
|
@Exclude()
|
||||||
|
export class OrderNote {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
userId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
orderId: number; // 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
content: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,86 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('order_refund')
|
||||||
|
@Exclude()
|
||||||
|
export class OrderRefund {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
orderId: number; // 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string; // 来源站点唯一标识
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalOrderId: string; // WooCommerce 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalRefundId: string; // WooCommerce refund ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'timestamp' })
|
||||||
|
@Expose()
|
||||||
|
date_created: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
reason: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
refunded_by: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
refunded_payment: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
meta_data: [];
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('order_refund_item')
|
||||||
|
@Exclude()
|
||||||
|
export class OrderRefundItem {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
refundId: number; // 订单 refund ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string; // 来源站点唯一标识
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalRefundId: string; // WooCommerce refund ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalRefundItemId: string; // WooCommerce refund item ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalProductId: string; // WooCommerce 产品 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalVariationId: string; // WooCommerce 变体 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
tax_class: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
subtotal: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
subtotal_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
total: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
total_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
sku?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
price: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt?: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt?: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
BeforeInsert,
|
||||||
|
BeforeUpdate,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('order_sale')
|
||||||
|
@Exclude()
|
||||||
|
export class OrderSale {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
orderId: number; // 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string; // 来源站点唯一标识
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
externalOrderItemId: string; // WooCommerce 订单item ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
productId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'sku', type: 'string' })
|
||||||
|
@Expose()
|
||||||
|
@Column()
|
||||||
|
sku: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
isPackage: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
isYoone: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
isZex: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ nullable: true })
|
||||||
|
@Column({ type: 'int', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
size: number | null;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
isYooneNew: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt?: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt?: Date;
|
||||||
|
|
||||||
|
// === 自动计算逻辑 ===
|
||||||
|
@BeforeInsert()
|
||||||
|
@BeforeUpdate()
|
||||||
|
setFlags() {
|
||||||
|
if (!this.name) return;
|
||||||
|
const lower = this.name.toLowerCase();
|
||||||
|
this.isYoone = lower.includes('yoone');
|
||||||
|
this.isZex = lower.includes('zex');
|
||||||
|
this.isYooneNew = this.isYoone && lower.includes('new');
|
||||||
|
let size: number | null = null;
|
||||||
|
const sizes = [3, 6, 9, 12, 15, 18];
|
||||||
|
for (const s of sizes) {
|
||||||
|
if (lower.includes(s.toString())) {
|
||||||
|
size = s;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('order_shipment')
|
||||||
|
export class OrderShipment {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
order_id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
shipment_id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
stockPointId: number;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('order_shipping')
|
||||||
|
@Exclude()
|
||||||
|
export class OrderShipping {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
orderId: number; // 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalOrderId: string; // WooCommerce 订单 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalOrderShippingId: string; // WooCommerce 订单快递 ID
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
method_title: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
method_id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
instance_id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
total: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2 })
|
||||||
|
@Expose()
|
||||||
|
total_tax: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
import {
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
Entity,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class Product {
|
||||||
|
@ApiProperty({
|
||||||
|
example: '1',
|
||||||
|
description: 'ID',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: 'ZYN 6MG WINTERGREEN',
|
||||||
|
description: '产品名称',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: ''})
|
||||||
|
nameCn: string;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '产品描述', description: '产品描述', type: 'string' })
|
||||||
|
@Column({ nullable: true })
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ example: '1', description: '分类 ID', type: 'number' })
|
||||||
|
@Column()
|
||||||
|
categoryId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
flavorsId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
strengthId: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
humidity: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'sku', type: 'string' })
|
||||||
|
@Column({ nullable: true })
|
||||||
|
sku?: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
// src/entity/PurchaseOrder.ts
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { PurchaseOrderStatus } from '../enums/base.enum';
|
||||||
|
|
||||||
|
@Entity('purchase_order')
|
||||||
|
export class PurchaseOrder {
|
||||||
|
@ApiProperty({ type: 'number' })
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
stockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'string' })
|
||||||
|
@Column()
|
||||||
|
orderNumber: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: PurchaseOrderStatus })
|
||||||
|
@Column({
|
||||||
|
type: 'enum',
|
||||||
|
enum: PurchaseOrderStatus,
|
||||||
|
default: 'draft',
|
||||||
|
})
|
||||||
|
status: PurchaseOrderStatus;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true, type: 'text' })
|
||||||
|
note: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '预计时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column({ type: 'timestamp', nullable: true })
|
||||||
|
expectedArrivalTime: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// src/entity/PurchaseOrderItem.ts
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('purchase_order_item')
|
||||||
|
export class PurchaseOrderItem {
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
@Column()
|
||||||
|
productSku: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
@Column()
|
||||||
|
productName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column({ type: 'decimal', precision: 10, scale: 2 })
|
||||||
|
price: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
purchaseOrderId: number;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
@Exclude()
|
||||||
|
export class Service {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryColumn()
|
||||||
|
@Expose()
|
||||||
|
id?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
carrier_name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
service_name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
@Expose()
|
||||||
|
isActive: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt?: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt?: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
ManyToOne,
|
||||||
|
OneToOne,
|
||||||
|
JoinColumn
|
||||||
|
} from 'typeorm';
|
||||||
|
import { StockPoint } from './stock_point.entity';
|
||||||
|
import { Order } from './order.entity';
|
||||||
|
|
||||||
|
@Entity('shipment')
|
||||||
|
@Exclude()
|
||||||
|
export class Shipment {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
order_id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@OneToOne(() => Order)
|
||||||
|
@JoinColumn({ name: 'order_id' })
|
||||||
|
order: Order;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ name: 'stock_point_id' })
|
||||||
|
@Expose()
|
||||||
|
stockPointId: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => StockPoint)
|
||||||
|
@JoinColumn({ name: 'stock_point_id' })
|
||||||
|
stockPoint: StockPoint;
|
||||||
|
|
||||||
|
@Column({ nullable: false, default: 0})
|
||||||
|
@Expose()
|
||||||
|
fee: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
tracking_id: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
tracking_provider?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
unique_id: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
state?: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false, default: false })
|
||||||
|
@Expose()
|
||||||
|
finished: boolean;
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
type?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
transaction_number?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
primary_tracking_number?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: [String] })
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
tracking_numbers?: string[];
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
tracking_url?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
return_tracking_number?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
bol_number?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
pickup_confirmation_number?: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
customs_invoice_url?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Object })
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
rate?: Record<string, any>;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
labels?: Array<any>;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt?: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt?: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
JoinColumn,
|
||||||
|
ManyToOne,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { Shipment } from './shipment.entity';
|
||||||
|
import { Order } from './order.entity';
|
||||||
|
|
||||||
|
@Entity('shipment_item')
|
||||||
|
@Exclude()
|
||||||
|
export class ShipmentItem {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Expose()
|
||||||
|
@ManyToOne(() => Shipment)
|
||||||
|
@JoinColumn({ name: 'shipment_id' })
|
||||||
|
shipment_id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Expose()
|
||||||
|
@ManyToOne(() => Order)
|
||||||
|
@JoinColumn({ name: 'order_id' })
|
||||||
|
order_id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true })
|
||||||
|
@Expose()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'sku', type: 'string' })
|
||||||
|
@Expose()
|
||||||
|
@Column()
|
||||||
|
sku: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { Address } from '../dto/freightcom.dto';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
@Exclude()
|
||||||
|
export class ShippingAddress {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
stockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Address })
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
address: Address;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
phone_number: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
phone_number_extension: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
phone_number_country: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt?: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt?: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('site')
|
||||||
|
export class Site {
|
||||||
|
@PrimaryGeneratedColumn({ type: 'int' })
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar', length: 255, nullable: true })
|
||||||
|
apiUrl: string;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar', length: 255, nullable: true })
|
||||||
|
consumerKey: string;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar', length: 255, nullable: true })
|
||||||
|
consumerSecret: string;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar', length: 255, unique: true })
|
||||||
|
siteName: string;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar', length: 32, default: 'woocommerce' })
|
||||||
|
type: string; // 平台类型:woocommerce | shopyy
|
||||||
|
|
||||||
|
@Column({ type: 'varchar', length: 64, nullable: true })
|
||||||
|
skuPrefix: string;
|
||||||
|
|
||||||
|
@Column({ type: 'tinyint', default: 0 })
|
||||||
|
isDisabled: number;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// src/entity/Stock.ts
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('stock')
|
||||||
|
export class Stock {
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
stockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
@Column()
|
||||||
|
productSku: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import {
|
||||||
|
BaseEntity,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
DeleteDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
OneToMany,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { Shipment } from './shipment.entity';
|
||||||
|
|
||||||
|
@Entity('stock_point')
|
||||||
|
export class StockPoint extends BaseEntity {
|
||||||
|
@ApiProperty({ type: 'number' })
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@OneToMany(() => Shipment, shipment => shipment.stockPoint)
|
||||||
|
shipments: Shipment[];
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'string' })
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'string' })
|
||||||
|
@Column()
|
||||||
|
location: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'string' })
|
||||||
|
@Column()
|
||||||
|
contactPerson: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'string' })
|
||||||
|
@Column()
|
||||||
|
contactPhone: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
ignore: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
inCanada: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: false })
|
||||||
|
isB: boolean;
|
||||||
|
|
||||||
|
@Column({ default: 'uniuni' })
|
||||||
|
upStreamName: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
upStreamStockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
|
||||||
|
@DeleteDateColumn()
|
||||||
|
deletedAt: Date; // 软删除时间
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
// src/entity/StockRecord.ts
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { StockRecordOperationType } from '../enums/base.enum';
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
|
||||||
|
@Entity('stock_record')
|
||||||
|
export class StockRecord {
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
stockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
@Column()
|
||||||
|
productSku: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: StockRecordOperationType })
|
||||||
|
@Column({ type: 'enum', enum: StockRecordOperationType })
|
||||||
|
operationType: StockRecordOperationType;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
quantityChange: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
operatorId: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
@Column({ nullable: true })
|
||||||
|
note: string;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
import {
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
Entity,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class Strength {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: '唯一识别key',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
unique_key: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Exclude, Expose } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { SubscriptionStatus } from '../enums/base.enum';
|
||||||
|
|
||||||
|
@Entity('subscription')
|
||||||
|
@Exclude()
|
||||||
|
export class Subscription {
|
||||||
|
// 本地主键,自增 ID
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
@Expose()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
// 站点唯一标识,用于区分不同来源站点
|
||||||
|
@ApiProperty({ description: '来源站点唯一标识' })
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
siteId: string;
|
||||||
|
|
||||||
|
// WooCommerce 订阅的原始 ID(字符串化),用于幂等更新
|
||||||
|
@ApiProperty({ description: 'WooCommerce 订阅 ID' })
|
||||||
|
@Column()
|
||||||
|
@Expose()
|
||||||
|
externalSubscriptionId: string;
|
||||||
|
|
||||||
|
// 订阅状态(active/cancelled/on-hold 等)
|
||||||
|
@ApiProperty({ type: SubscriptionStatus })
|
||||||
|
@Column({ type: 'enum', enum: SubscriptionStatus })
|
||||||
|
@Expose()
|
||||||
|
status: SubscriptionStatus;
|
||||||
|
|
||||||
|
// 货币代码,例如 USD/CAD
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
currency: string;
|
||||||
|
|
||||||
|
// 总金额,保留两位小数
|
||||||
|
@ApiProperty()
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, default: 0 })
|
||||||
|
@Expose()
|
||||||
|
total: number;
|
||||||
|
|
||||||
|
// 计费周期(day/week/month/year)
|
||||||
|
@ApiProperty({ description: '计费周期 e.g. day/week/month/year' })
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
billing_period: string;
|
||||||
|
|
||||||
|
// 计费周期间隔(例如 1/3/12)
|
||||||
|
@ApiProperty({ description: '计费周期间隔 e.g. 1/3/12' })
|
||||||
|
@Column({ type: 'int', default: 0 })
|
||||||
|
@Expose()
|
||||||
|
billing_interval: number;
|
||||||
|
|
||||||
|
// 客户 ID(WooCommerce 用户 ID)
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'int', default: 0 })
|
||||||
|
@Expose()
|
||||||
|
customer_id: number;
|
||||||
|
|
||||||
|
// 客户邮箱(从 billing.email 或 customer_email 提取)
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ default: '' })
|
||||||
|
@Expose()
|
||||||
|
customer_email: string;
|
||||||
|
|
||||||
|
// 父订单/订阅 ID(如有)
|
||||||
|
@ApiProperty({ description: '父订单/父订阅ID(如有)' })
|
||||||
|
@Column({ type: 'int', default: 0 })
|
||||||
|
@Expose()
|
||||||
|
parent_id: number;
|
||||||
|
|
||||||
|
// 订阅开始时间
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'timestamp', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
start_date: Date;
|
||||||
|
|
||||||
|
// 试用结束时间
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'timestamp', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
trial_end: Date;
|
||||||
|
|
||||||
|
// 下次支付时间
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'timestamp', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
next_payment_date: Date;
|
||||||
|
|
||||||
|
// 订阅结束时间
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'timestamp', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
end_date: Date;
|
||||||
|
|
||||||
|
// 商品项(订阅行项目)
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
line_items: any[];
|
||||||
|
|
||||||
|
// 额外元数据(键值对)
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
@Expose()
|
||||||
|
meta_data: any[];
|
||||||
|
|
||||||
|
// 创建时间(数据库自动生成)
|
||||||
|
@ApiProperty({ example: '2022-12-12 11:11:11', description: '创建时间', required: true })
|
||||||
|
@CreateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
// 更新时间(数据库自动生成)
|
||||||
|
@ApiProperty({ example: '2022-12-12 11:11:11', description: '更新时间', required: true })
|
||||||
|
@UpdateDateColumn()
|
||||||
|
@Expose()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import {
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
Entity,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export class Transfer {
|
||||||
|
@ApiProperty()
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id?: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: 'string' })
|
||||||
|
@Column()
|
||||||
|
orderNumber: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
sourceStockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
destStockPointId: number;
|
||||||
|
|
||||||
|
@ApiProperty({})
|
||||||
|
@Column({ default: false })
|
||||||
|
isCancel: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({})
|
||||||
|
@Column({ default: false })
|
||||||
|
isArrived: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({})
|
||||||
|
@Column({ default: false })
|
||||||
|
isLost: boolean;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true, type: 'text' })
|
||||||
|
note: string;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true, type: Date })
|
||||||
|
sendAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty()
|
||||||
|
@Column({ nullable: true, type: Date })
|
||||||
|
arriveAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('transfer_item')
|
||||||
|
export class TransferItem {
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
@Column()
|
||||||
|
productSku: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: String })
|
||||||
|
@Column()
|
||||||
|
productName: string;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
quantity: number;
|
||||||
|
|
||||||
|
@ApiProperty({ type: Number })
|
||||||
|
@Column()
|
||||||
|
transferId: number;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// src/entity/user.entity.ts
|
||||||
|
import { Exclude } from 'class-transformer';
|
||||||
|
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('user')
|
||||||
|
export class User {
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@Column({ unique: true })
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
@Exclude()
|
||||||
|
password: string;
|
||||||
|
|
||||||
|
// @Column() // 默认角色为管理员
|
||||||
|
// roleId: number; // 角色 (如:admin, editor, viewer)
|
||||||
|
|
||||||
|
@Column({ type: 'simple-array', nullable: true })
|
||||||
|
permissions: string[]; // 自定义权限 (如:['user:add', 'user:edit'])
|
||||||
|
|
||||||
|
@Column({ default: false })
|
||||||
|
isSuper: boolean; // 超级管理员
|
||||||
|
|
||||||
|
@Column({ default: false })
|
||||||
|
isAdmin: boolean; // 管理员
|
||||||
|
|
||||||
|
@Column({ default: true })
|
||||||
|
isActive: boolean; // 用户是否启用
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
import {
|
||||||
|
Entity,
|
||||||
|
Column,
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Unique,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
|
||||||
|
@Entity('variation')
|
||||||
|
@Unique(['siteId', 'externalProductId', 'externalVariationId']) // 确保变体的唯一性
|
||||||
|
export class Variation {
|
||||||
|
@ApiProperty({
|
||||||
|
example: '1',
|
||||||
|
description: 'ID',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '1',
|
||||||
|
description: 'wp网站ID',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
siteId: string; // 来源站点唯一标识
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '1',
|
||||||
|
description: 'wp产品ID',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
externalProductId: string; // WooCommerce 产品 ID
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '1',
|
||||||
|
description: 'wp变体ID',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
externalVariationId: string; // WooCommerce 变体 ID
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '1',
|
||||||
|
description: '对应WP产品表的ID',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
productId: number; // 对应WP产品表的 ID
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'sku', type: 'string' })
|
||||||
|
@Column({ nullable: true })
|
||||||
|
sku?: string; // sku 编码
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: '变体名称',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '常规价格', type: Number })
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
regular_price: number; // 常规价格
|
||||||
|
|
||||||
|
@ApiProperty({ description: '销售价格', type: Number })
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
sale_price: number; // 销售价格
|
||||||
|
|
||||||
|
@ApiProperty({ description: '是否促销中', type: Boolean })
|
||||||
|
@Column({ nullable: true, type: Boolean })
|
||||||
|
on_sale: boolean; // 是否促销中
|
||||||
|
|
||||||
|
@ApiProperty({ description: '是否删除', type: Boolean })
|
||||||
|
@Column({ nullable: true, type: Boolean , default: false })
|
||||||
|
on_delete: boolean; // 是否删除
|
||||||
|
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
attributes: Record<string, any>; // 变体的属性
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: '变体构成成分',
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
sku: { type: 'string' },
|
||||||
|
quantity: { type: 'number' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
@Column('json', { nullable: true, comment: '变体构成成分' })
|
||||||
|
constitution: { sku: string; quantity: number }[] | null;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,125 @@
|
||||||
|
import {
|
||||||
|
PrimaryGeneratedColumn,
|
||||||
|
Column,
|
||||||
|
CreateDateColumn,
|
||||||
|
UpdateDateColumn,
|
||||||
|
Unique,
|
||||||
|
Entity,
|
||||||
|
} from 'typeorm';
|
||||||
|
import { ApiProperty } from '@midwayjs/swagger';
|
||||||
|
import { ProductStatus, ProductStockStatus, ProductType } from '../enums/base.enum';
|
||||||
|
|
||||||
|
@Entity('wp_product')
|
||||||
|
@Unique(['siteId', 'externalProductId']) // 确保产品的唯一性
|
||||||
|
export class WpProduct {
|
||||||
|
@ApiProperty({
|
||||||
|
example: '1',
|
||||||
|
description: 'ID',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@PrimaryGeneratedColumn()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '1',
|
||||||
|
description: 'wp网站ID',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
siteId: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '1',
|
||||||
|
description: 'wp产品ID',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
externalProductId: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'sku', type: 'string' })
|
||||||
|
@Column({ nullable: true })
|
||||||
|
sku?: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: 'ZYN 6MG WINTERGREEN',
|
||||||
|
description: '产品名称',
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '产品状态', enum: ProductStatus })
|
||||||
|
@Column({ type: 'enum', enum: ProductStatus })
|
||||||
|
status: ProductStatus;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '上下架状态', enum: ProductStockStatus })
|
||||||
|
@Column({
|
||||||
|
name: 'stock_status',
|
||||||
|
type: 'enum',
|
||||||
|
enum: ProductStockStatus,
|
||||||
|
default: ProductStockStatus.INSTOCK
|
||||||
|
})
|
||||||
|
stockStatus: ProductStockStatus;
|
||||||
|
|
||||||
|
@ApiProperty({ description: '常规价格', type: Number })
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
regular_price: number; // 常规价格
|
||||||
|
|
||||||
|
@ApiProperty({ description: '销售价格', type: Number })
|
||||||
|
@Column('decimal', { precision: 10, scale: 2, nullable: true })
|
||||||
|
sale_price: number; // 销售价格
|
||||||
|
|
||||||
|
@ApiProperty({ description: '是否促销中', type: Boolean })
|
||||||
|
@Column({ nullable: true, type: Boolean })
|
||||||
|
on_sale: boolean; // 是否促销中
|
||||||
|
|
||||||
|
@ApiProperty({ description: '是否删除', type: Boolean })
|
||||||
|
@Column({ nullable: true, type: Boolean , default: false })
|
||||||
|
on_delete: boolean; // 是否删除
|
||||||
|
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: '产品类型',
|
||||||
|
enum: ProductType,
|
||||||
|
})
|
||||||
|
@Column({ type: 'enum', enum: ProductType })
|
||||||
|
type: ProductType;
|
||||||
|
|
||||||
|
|
||||||
|
@Column({ type: 'json', nullable: true })
|
||||||
|
metadata: Record<string, any>; // 产品的其他扩展字段
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '创建时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@CreateDateColumn()
|
||||||
|
createdAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: '2022-12-12 11:11:11',
|
||||||
|
description: '更新时间',
|
||||||
|
required: true,
|
||||||
|
})
|
||||||
|
@UpdateDateColumn()
|
||||||
|
updatedAt: Date;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
description: '产品构成成分',
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
sku: { type: 'string' },
|
||||||
|
quantity: { type: 'number' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
@Column('json', { nullable: true, comment: '产品构成成分' })
|
||||||
|
constitution: { sku: string; quantity: number }[] | null;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
export enum ProductStatus {
|
||||||
|
PUBLISH = 'publish', // 已发布
|
||||||
|
DRAFT = 'draft', // 草稿
|
||||||
|
PENDING = 'pending', // 待审核
|
||||||
|
PRIVATE = 'private', // 私有
|
||||||
|
TRASH = 'trash', // 回收站
|
||||||
|
AUTO_DRAFT = 'auto-draft', // 自动草稿
|
||||||
|
FUTURE = 'future', // 定时发布
|
||||||
|
INHERIT = 'inherit', // 继承状态
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ProductStockStatus {
|
||||||
|
INSTOCK = 'instock',
|
||||||
|
OUT_OF_STOCK = 'outofstock',
|
||||||
|
ON_BACK_ORDER = 'onbackorder',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ProductType {
|
||||||
|
SIMPLE = 'simple',
|
||||||
|
VARIABLE = 'variable',
|
||||||
|
WOOSB = 'woosb',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum PurchaseOrderStatus {
|
||||||
|
DRAFT = 'draft',
|
||||||
|
SUBMITTED = 'submitted',
|
||||||
|
RECEIVED = 'received',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum StockRecordOperationType {
|
||||||
|
IN = 'in',
|
||||||
|
OUT = 'out',
|
||||||
|
}
|
||||||
|
// Order status. Options: pending, processing, on-hold, completed, cancelled, refunded, failed and trash. Default is pending.
|
||||||
|
// 原始订单状态
|
||||||
|
export enum OrderStatus {
|
||||||
|
PENDING = 'pending', // default // 待付款
|
||||||
|
PROCESSING = 'processing', // 正在处理
|
||||||
|
ON_HOLD = 'on-hold', // 保留
|
||||||
|
COMPLETED = 'completed', // 已完成
|
||||||
|
CANCEL = 'cancelled', // 已取消
|
||||||
|
REFUNDED = 'refunded', // 已退款
|
||||||
|
FAILED = 'failed', // 失败订单
|
||||||
|
DRAFT = 'draft', // 草稿
|
||||||
|
AUTO_DRAFT = 'auto-draft', // 自动草稿
|
||||||
|
// TRASH = 'trash',
|
||||||
|
// refund 也就是退款相关的状态
|
||||||
|
RETURN_REQUESTED = 'return-requested', // 已申请退款
|
||||||
|
RETURN_APPROVED = 'return-approved', // 退款申请已通过
|
||||||
|
RETURN_CANCELLED = 'return-cancelled', // 已取消退款
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ErpOrderStatus {
|
||||||
|
PENDING = 'pending', // 待确认
|
||||||
|
PROCESSING = 'processing', //待发货
|
||||||
|
COMPLETED = 'completed', //已完成
|
||||||
|
CANCEL = 'cancelled', //已取消
|
||||||
|
REFUNDED = 'refunded', //已退款
|
||||||
|
FAILED = 'failed', //失败
|
||||||
|
AFTER_SALE_PROCESSING = 'after_sale_pending', // 售后处理中
|
||||||
|
PENDING_RESHIPMENT = 'pending_reshipment', // 待补发
|
||||||
|
PENDING_REFUND = 'pending_refund', // 待退款
|
||||||
|
RETURN_REQUESTED = 'return-requested', // 已申请退款
|
||||||
|
RETURN_APPROVED = 'return-approved', // 退款申请已通过
|
||||||
|
RETURN_CANCELLED = 'return-cancelled', // 已取消退款
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ShipmentType {
|
||||||
|
CANADAPOST = 'canadapost',
|
||||||
|
FREIGHTCOM = 'freightcom',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum staticValue {
|
||||||
|
// 万能验证码
|
||||||
|
STATIC_CAPTCHA = 'yoone2025!@YOONE0923'
|
||||||
|
}
|
||||||
|
|
||||||
|
// WooCommerce Subscription status
|
||||||
|
// Reference: https://woocommerce.com/document/subscriptions/statuses/
|
||||||
|
export enum SubscriptionStatus {
|
||||||
|
ACTIVE = 'active', // 活跃
|
||||||
|
PENDING = 'pending', // 待处理/待激活
|
||||||
|
ON_HOLD = 'on-hold', // 暂停
|
||||||
|
CANCELLED = 'cancelled', // 已取消
|
||||||
|
EXPIRED = 'expired', // 已过期
|
||||||
|
PENDING_CANCELLATION = 'pending-cancel', // 待取消
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { Catch } from '@midwayjs/core';
|
||||||
|
import { Context } from '@midwayjs/koa';
|
||||||
|
|
||||||
|
@Catch()
|
||||||
|
export class DefaultErrorFilter {
|
||||||
|
async catch(err: Error, ctx: Context) {
|
||||||
|
// 所有的未分类错误会到这里
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
message: err.message,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Catch, httpError, MidwayHttpError } from '@midwayjs/core';
|
||||||
|
import { Context } from '@midwayjs/koa';
|
||||||
|
|
||||||
|
@Catch(httpError.NotFoundError)
|
||||||
|
export class NotFoundFilter {
|
||||||
|
async catch(err: MidwayHttpError, ctx: Context) {
|
||||||
|
// 404 错误会到这里
|
||||||
|
ctx.redirect('/404.html');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
import { useEffect, useState } from 'react';
|
|
||||||
import FingerprintJS from '@fingerprintjs/fingerprintjs';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hook: 获取设备指纹(visitorId)
|
|
||||||
*/
|
|
||||||
export function useDeviceFingerprint() {
|
|
||||||
const [fingerprint, setFingerprint] = useState<string | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let isMounted = true;
|
|
||||||
|
|
||||||
async function loadFingerprint() {
|
|
||||||
try {
|
|
||||||
const fp = await FingerprintJS.load();
|
|
||||||
const result = await fp.get();
|
|
||||||
if (isMounted) {
|
|
||||||
setFingerprint(result.visitorId);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.error('获取设备指纹失败:', err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadFingerprint();
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
isMounted = false;
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return fingerprint; // 初始为 null,加载后返回指纹 ID
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* @description User-Service parameters
|
||||||
|
*/
|
||||||
|
export interface IUserOptions {
|
||||||
|
uid: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WpSite {
|
||||||
|
id: string;
|
||||||
|
wpApiUrl: string;
|
||||||
|
consumerKey: string;
|
||||||
|
consumerSecret: string;
|
||||||
|
siteName: string;
|
||||||
|
email: string;
|
||||||
|
emailPswd: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaginationParams {
|
||||||
|
current?: number; // 当前页码
|
||||||
|
pageSize?: number; // 每页数量
|
||||||
|
sorter?: any;
|
||||||
|
filter?: any;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { FORMAT, ILogger, Logger } from '@midwayjs/core';
|
||||||
|
import { IJob, Job } from '@midwayjs/cron';
|
||||||
|
|
||||||
|
@Job({
|
||||||
|
cronTime: FORMAT.CRONTAB.EVERY_DAY,
|
||||||
|
runOnInit: true,
|
||||||
|
})
|
||||||
|
export class SyncProductJob implements IJob {
|
||||||
|
@Logger()
|
||||||
|
logger: ILogger;
|
||||||
|
|
||||||
|
onTick() {
|
||||||
|
}
|
||||||
|
onComplete?(result: any) {}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
import { FORMAT, ILogger, Inject, Logger } from '@midwayjs/core';
|
||||||
|
import { IJob, Job } from '@midwayjs/cron';
|
||||||
|
import { LogisticsService } from '../service/logistics.service';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { Shipment } from '../entity/shipment.entity';
|
||||||
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
|
|
||||||
|
@Job({
|
||||||
|
cronTime: FORMAT.CRONTAB.EVERY_PER_30_MINUTE,
|
||||||
|
start: true,
|
||||||
|
runOnInit: true,
|
||||||
|
})
|
||||||
|
export class SyncShipmentJob implements IJob {
|
||||||
|
@Logger()
|
||||||
|
logger: ILogger;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
logisticsService: LogisticsService;
|
||||||
|
|
||||||
|
onTick() {
|
||||||
|
this.logisticsService.syncShipmentStatus();
|
||||||
|
this.logisticsService.syncShipment();
|
||||||
|
}
|
||||||
|
onComplete?(result: any) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Job({
|
||||||
|
cronTime: '0 0 12 * * *', // 每天12点执行
|
||||||
|
start: true
|
||||||
|
})
|
||||||
|
export class SyncUniuniShipmentJob implements IJob{
|
||||||
|
@Logger()
|
||||||
|
logger: ILogger;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
logisticsService: LogisticsService;
|
||||||
|
|
||||||
|
@InjectEntityModel(Shipment)
|
||||||
|
shipmentModel: Repository<Shipment>
|
||||||
|
|
||||||
|
uniuniStateCodes = {
|
||||||
|
'190': 'ORDER_RECEIVED',
|
||||||
|
'192': 'CUSTOM_HOLD',
|
||||||
|
'195': 'GATEWAY_TRANSIT_OUT',
|
||||||
|
'198': 'CUSTOM_RELEASE_DIRECT',
|
||||||
|
'199': 'GATEWAY_TRANSIT',
|
||||||
|
'200': 'PARCEL_SCANNED',
|
||||||
|
'202': 'IN_TRANSIT',
|
||||||
|
'203': 'DELIVERED',
|
||||||
|
'204': 'TRANSSHIPMENT',
|
||||||
|
'206': 'WRONG_ADDRESS_FROM_TRANSIT',
|
||||||
|
'207': 'PARCEL_LOST',
|
||||||
|
'209': 'OTHER_EXCEPTION',
|
||||||
|
'211': 'RETURN_OFFICE_FROM_TRANSIT',
|
||||||
|
'212': 'WRONG_ADDRESS_FROM_RECEIVE',
|
||||||
|
'213': 'STORAGE_30_DAYS_FROM_OFFICE',
|
||||||
|
'214': 'STORAGE_30_DAYS_AFTER_SCAN',
|
||||||
|
'215': 'PARCEL_ABANDONED',
|
||||||
|
'216': 'SELF_PICK_UP',
|
||||||
|
'217': 'TRANSSHIPMENT_COMPLETE',
|
||||||
|
'218': 'SCANNED_PARCEL_MISSING',
|
||||||
|
'219': 'WRONG_ROUTE_PARCEL',
|
||||||
|
'220': 'SECOND_DELIVERY',
|
||||||
|
'221': 'RETURNED_PARCEL_SCANNED',
|
||||||
|
'222': 'REJECTED_PARCEL_FROM_TRANSIT',
|
||||||
|
'223': 'CHANGED_ORDER_RESENT',
|
||||||
|
'224': 'RESENT_ORDER_VOIDED',
|
||||||
|
'225': 'FORWARDED_3RDPARTY',
|
||||||
|
'226': 'STORAGE_3RDPARTY_SERVICE_POINT',
|
||||||
|
'228': 'SECOND_DELIVERED',
|
||||||
|
'229': 'DROP_OFF_SERVICE_POINTS',
|
||||||
|
'230': 'RETURN TO SENDER WAREHOUSE',
|
||||||
|
'231': 'FAILED_DELIVERY_RETRY1',
|
||||||
|
'232': 'FAILED_DELIVERY_RETRY2',
|
||||||
|
'255': 'Gateway_To_Gateway_Transit'
|
||||||
|
};
|
||||||
|
async onTick() {
|
||||||
|
const shipments:Shipment[] = await this.shipmentModel.findBy({ finished: false });
|
||||||
|
shipments.forEach(shipment => {
|
||||||
|
this.logisticsService.updateShipmentState(shipment);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onComplete(result: any) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
import { ILogger, Inject, Logger } from '@midwayjs/core';
|
||||||
|
import { IJob, Job } from '@midwayjs/cron';
|
||||||
|
import { LogisticsService } from '../service/logistics.service';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { Shipment } from '../entity/shipment.entity';
|
||||||
|
import { InjectEntityModel } from '@midwayjs/typeorm';
|
||||||
|
|
||||||
|
|
||||||
|
@Job({
|
||||||
|
cronTime: '0 0 12 * * *', // 每天12点执行
|
||||||
|
start: true
|
||||||
|
})
|
||||||
|
export class SyncTmsJob implements IJob {
|
||||||
|
@Logger()
|
||||||
|
logger: ILogger;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
logisticsService: LogisticsService;
|
||||||
|
|
||||||
|
@InjectEntityModel(Shipment)
|
||||||
|
shipmentModel: Repository<Shipment>
|
||||||
|
|
||||||
|
async onTick() {
|
||||||
|
const shipments: Shipment[] = await this.shipmentModel.findBy({ tracking_provider: 'freightwaves', finished: false });
|
||||||
|
const results = await Promise.all(
|
||||||
|
shipments.map(async shipment => {
|
||||||
|
return await this.logisticsService.updateFreightwavesShipmentState(shipment);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
this.logger.info(`更新运单状态完毕 ${JSON.stringify(results)}`);
|
||||||
|
return results
|
||||||
|
}
|
||||||
|
|
||||||
|
onComplete(result: any) {
|
||||||
|
this.logger.info(`更新运单状态完成 ${result}`);
|
||||||
|
}
|
||||||
|
onError(error: any) {
|
||||||
|
this.logger.error(`更新运单状态失败 ${error.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
// src/middleware/auth.middleware.ts
|
||||||
|
import {
|
||||||
|
IMiddleware,
|
||||||
|
Middleware,
|
||||||
|
Inject,
|
||||||
|
NextFunction,
|
||||||
|
httpError,
|
||||||
|
} from '@midwayjs/core';
|
||||||
|
import { Context } from '@midwayjs/koa';
|
||||||
|
import { JwtService } from '@midwayjs/jwt'; // 引入 JwtService 类型
|
||||||
|
import { DeviceWhitelistService } from '../service/deviceWhitelist.service';
|
||||||
|
|
||||||
|
@Middleware()
|
||||||
|
export class AuthMiddleware implements IMiddleware<Context, NextFunction> {
|
||||||
|
@Inject()
|
||||||
|
jwtService: JwtService; // 注入 JwtService 实例
|
||||||
|
@Inject()
|
||||||
|
deviceWhitelistService: DeviceWhitelistService;
|
||||||
|
|
||||||
|
// 白名单配置
|
||||||
|
whiteList = [
|
||||||
|
'/user/login',
|
||||||
|
'/webhook/woocommerce',
|
||||||
|
'/logistics/getTrackingNumber',
|
||||||
|
'/logistics/getListByTrackingId',
|
||||||
|
];
|
||||||
|
|
||||||
|
match(ctx: Context) {
|
||||||
|
return !this.isWhiteListed(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve() {
|
||||||
|
return async (ctx: Context, next: NextFunction) => {
|
||||||
|
// 判断下有没有校验信息
|
||||||
|
if (!ctx.headers['authorization']) {
|
||||||
|
throw new httpError.UnauthorizedError();
|
||||||
|
}
|
||||||
|
// 从 header 上获取校验信息
|
||||||
|
const parts = ctx.get('authorization').trim().split(' ');
|
||||||
|
|
||||||
|
if (parts.length !== 2) {
|
||||||
|
throw new httpError.UnauthorizedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
const [scheme, token] = parts;
|
||||||
|
|
||||||
|
if (!/^Bearer$/i.test(scheme)) {
|
||||||
|
throw new httpError.UnauthorizedError('Invalid Token Scheme');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2. 校验 JWT 并解析 payload
|
||||||
|
const decoded: any = await this.jwtService.verify(token);
|
||||||
|
|
||||||
|
const deviceId: string = decoded.deviceId;
|
||||||
|
if (!deviceId) {
|
||||||
|
throw new httpError.UnauthorizedError('Missing deviceId in token');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 校验设备是否在白名单
|
||||||
|
const isWhite = await this.deviceWhitelistService.isWhitelisted(
|
||||||
|
deviceId
|
||||||
|
);
|
||||||
|
if (!isWhite) {
|
||||||
|
throw new httpError.UnauthorizedError('Device not authorized');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
throw new httpError.UnauthorizedError('Invalid or expired token');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (/^Bearer$/i.test(scheme)) {
|
||||||
|
try {
|
||||||
|
//jwt.verify方法验证token是否有效
|
||||||
|
await this.jwtService.verify(token, {
|
||||||
|
complete: true,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw new httpError.UnauthorizedError();
|
||||||
|
}
|
||||||
|
await next();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getName(): string {
|
||||||
|
return 'authMiddleware';
|
||||||
|
}
|
||||||
|
|
||||||
|
static getPriority(): number {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
isWhiteListed(ctx: Context): boolean {
|
||||||
|
return this.whiteList.includes(ctx.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Middleware, IMiddleware } from '@midwayjs/core';
|
||||||
|
import { NextFunction, Context } from '@midwayjs/koa';
|
||||||
|
|
||||||
|
@Middleware()
|
||||||
|
export class ReportMiddleware implements IMiddleware<Context, NextFunction> {
|
||||||
|
resolve() {
|
||||||
|
return async (ctx: Context, next: NextFunction) => {
|
||||||
|
// 控制器前执行的逻辑
|
||||||
|
const startTime = Date.now();
|
||||||
|
// 执行下一个 Web 中间件,最后执行到控制器
|
||||||
|
// 这里可以拿到下一个中间件或者控制器的返回值
|
||||||
|
const result = await next();
|
||||||
|
// 控制器之后执行的逻辑
|
||||||
|
ctx.logger.info(
|
||||||
|
`Report in "src/middleware/report.middleware.ts", rt = ${
|
||||||
|
Date.now() - startTime
|
||||||
|
}ms`
|
||||||
|
);
|
||||||
|
// 返回给上一个中间件的结果
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getName(): string {
|
||||||
|
return 'report';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
// 全局共享数据示例
|
|
||||||
import { DEFAULT_NAME } from '@/constants';
|
|
||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
const useUser = () => {
|
|
||||||
const [name, setName] = useState<string>(DEFAULT_NAME);
|
|
||||||
return {
|
|
||||||
name,
|
|
||||||
setName,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default useUser;
|
|
||||||
|
|
@ -1,286 +0,0 @@
|
||||||
import { HistoryOrder } from '@/pages/Statistics/Order';
|
|
||||||
import {
|
|
||||||
customercontrollerAddtag,
|
|
||||||
customercontrollerDeltag,
|
|
||||||
customercontrollerGetcustomerlist,
|
|
||||||
customercontrollerGettags,
|
|
||||||
customercontrollerSetrate,
|
|
||||||
} from '@/servers/api/customer';
|
|
||||||
import {
|
|
||||||
ActionType,
|
|
||||||
ModalForm,
|
|
||||||
PageContainer,
|
|
||||||
ProColumns,
|
|
||||||
ProFormSelect,
|
|
||||||
ProTable,
|
|
||||||
} from '@ant-design/pro-components';
|
|
||||||
import { App, Button, Rate, Space, Tag } from 'antd';
|
|
||||||
import dayjs from 'dayjs';
|
|
||||||
import { useRef, useState } from 'react';
|
|
||||||
|
|
||||||
const ListPage: React.FC = () => {
|
|
||||||
const actionRef = useRef<ActionType>();
|
|
||||||
const { message } = App.useApp();
|
|
||||||
const columns: ProColumns[] = [
|
|
||||||
{
|
|
||||||
title: '用户名',
|
|
||||||
dataIndex: 'username',
|
|
||||||
hideInSearch: true,
|
|
||||||
render: (_, record) => {
|
|
||||||
if (record.billing.first_name || record.billing.last_name)
|
|
||||||
return record.billing.first_name + ' ' + record.billing.last_name;
|
|
||||||
return record.shipping.first_name + ' ' + record.shipping.last_name;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '邮箱',
|
|
||||||
dataIndex: 'email',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '客户编号',
|
|
||||||
dataIndex: 'customerId',
|
|
||||||
render: (_, record) => {
|
|
||||||
if(!record.customerId) return '-';
|
|
||||||
return String(record.customerId).padStart(6,0)
|
|
||||||
},
|
|
||||||
sorter: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '首单时间',
|
|
||||||
dataIndex: 'first_purchase_date',
|
|
||||||
valueType: 'dateMonth',
|
|
||||||
sorter: true,
|
|
||||||
render: (_, record) =>
|
|
||||||
record.first_purchase_date
|
|
||||||
? dayjs(record.first_purchase_date).format('YYYY-MM-DD HH:mm:ss')
|
|
||||||
: '-',
|
|
||||||
// search: {
|
|
||||||
// transform: (value: string) => {
|
|
||||||
// return { month: value };
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '尾单时间',
|
|
||||||
hideInSearch: true,
|
|
||||||
dataIndex: 'last_purchase_date',
|
|
||||||
valueType: 'dateTime',
|
|
||||||
sorter: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '订单数',
|
|
||||||
dataIndex: 'orders',
|
|
||||||
hideInSearch: true,
|
|
||||||
sorter: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '金额',
|
|
||||||
dataIndex: 'total',
|
|
||||||
hideInSearch: true,
|
|
||||||
sorter: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'YOONE订单数',
|
|
||||||
dataIndex: 'yoone_orders',
|
|
||||||
hideInSearch: true,
|
|
||||||
sorter: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'YOONE金额',
|
|
||||||
dataIndex: 'yoone_total',
|
|
||||||
hideInSearch: true,
|
|
||||||
sorter: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '等级',
|
|
||||||
hideInSearch: true,
|
|
||||||
render: (_, record) => {
|
|
||||||
if(!record.yoone_orders || !record.yoone_total) return '-'
|
|
||||||
if(Number(record.yoone_orders) === 1 && Number(record.yoone_total) > 0 ) return 'B'
|
|
||||||
return '-'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '评星',
|
|
||||||
dataIndex: 'rate',
|
|
||||||
width: 200,
|
|
||||||
render: (_, record) => {
|
|
||||||
return <Rate onChange={async(val)=>{
|
|
||||||
try{
|
|
||||||
const { success, message: msg } = await customercontrollerSetrate({
|
|
||||||
id: record.customerId,
|
|
||||||
rate: val
|
|
||||||
});
|
|
||||||
if (success) {
|
|
||||||
message.success(msg);
|
|
||||||
actionRef.current?.reload();
|
|
||||||
}
|
|
||||||
}catch(e){
|
|
||||||
message.error(e.message);
|
|
||||||
|
|
||||||
}
|
|
||||||
}} value={record.rate} />
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'phone',
|
|
||||||
dataIndex: 'phone',
|
|
||||||
hideInSearch: true,
|
|
||||||
render: (_, record) => record?.billing.phone || record?.shipping.phone,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'state',
|
|
||||||
dataIndex: 'state',
|
|
||||||
render: (_, record) => record?.billing.state || record?.shipping.state,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'city',
|
|
||||||
dataIndex: 'city',
|
|
||||||
hideInSearch: true,
|
|
||||||
render: (_, record) => record?.billing.city || record?.shipping.city,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '标签',
|
|
||||||
dataIndex: 'tags',
|
|
||||||
render: (_, record) => {
|
|
||||||
return (
|
|
||||||
<Space>
|
|
||||||
{(record.tags || []).map((tag) => {
|
|
||||||
return (
|
|
||||||
<Tag
|
|
||||||
key={tag}
|
|
||||||
closable
|
|
||||||
onClose={async () => {
|
|
||||||
const { success, message: msg } =
|
|
||||||
await customercontrollerDeltag({
|
|
||||||
email: record.email,
|
|
||||||
tag,
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{tag}
|
|
||||||
</Tag>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Space>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '操作',
|
|
||||||
dataIndex: 'option',
|
|
||||||
valueType: 'option',
|
|
||||||
render: (_, record) => {
|
|
||||||
return (
|
|
||||||
<Space>
|
|
||||||
<AddTag
|
|
||||||
email={record.email}
|
|
||||||
tags={record.tags}
|
|
||||||
tableRef={actionRef}
|
|
||||||
/>
|
|
||||||
<HistoryOrder
|
|
||||||
email={record.email}
|
|
||||||
tags={record.tags}
|
|
||||||
tableRef={actionRef}
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
return (
|
|
||||||
<PageContainer ghost>
|
|
||||||
<ProTable
|
|
||||||
headerTitle="查询表格"
|
|
||||||
actionRef={actionRef}
|
|
||||||
rowKey="id"
|
|
||||||
request={async (params, sorter) => {
|
|
||||||
const key = Object.keys(sorter)[0];
|
|
||||||
const { data, success } = await customercontrollerGetcustomerlist({
|
|
||||||
...params,
|
|
||||||
...(key ? { sorterKey: key, sorterValue: sorter[key] } : {}),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
total: data?.total || 0,
|
|
||||||
data: data?.items || [],
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
columns={columns}
|
|
||||||
/>
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const AddTag: React.FC<{
|
|
||||||
email: string;
|
|
||||||
tags?: string[];
|
|
||||||
tableRef: React.MutableRefObject<ActionType | undefined>;
|
|
||||||
}> = ({ email, tags, tableRef }) => {
|
|
||||||
const { message } = App.useApp();
|
|
||||||
const [tagList, setTagList] = useState<string[]>([]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ModalForm
|
|
||||||
title={`修改标签 - ${email}`}
|
|
||||||
trigger={<Button>修改标签</Button>}
|
|
||||||
width={800}
|
|
||||||
modalProps={{
|
|
||||||
destroyOnHidden: true,
|
|
||||||
}}
|
|
||||||
submitter={false}
|
|
||||||
>
|
|
||||||
<ProFormSelect
|
|
||||||
mode="tags"
|
|
||||||
allowClear
|
|
||||||
name="tag"
|
|
||||||
label="标签"
|
|
||||||
request={async () => {
|
|
||||||
const { data, success } = await customercontrollerGettags();
|
|
||||||
if (!success) return [];
|
|
||||||
setTagList(tags || []);
|
|
||||||
return data
|
|
||||||
.filter((tag) => {
|
|
||||||
return !(tags || []).includes(tag);
|
|
||||||
})
|
|
||||||
.map((tag) => ({ label: tag, value: tag }));
|
|
||||||
}}
|
|
||||||
fieldProps={{
|
|
||||||
value: tagList, // 当前值
|
|
||||||
onChange: async (newValue) => {
|
|
||||||
const added = newValue.filter((x) => !tagList.includes(x));
|
|
||||||
const removed = tagList.filter((x) => !newValue.includes(x));
|
|
||||||
|
|
||||||
if (added.length) {
|
|
||||||
const { success, message: msg } = await customercontrollerAddtag({
|
|
||||||
email,
|
|
||||||
tag: added[0],
|
|
||||||
});
|
|
||||||
if (!success) {
|
|
||||||
message.error(msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (removed.length) {
|
|
||||||
const { success, message: msg } = await customercontrollerDeltag({
|
|
||||||
email,
|
|
||||||
tag: removed[0],
|
|
||||||
});
|
|
||||||
if (!success) {
|
|
||||||
message.error(msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tableRef?.current?.reload();
|
|
||||||
|
|
||||||
setTagList(newValue);
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
></ProFormSelect>
|
|
||||||
</ModalForm>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ListPage;
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
.container {
|
|
||||||
padding-top: 80px;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue