diff --git a/admin-system/src/api/supplier.ts b/admin-system/src/api/supplier.ts index 9cbf1c8..65b9bda 100644 --- a/admin-system/src/api/supplier.ts +++ b/admin-system/src/api/supplier.ts @@ -1,4 +1,5 @@ import request from '@/utils/request' +import type { ApiResponse, PaginatedResponse } from '@/utils/request' import type { Supplier, SupplierListParams, @@ -8,68 +9,39 @@ import type { } from '@/types/supplier' // 获取供应商列表 -export const getSupplierList = (params: SupplierListParams) => { - return request<{ - list: Supplier[] - pagination: { - page: number - pageSize: number - total: number - totalPages: number - } - }>({ - url: '/suppliers', - method: 'GET', - params - }) +export const getSupplierList = (params: SupplierListParams): Promise>> => { + return request.get('/suppliers', { params }) } // 获取供应商详情 -export const getSupplierDetail = (id: number) => { - return request({ - url: `/suppliers/${id}`, - method: 'GET' - }) +export const getSupplierDetail = (id: number): Promise> => { + return request.get(`/suppliers/${id}`) } // 创建供应商 -export const createSupplier = (data: SupplierCreateForm) => { - return request({ - url: '/suppliers', - method: 'POST', - data: { - ...data, - cattleTypes: Array.isArray(data.cattleTypes) ? data.cattleTypes : JSON.parse(data.cattleTypes || '[]'), - certifications: Array.isArray(data.certifications) ? data.certifications : JSON.parse(data.certifications || '[]') - } +export const createSupplier = (data: SupplierCreateForm): Promise> => { + return request.post('/suppliers', { + ...data, + cattleTypes: Array.isArray(data.cattleTypes) ? data.cattleTypes : JSON.parse(data.cattleTypes || '[]'), + certifications: Array.isArray(data.certifications) ? data.certifications : JSON.parse(data.certifications || '[]') }) } // 更新供应商 -export const updateSupplier = (id: number, data: SupplierUpdateForm) => { - return request({ - url: `/suppliers/${id}`, - method: 'PUT', - data: { - ...data, - cattleTypes: data.cattleTypes ? (Array.isArray(data.cattleTypes) ? data.cattleTypes : JSON.parse(data.cattleTypes)) : undefined, - certifications: data.certifications ? (Array.isArray(data.certifications) ? data.certifications : JSON.parse(data.certifications)) : undefined - } +export const updateSupplier = (id: number, data: SupplierUpdateForm): Promise> => { + return request.put(`/suppliers/${id}`, { + ...data, + cattleTypes: data.cattleTypes ? (Array.isArray(data.cattleTypes) ? data.cattleTypes : JSON.parse(data.cattleTypes)) : undefined, + certifications: data.certifications ? (Array.isArray(data.certifications) ? data.certifications : JSON.parse(data.certifications)) : undefined }) } // 删除供应商 -export const deleteSupplier = (id: number) => { - return request({ - url: `/suppliers/${id}`, - method: 'DELETE' - }) +export const deleteSupplier = (id: number): Promise => { + return request.delete(`/suppliers/${id}`) } // 获取供应商统计信息 -export const getSupplierStats = () => { - return request({ - url: '/suppliers/stats/overview', - method: 'GET' - }) +export const getSupplierStats = (): Promise> => { + return request.get('/suppliers/stats/overview') } \ No newline at end of file diff --git a/admin-system/src/api/transport.ts b/admin-system/src/api/transport.ts index b5408e2..410c2af 100644 --- a/admin-system/src/api/transport.ts +++ b/admin-system/src/api/transport.ts @@ -1,4 +1,5 @@ -import request from '@/utils/request'; +import request from '@/utils/request' +import type { ApiResponse, PaginatedResponse } from '@/utils/request' import type { Transport, TransportCreateForm, @@ -8,8 +9,7 @@ import type { VehicleCreateForm, VehicleUpdateForm, VehicleListParams -} from '@/types/transport'; -import type { PaginatedResponse, ApiResponse } from '@/types/api'; +} from '@/types/transport' // 运输管理相关API接口 @@ -19,12 +19,8 @@ import type { PaginatedResponse, ApiResponse } from '@/types/api'; * @returns 运输列表 */ export const getTransportList = (params: TransportListParams): Promise>> => { - return request({ - url: '/transports', - method: 'get', - params - }); -}; + return request.get('/transports', { params }) +} /** * 获取运输详情 @@ -32,11 +28,8 @@ export const getTransportList = (params: TransportListParams): Promise> => { - return request({ - url: `/transports/${id}`, - method: 'get' - }); -}; + return request.get(`/transports/${id}`) +} /** * 创建运输记录 @@ -44,12 +37,8 @@ export const getTransportDetail = (id: number): Promise> * @returns 创建的运输记录 */ export const createTransport = (data: TransportCreateForm): Promise> => { - return request({ - url: '/transports', - method: 'post', - data - }); -}; + return request.post('/transports', data) +} /** * 更新运输记录 @@ -58,24 +47,17 @@ export const createTransport = (data: TransportCreateForm): Promise> => { - return request({ - url: `/transports/${id}`, - method: 'put', - data - }); -}; + return request.put(`/transports/${id}`, data) +} /** * 删除运输记录 * @param id 运输ID * @returns 删除结果 */ -export const deleteTransport = (id: number): Promise> => { - return request({ - url: `/transports/${id}`, - method: 'delete' - }); -}; +export const deleteTransport = (id: number): Promise => { + return request.delete(`/transports/${id}`) +} /** * 获取车辆列表 @@ -83,12 +65,8 @@ export const deleteTransport = (id: number): Promise> => { * @returns 车辆列表 */ export const getVehicleList = (params: VehicleListParams): Promise>> => { - return request({ - url: '/transports/vehicles', - method: 'get', - params - }); -}; + return request.get('/transports/vehicles', { params }) +} /** * 获取车辆详情 @@ -96,11 +74,8 @@ export const getVehicleList = (params: VehicleListParams): Promise> => { - return request({ - url: `/transports/vehicles/${id}`, - method: 'get' - }); -}; + return request.get(`/transports/vehicles/${id}`) +} /** * 创建车辆记录 @@ -108,12 +83,8 @@ export const getVehicleDetail = (id: number): Promise> => { * @returns 创建的车辆记录 */ export const createVehicle = (data: VehicleCreateForm): Promise> => { - return request({ - url: '/transports/vehicles', - method: 'post', - data - }); -}; + return request.post('/transports/vehicles', data) +} /** * 更新车辆记录 @@ -122,21 +93,14 @@ export const createVehicle = (data: VehicleCreateForm): Promise> => { - return request({ - url: `/transports/vehicles/${id}`, - method: 'put', - data - }); -}; + return request.put(`/transports/vehicles/${id}`, data) +} /** * 删除车辆记录 * @param id 车辆ID * @returns 删除结果 */ -export const deleteVehicle = (id: number): Promise> => { - return request({ - url: `/transports/vehicles/${id}`, - method: 'delete' - }); -}; \ No newline at end of file +export const deleteVehicle = (id: number): Promise => { + return request.delete(`/transports/vehicles/${id}`) +} \ No newline at end of file diff --git a/admin-system/src/types/user.ts b/admin-system/src/types/user.ts index 96d345a..2f72e7b 100644 --- a/admin-system/src/types/user.ts +++ b/admin-system/src/types/user.ts @@ -6,7 +6,7 @@ export interface User { email: string phone?: string avatar?: string - role: string + user_type: string status: 'active' | 'inactive' | 'banned' createdAt: string updatedAt: string @@ -29,7 +29,7 @@ export interface UserListParams { page?: number pageSize?: number keyword?: string - role?: string + user_type?: string status?: string } diff --git a/admin-system/src/views/user/index.vue b/admin-system/src/views/user/index.vue index 80e6b4a..39d6897 100644 --- a/admin-system/src/views/user/index.vue +++ b/admin-system/src/views/user/index.vue @@ -443,7 +443,7 @@ const handleSubmit = async () => { username: form.username, email: form.email, phone: form.phone, - role: form.role, + user_type: form.role, // 将前端的role映射到后端的user_type status: form.status } await updateUser(form.id, updateData) @@ -454,7 +454,7 @@ const handleSubmit = async () => { email: form.email, phone: form.phone, password: form.password, - role: form.role, + user_type: form.role, // 将前端的role映射到后端的user_type status: form.status } await createUser(createData) diff --git a/apache-maven-3.9.6-bin.tar.gz b/apache-maven-3.9.6-bin.tar.gz deleted file mode 100644 index 6bdb663..0000000 --- a/apache-maven-3.9.6-bin.tar.gz +++ /dev/null @@ -1,7 +0,0 @@ - - -404 Not Found - -

Not Found

-

The requested URL was not found on this server.

- diff --git a/backend/create_test_orders.js b/backend/create_test_orders.js new file mode 100644 index 0000000..1788aca --- /dev/null +++ b/backend/create_test_orders.js @@ -0,0 +1,107 @@ +// 创建测试订单数据 +const { Order } = require('./models'); + +const createTestOrders = async () => { + try { + // 测试数据库连接 + const { testConnection } = require('./models'); + const connected = await testConnection(); + + if (!connected) { + console.error('数据库连接失败,无法创建测试数据'); + return; + } + + // 同步模型 + await Order.sync({ force: false }); + console.log('✅ 订单表同步成功'); + + // 检查是否已有数据 + const existingCount = await Order.count(); + if (existingCount > 0) { + console.log(`已存在 ${existingCount} 条订单记录`); + return; + } + + // 创建测试订单 + const testOrders = [ + { + orderNo: 'ORD20240101001', + buyerId: 1, + buyerName: '测试采购商A', + supplierId: 1, + supplierName: '山东畜牧合作社', + cattleBreed: '西门塔尔牛', + cattleCount: 50, + expectedWeight: 25000.00, + unitPrice: 28.50, + totalAmount: 712500.00, + paidAmount: 200000.00, + remainingAmount: 512500.00, + status: 'pending', + deliveryAddress: '山东省济南市历下区测试地址1号', + expectedDeliveryDate: new Date('2024-02-01'), + notes: '优质西门塔尔牛,要求健康证明齐全' + }, + { + orderNo: 'ORD20240101002', + buyerId: 2, + buyerName: '测试采购商B', + supplierId: 2, + supplierName: '河北养殖基地', + cattleBreed: '安格斯牛', + cattleCount: 30, + expectedWeight: 18000.00, + unitPrice: 32.00, + totalAmount: 576000.00, + paidAmount: 576000.00, + remainingAmount: 0.00, + status: 'confirmed', + deliveryAddress: '河北省石家庄市长安区测试地址2号', + expectedDeliveryDate: new Date('2024-01-25'), + actualDeliveryDate: new Date('2024-01-24'), + notes: '已完成支付,请按时交付' + }, + { + orderNo: 'ORD20240101003', + buyerId: 1, + buyerName: '测试采购商A', + supplierId: 3, + supplierName: '内蒙古牧场', + cattleBreed: '蒙古牛', + cattleCount: 80, + expectedWeight: 32000.00, + unitPrice: 26.00, + totalAmount: 832000.00, + paidAmount: 300000.00, + remainingAmount: 532000.00, + status: 'shipping', + deliveryAddress: '内蒙古呼和浩特市赛罕区测试地址3号', + expectedDeliveryDate: new Date('2024-02-10'), + notes: '大批量订单,分批交付' + } + ]; + + // 批量创建订单 + const createdOrders = await Order.bulkCreate(testOrders); + console.log(`✅ 成功创建 ${createdOrders.length} 条测试订单`); + + // 显示创建的订单 + createdOrders.forEach(order => { + console.log(`- ${order.orderNo}: ${order.cattleCount}头${order.cattleBreed} (${order.status})`); + }); + + } catch (error) { + console.error('❌ 创建测试订单失败:', error); + } +}; + +// 如果直接运行此文件 +if (require.main === module) { + createTestOrders().then(() => { + console.log('测试数据创建完成'); + process.exit(0); + }); +} + +module.exports = createTestOrders; \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index 373cfd0..6f6a0c0 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -44,7 +44,6 @@ "nodemon": "^3.0.2", "prettier": "^3.1.0", "sequelize-cli": "^6.6.2", - "sqlite3": "^5.1.7", "supertest": "^6.3.3" }, "engines": { @@ -770,14 +769,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -1495,48 +1486,6 @@ "node": ">= 8" } }, - "node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "@gar/promisify": "^1.0.1", - "semver": "^7.3.5" - } - }, - "node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/move-file/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "optional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@one-ini/wasm": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz", @@ -1640,17 +1589,6 @@ "@sinonjs/commons": "^3.0.0" } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1899,35 +1837,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2384,27 +2293,6 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/baseline-browser-mapping": { "version": "2.8.6", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.6.tgz", @@ -2451,7 +2339,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==", - "license": "BSD-3-Clause", "bin": { "bcrypt": "bin/bcrypt" } @@ -2469,43 +2356,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", @@ -2604,31 +2454,6 @@ "node-int64": "^0.4.0" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -2686,87 +2511,6 @@ "node": ">= 0.8" } }, - "node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacache/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "optional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cacache/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC", - "optional": true - }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", @@ -2959,17 +2703,6 @@ "dev": true, "license": "MIT" }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=6" - } - }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3346,22 +3079,6 @@ "ms": "2.0.0" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/dedent": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", @@ -3377,16 +3094,6 @@ } } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -3682,6 +3389,7 @@ "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "iconv-lite": "^0.6.2" } @@ -3692,6 +3400,7 @@ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "license": "MIT", "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -3699,35 +3408,6 @@ "node": ">=0.10.0" } }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -4519,16 +4199,6 @@ "node": ">= 0.8.0" } }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "license": "(MIT OR WTFPL)", - "engines": { - "node": ">=6" - } - }, "node_modules/expect": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", @@ -4703,13 +4373,6 @@ "moment": "^2.29.1" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "license": "MIT" - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -4883,13 +4546,6 @@ "node": ">= 0.6" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "license": "MIT" - }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -5139,13 +4795,6 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true, - "license": "MIT" - }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -5353,14 +5002,6 @@ "dev": true, "license": "MIT" }, - "node_modules/http-cache-semantics": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", - "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", - "dev": true, - "license": "BSD-2-Clause", - "optional": true - }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -5377,49 +5018,6 @@ "node": ">= 0.8" } }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/http-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -5466,17 +5064,6 @@ "node": ">=10.17.0" } }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ms": "^2.0.0" - } - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -5489,27 +5076,6 @@ "node": ">=0.10.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5574,25 +5140,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true, - "license": "ISC", - "optional": true - }, "node_modules/inflection": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz", @@ -5641,17 +5188,6 @@ "node": ">= 0.4" } }, - "node_modules/ip-address": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz", - "integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -5910,14 +5446,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -7357,71 +6885,6 @@ "semver": "bin/semver.js" } }, - "node_modules/make-fetch-happen": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", - "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "agentkeepalive": "^4.1.3", - "cacache": "^15.2.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^6.0.0", - "minipass": "^3.1.3", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^1.3.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.2", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^6.0.0", - "ssri": "^8.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-fetch-happen/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/make-fetch-happen/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC", - "optional": true - }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -7541,19 +7004,6 @@ "node": ">=6" } }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -7584,191 +7034,6 @@ "node": ">=8" } }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-collect/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, - "node_modules/minipass-fetch/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-fetch/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC", - "optional": true - }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -7812,13 +7077,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true, - "license": "MIT" - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -7950,13 +7208,6 @@ "node": ">=12" } }, - "node_modules/napi-build-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", - "dev": true, - "license": "MIT" - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7973,19 +7224,6 @@ "node": ">= 0.6" } }, - "node_modules/node-abi": { - "version": "3.77.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.77.0.tgz", - "integrity": "sha512-DSmt0OEcLoK4i3NuscSbGjOf3bqiDEutejqENSplMSFA/gmB8mkED9G4pKWnPl7MDU4rSHebKPHeitpDfyH0cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-addon-api": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", @@ -8012,104 +7250,6 @@ } } }, - "node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">= 10.12.0" - } - }, - "node_modules/node-gyp/node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/node-gyp/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -8496,23 +7636,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -8752,33 +7875,6 @@ "node": ">= 0.4" } }, - "node_modules/prebuild-install": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -8852,29 +7948,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true, - "license": "ISC", - "optional": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -8916,17 +7989,6 @@ "dev": true, "license": "MIT" }, - "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -9014,32 +8076,6 @@ "node": ">= 0.8" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", @@ -9223,17 +8259,6 @@ "node": ">=10" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/retry-as-promised": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-7.1.1.tgz", @@ -9795,53 +8820,6 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "license": "ISC" }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/simple-swizzle": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.4.tgz", @@ -9887,77 +8865,6 @@ "node": ">=8" } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.7", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", - "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/socks-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT", - "optional": true - }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9985,38 +8892,6 @@ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "license": "BSD-3-Clause" }, - "node_modules/sqlite3": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", - "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", - "dev": true, - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "bindings": "^1.5.0", - "node-addon-api": "^7.0.0", - "prebuild-install": "^7.1.1", - "tar": "^6.1.11" - }, - "optionalDependencies": { - "node-gyp": "8.x" - }, - "peerDependencies": { - "node-gyp": "8.x" - }, - "peerDependenciesMeta": { - "node-gyp": { - "optional": true - } - } - }, - "node_modules/sqlite3/node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, - "license": "MIT" - }, "node_modules/sqlstring": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", @@ -10026,42 +8901,6 @@ "node": ">= 0.6" } }, - "node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/ssri/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ssri/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC", - "optional": true - }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -10523,58 +9362,6 @@ "node": ">=10" } }, - "node_modules/tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "license": "ISC" - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/tar/node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -10717,19 +9504,6 @@ "node": ">=4" } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -10908,28 +9682,6 @@ "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==", "license": "MIT" }, - "node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, - "license": "ISC", - "optional": true, - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", @@ -11395,7 +10147,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", - "license": "MIT", "dependencies": { "argparse": "^1.0.7", "glob": "^7.0.5" @@ -11409,7 +10160,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } diff --git a/backend/package.json b/backend/package.json index 00e74aa..362d7c7 100644 --- a/backend/package.json +++ b/backend/package.json @@ -31,40 +31,42 @@ "author": "NiuMall Team", "license": "MIT", "dependencies": { - "express": "^4.18.2", - "sequelize": "^6.35.2", - "mysql2": "^3.6.5", "bcrypt": "^5.1.1", - "jsonwebtoken": "^9.0.2", - "joi": "^17.11.0", - "cors": "^2.8.5", - "helmet": "^7.1.0", - "express-rate-limit": "^7.1.5", + "bcryptjs": "^3.0.2", "compression": "^1.7.4", - "morgan": "^1.10.0", - "winston": "^3.11.0", - "winston-daily-rotate-file": "^4.7.1", + "cors": "^2.8.5", "dotenv": "^16.3.1", + "express": "^4.18.2", + "express-rate-limit": "^7.1.5", + "express-validator": "^7.0.1", + "helmet": "^7.1.0", + "joi": "^17.11.0", + "jsonwebtoken": "^9.0.2", + "moment": "^2.29.4", + "morgan": "^1.10.0", "multer": "^1.4.5-lts.1", + "mysql2": "^3.6.5", + "sequelize": "^6.35.2", "swagger-jsdoc": "^6.2.8", "swagger-ui-express": "^5.0.0", - "express-validator": "^7.0.1", - "moment": "^2.29.4", - "uuid": "^9.0.1" + "uuid": "^9.0.1", + "winston": "^3.11.0", + "winston-daily-rotate-file": "^4.7.1", + "yamljs": "^0.3.0" }, "devDependencies": { - "nodemon": "^3.0.2", - "jest": "^29.7.0", - "supertest": "^6.3.3", "eslint": "^8.55.0", + "eslint-config-prettier": "^9.1.0", "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.29.0", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.1.1", - "prettier": "^3.1.0", - "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.0.1", - "sequelize-cli": "^6.6.2" + "eslint-plugin-promise": "^6.1.1", + "jest": "^29.7.0", + "nodemon": "^3.0.2", + "prettier": "^3.1.0", + "sequelize-cli": "^6.6.2", + "supertest": "^6.3.3" }, "jest": { "testEnvironment": "node", diff --git a/backend/src/controllers/OrderController.js b/backend/src/controllers/OrderController.js index c6ba619..ebcdeac 100644 --- a/backend/src/controllers/OrderController.js +++ b/backend/src/controllers/OrderController.js @@ -1,5 +1,5 @@ const { successResponse, errorResponse, paginatedResponse } = require('../utils/response'); -const Order = require('../models/Order'); +const { Order } = require('../../models'); // 创建订单 const createOrder = async (req, res) => { @@ -51,13 +51,13 @@ const getOrderList = async (req, res) => { // 根据用户类型过滤 if (req.user.userType === 'client') { - whereConditions.buyer_id = req.user.id; + whereConditions.buyerId = req.user.id; } else if (req.user.userType === 'trader') { - whereConditions.trader_id = req.user.id; + whereConditions.traderId = req.user.id; } else if (req.user.userType === 'supplier') { - whereConditions.supplier_id = req.user.id; + whereConditions.supplierId = req.user.id; } else if (req.user.userType === 'driver') { - whereConditions.driver_id = req.user.id; + whereConditions.driverId = req.user.id; } if (status) whereConditions.status = status; @@ -71,7 +71,18 @@ const getOrderList = async (req, res) => { order: [['created_at', 'DESC']] }); - res.json(paginatedResponse(rows, count, parseInt(page), parseInt(pageSize))); + // 格式化返回数据以匹配前端期望的格式 + res.json({ + success: true, + data: { + items: rows, + total: count, + page: parseInt(page), + pageSize: parseInt(pageSize), + totalPages: Math.ceil(count / parseInt(pageSize)) + }, + message: '获取订单列表成功' + }); } catch (error) { console.error('获取订单列表错误:', error); res.status(500).json(errorResponse('服务器内部错误', 500)); @@ -90,19 +101,19 @@ const getOrderDetail = async (req, res) => { } // 权限检查 - if (req.user.userType === 'client' && order.buyer_id !== req.user.id) { + if (req.user.userType === 'client' && order.buyerId !== req.user.id) { return res.status(403).json(errorResponse('无权限访问该订单', 403)); } - if (req.user.userType === 'trader' && order.trader_id !== req.user.id) { + if (req.user.userType === 'trader' && order.traderId !== req.user.id) { return res.status(403).json(errorResponse('无权限访问该订单', 403)); } - if (req.user.userType === 'supplier' && order.supplier_id !== req.user.id) { + if (req.user.userType === 'supplier' && order.supplierId !== req.user.id) { return res.status(403).json(errorResponse('无权限访问该订单', 403)); } - if (req.user.userType === 'driver' && order.driver_id !== req.user.id) { + if (req.user.userType === 'driver' && order.driverId !== req.user.id) { return res.status(403).json(errorResponse('无权限访问该订单', 403)); } diff --git a/backend/src/controllers/UserController.js b/backend/src/controllers/UserController.js index 68f46fa..88e8293 100644 --- a/backend/src/controllers/UserController.js +++ b/backend/src/controllers/UserController.js @@ -29,7 +29,7 @@ const getUserList = async (req, res) => { email: user.email, userType: user.user_type, status: user.status, - avatar: user.avatar_url, + avatar: user.avatar, createdAt: user.created_at })); @@ -60,12 +60,8 @@ const getUserDetail = async (req, res) => { email: user.email, userType: user.user_type, status: user.status, - avatar: user.avatar_url, - idCardFront: user.id_card_front_url, - idCardBack: user.id_card_back_url, - licenseFront: user.license_front_url, - licenseBack: user.license_back_url, - businessLicense: user.business_license_url, + avatar: user.avatar, + businessLicense: user.business_license, createdAt: user.created_at, updatedAt: user.updated_at }; @@ -84,7 +80,7 @@ const updateUser = async (req, res) => { const updateData = req.body; // 过滤不允许更新的字段 - const allowedFields = ['real_name', 'email', 'avatar_url']; + const allowedFields = ['username', 'real_name', 'email', 'avatar']; const filteredData = {}; Object.keys(updateData).forEach(key => { if (allowedFields.includes(key)) { diff --git a/backend/src/main.js b/backend/src/main.js index 7a139ba..d3ae557 100644 --- a/backend/src/main.js +++ b/backend/src/main.js @@ -65,6 +65,7 @@ app.use(cors({ origin: [ 'http://localhost:3000', 'http://localhost:3001', + 'http://localhost:3002', 'http://localhost:5173', 'https://wapi.nanniwan.com', 'https://ad.nanniwan.com', diff --git a/backend/src/middleware/auth.js b/backend/src/middleware/auth.js index c67c112..2dca518 100644 --- a/backend/src/middleware/auth.js +++ b/backend/src/middleware/auth.js @@ -24,7 +24,11 @@ const authenticateToken = (req, res, next) => { // 从请求头获取token const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { - return errorResponse(res, '未提供认证token', 401); + return res.status(401).json({ + success: false, + message: '未提供认证token', + code: 'AUTH_TOKEN_MISSING' + }); } const token = authHeader.split(' ')[1]; @@ -35,11 +39,23 @@ const authenticateToken = (req, res, next) => { next(); } catch (error) { if (error.name === 'TokenExpiredError') { - return errorResponse(res, 'Token已过期', 401); + return res.status(401).json({ + success: false, + message: 'Token已过期', + code: 'AUTH_TOKEN_EXPIRED' + }); } else if (error.name === 'JsonWebTokenError') { - return errorResponse(res, '无效的Token', 401); + return res.status(401).json({ + success: false, + message: '无效的Token', + code: 'AUTH_INVALID_TOKEN' + }); } - return errorResponse(res, '认证失败', 401); + return res.status(401).json({ + success: false, + message: '认证失败', + code: 'AUTH_FAILED' + }); } }; diff --git a/backend/src/routes/auth.js b/backend/src/routes/auth.js index 16e2f2f..497a482 100644 --- a/backend/src/routes/auth.js +++ b/backend/src/routes/auth.js @@ -11,6 +11,7 @@ router.post('/mini-program/login', AuthController.miniProgramLogin); // 获取当前用户信息 router.get('/current', authenticate, AuthController.getCurrentUser); +router.get('/me', authenticate, AuthController.getCurrentUser); // 用户登出 router.post('/logout', authenticate, async (req, res) => { diff --git a/backend/src/routes/orders.js b/backend/src/routes/orders.js index bd15197..7a083e9 100644 --- a/backend/src/routes/orders.js +++ b/backend/src/routes/orders.js @@ -3,6 +3,15 @@ const router = express.Router(); const OrderController = require('../controllers/OrderController'); const { authenticate } = require('../middleware/auth'); +// 测试接口 - 不需要认证 +router.get('/test', (req, res) => { + res.json({ + success: true, + message: '订单API测试成功', + timestamp: new Date().toISOString() + }); +}); + // 创建订单 router.post('/', authenticate, OrderController.createOrder); diff --git a/backend/src/services/UserService.js b/backend/src/services/UserService.js index d57dbb0..2794e54 100644 --- a/backend/src/services/UserService.js +++ b/backend/src/services/UserService.js @@ -67,7 +67,7 @@ const getUserDetail = async (id) => { // 更新用户信息服务 const updateUser = async (id, updateData) => { // 过滤不允许更新的字段 - const allowedFields = ['real_name', 'email', 'avatar_url']; + const allowedFields = ['real_name', 'avatar_url']; const filteredData = {}; Object.keys(updateData).forEach(key => { if (allowedFields.includes(key)) { diff --git a/backend/test_user_update.js b/backend/test_user_update.js new file mode 100644 index 0000000..1cbe4ea --- /dev/null +++ b/backend/test_user_update.js @@ -0,0 +1,65 @@ +const sequelize = require('./src/config/database'); +const { User } = require('./src/models'); + +// 使用环境变量中的数据库配置 +const config = { + host: process.env.DB_HOST || 'nj-cdb-3pwh2kz1.sql.tencentcdb.com', + port: process.env.DB_PORT || 20784, + username: process.env.DB_USERNAME || 'jiebanke', + password: process.env.DB_PASSWORD || 'aiot741$12346', + database: process.env.DB_NAME || 'niumall' +}; + +async function testUserUpdate() { + try { + console.log('测试用户编辑功能...'); + + // 连接到腾讯云数据库 + await sequelize.authenticate(); + console.log('数据库连接成功'); + + // 获取一个测试用户 + const testUser = await User.findOne(); + if (!testUser) { + console.log('没有找到测试用户,请先创建用户数据'); + return; + } + + console.log('原始用户数据:', { + id: testUser.id, + username: testUser.username, + email: testUser.email + }); + + // 更新用户信息 + const updateData = { + username: 'test_updated_' + Date.now(), + email: 'updated_' + Date.now() + '@example.com' + }; + + const [updatedRows] = await User.update(updateData, { + where: { id: testUser.id } + }); + + if (updatedRows > 0) { + console.log('用户更新成功,更新行数:', updatedRows); + + // 验证更新结果 + const updatedUser = await User.findByPk(testUser.id); + console.log('更新后的用户数据:', { + id: updatedUser.id, + username: updatedUser.username, + email: updatedUser.email + }); + + console.log('用户编辑功能测试通过!'); + } else { + console.log('用户更新失败,没有行被更新'); + } + + } catch (error) { + console.error('测试过程中出错:', error.message); + } +} + +testUserUpdate(); \ No newline at end of file diff --git a/backend/test_user_update_fixed.js b/backend/test_user_update_fixed.js new file mode 100644 index 0000000..bef5208 --- /dev/null +++ b/backend/test_user_update_fixed.js @@ -0,0 +1,217 @@ +// 使用腾讯云数据库配置进行测试 +const { Sequelize, DataTypes } = require('sequelize'); + +const config = { + host: 'nj-cdb-3pwh2kz1.sql.tencentcdb.com', + port: 20784, + username: 'jiebanke', + password: 'aiot741$12346', + database: 'niumall', + dialect: 'mysql', + dialectOptions: { + charset: 'utf8mb4', + collate: 'utf8mb4_general_ci' + }, + logging: console.log +}; + +const sequelize = new Sequelize(config); + +// 定义用户模型(与数据库表结构一致) +const User = sequelize.define('User', { + id: { + type: DataTypes.BIGINT, + primaryKey: true, + autoIncrement: true, + comment: '用户ID' + }, + uuid: { + type: DataTypes.STRING(36), + allowNull: true, + unique: true, + comment: '用户唯一标识符' + }, + username: { + type: DataTypes.STRING(50), + allowNull: true, + unique: true, + comment: '用户名' + }, + password_hash: { + type: DataTypes.STRING(255), + allowNull: true, + comment: '密码哈希值' + }, + openid: { + type: DataTypes.STRING(64), + allowNull: true, + comment: '微信小程序OpenID' + }, + unionid: { + type: DataTypes.STRING(64), + allowNull: true, + comment: '微信UnionID' + }, + nickname: { + type: DataTypes.STRING(50), + allowNull: false, + comment: '用户昵称' + }, + real_name: { + type: DataTypes.STRING(50), + allowNull: true, + comment: '真实姓名' + }, + avatar: { + type: DataTypes.STRING(255), + allowNull: true, + comment: '头像URL' + }, + gender: { + type: DataTypes.ENUM('male', 'female', 'other'), + allowNull: true, + comment: '性别' + }, + birthday: { + type: DataTypes.DATE, + allowNull: true, + comment: '生日' + }, + phone: { + type: DataTypes.STRING(20), + allowNull: true, + unique: true, + comment: '手机号码' + }, + email: { + type: DataTypes.STRING(100), + allowNull: true, + unique: true, + comment: '邮箱地址' + }, + user_type: { + type: DataTypes.ENUM('buyer', 'trader', 'supplier', 'driver', 'staff', 'admin'), + allowNull: false, + defaultValue: 'buyer', + comment: '用户类型' + }, + company_name: { + type: DataTypes.STRING(100), + allowNull: true, + comment: '公司名称' + }, + company_address: { + type: DataTypes.STRING(200), + allowNull: true, + comment: '公司地址' + }, + business_license: { + type: DataTypes.STRING(255), + allowNull: true, + comment: '营业执照文件路径' + }, + id_card: { + type: DataTypes.STRING(18), + allowNull: true, + comment: '身份证号' + }, + status: { + type: DataTypes.ENUM('active', 'inactive', 'suspended', 'pending_approval'), + allowNull: false, + defaultValue: 'pending_approval', + comment: '用户状态' + }, + last_login_at: { + type: DataTypes.DATE, + allowNull: true, + comment: '最后登录时间' + }, + login_count: { + type: DataTypes.INTEGER, + allowNull: false, + defaultValue: 0, + comment: '登录次数' + }, + registration_source: { + type: DataTypes.ENUM('miniprogram', 'web', 'admin_create'), + allowNull: false, + defaultValue: 'miniprogram', + comment: '注册来源' + }, + approval_notes: { + type: DataTypes.TEXT, + allowNull: true, + comment: '审核备注' + }, + created_at: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW, + comment: '创建时间' + }, + updated_at: { + type: DataTypes.DATE, + allowNull: false, + defaultValue: DataTypes.NOW, + comment: '更新时间' + } +}, { + tableName: 'users', + timestamps: false +}); + +async function testUserUpdate() { + try { + console.log('测试用户编辑功能...'); + + // 连接到腾讯云数据库 + await sequelize.authenticate(); + console.log('数据库连接成功'); + + // 获取一个测试用户 + const testUser = await User.findOne(); + if (!testUser) { + console.log('没有找到测试用户,请先创建用户数据'); + return; + } + + console.log('原始用户数据:', { + id: testUser.id, + username: testUser.username, + email: testUser.email + }); + + // 更新用户信息 + const updateData = { + username: 'test_updated_' + Date.now(), + email: 'updated_' + Date.now() + '@example.com' + }; + + const [updatedRows] = await User.update(updateData, { + where: { id: testUser.id } + }); + + if (updatedRows > 0) { + console.log('用户更新成功,更新行数:', updatedRows); + + // 验证更新结果 + const updatedUser = await User.findByPk(testUser.id); + console.log('更新后的用户数据:', { + id: updatedUser.id, + username: updatedUser.username, + email: updatedUser.email + }); + + console.log('用户编辑功能测试通过!'); + } else { + console.log('用户更新失败,没有行被更新'); + } + + } catch (error) { + console.error('测试过程中出错:', error.message); + } finally { + await sequelize.close(); + } +} + +testUserUpdate(); \ No newline at end of file diff --git a/docs/API接口文档.md b/docs/API接口文档.md index 7a5615c..d8fec8a 100644 --- a/docs/API接口文档.md +++ b/docs/API接口文档.md @@ -1608,25 +1608,53 @@ def get_transport_task(task_id): return None ``` -## 13. 测试环境 +## 13. 环境配置 -### 13.1 测试环境信息 +### 13.1 环境信息 -- **测试环境URL**: `https://api-test.niumall.com/v1` -- **测试账号**: - - 采购人: test_client / 123456 - - 供应商: test_supplier / 123456 - - 司机: test_driver / 123456 - - 管理员: test_admin / 123456 +- **本地开发环境**: `http://localhost:4330` +- **测试环境**: `https://api-test.niumall.com/v1` +- **生产环境**: `https://wapi.yunniushi.cn/v1` -### 13.2 Postman集合 +### 13.2 测试账号 + +- **采购人**: test_client / 123456 +- **供应商**: test_supplier / 123456 +- **司机**: test_driver / 123456 +- **管理员**: test_admin / 123456 + +### 13.3 环境切换配置 + +```javascript +// 环境配置示例 +const environments = { + development: { + baseURL: 'http://localhost:4330', + apiVersion: 'v1' + }, + test: { + baseURL: 'https://api-test.niumall.com/v1', + apiVersion: 'v1' + }, + production: { + baseURL: 'https://wapi.yunniushi.cn/v1', + apiVersion: 'v1' + } +}; + +// 根据环境变量切换配置 +const currentEnv = process.env.NODE_ENV || 'development'; +const config = environments[currentEnv]; +``` + +### 13.4 Postman集合 我们提供了完整的Postman集合,包含所有API接口的测试用例: - **集合下载**: [Niumall API Collection](https://api.niumall.com/docs/postman/collection.json) - **环境配置**: [Niumall API Environment](https://api.niumall.com/docs/postman/environment.json) -### 13.3 API测试工具 +### 13.5 API测试工具 推荐使用以下工具进行API测试: diff --git a/docs/API接口文档更新.md b/docs/API接口文档更新.md deleted file mode 100644 index d00fe80..0000000 --- a/docs/API接口文档更新.md +++ /dev/null @@ -1,544 +0,0 @@ -# 牛商城后端系统 - API接口文档 (更新版) - -## 版本历史 -| 版本 | 日期 | 作者 | 变更说明 | -|------|------|------|----------| -| v1.0 | 2024-12-20 | API架构师 | 初版API接口文档 | -| v1.1 | 2025-01-20 | 系统工程师 | 基于实际代码实现更新文档 | - -## 1. API概览 - -### 1.1 基础信息 - -- **Base URL**: `http://localhost:3000/api` (开发环境) -- **协议**: HTTP/HTTPS -- **数据格式**: JSON -- **字符编码**: UTF-8 -- **API版本**: v1 - -### 1.2 认证方式 - -#### JWT Token认证 -```http -Authorization: Bearer -``` - -#### 认证流程 -1. 用户登录获取access_token -2. 请求头携带access_token -3. token过期需重新登录 - -### 1.3 通用响应格式 - -#### 成功响应 -```json -{ - "success": true, - "message": "操作成功", - "data": { - // 具体数据 - } -} -``` - -#### 分页响应 -```json -{ - "success": true, - "message": "获取成功", - "data": { - "list": [], - "total": 100, - "page": 1, - "pageSize": 10 - } -} -``` - -#### 错误响应 -```json -{ - "success": false, - "message": "错误描述", - "code": 400 -} -``` - -### 1.4 状态码说明 - -| 状态码 | 说明 | 描述 | -|--------|------|------| -| 200 | OK | 请求成功 | -| 400 | Bad Request | 请求参数错误 | -| 401 | Unauthorized | 未授权,需要登录 | -| 403 | Forbidden | 禁止访问,权限不足 | -| 404 | Not Found | 资源不存在 | -| 500 | Internal Server Error | 服务器内部错误 | - -## 2. 认证模块 (AuthController) - -### 2.1 用户登录 - -#### 接口信息 -- **URL**: `/auth/login` -- **Method**: `POST` -- **描述**: 用户登录接口,支持用户名/邮箱登录 -- **认证**: 不需要 - -#### 请求参数 -```json -{ - "username": "admin", - "password": "123456" -} -``` - -#### 参数说明 -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| username | string | 是 | 用户名或邮箱 | -| password | string | 是 | 密码 | - -#### 响应示例 -```json -{ - "success": true, - "message": "登录成功", - "data": { - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "user": { - "id": 1, - "uuid": "550e8400-e29b-41d4-a716-446655440000", - "username": "admin", - "userType": "admin", - "email": "admin@example.com" - } - } -} -``` - -### 2.2 小程序登录 - -#### 接口信息 -- **URL**: `/auth/miniprogram-login` -- **Method**: `POST` -- **描述**: 微信小程序登录接口 -- **认证**: 不需要 - -#### 请求参数 -```json -{ - "code": "wx_code_from_miniprogram", - "userInfo": { - "nickName": "用户昵称", - "avatarUrl": "头像URL" - } -} -``` - -### 2.3 获取当前用户信息 - -#### 接口信息 -- **URL**: `/auth/current-user` -- **Method**: `GET` -- **描述**: 获取当前登录用户信息 -- **认证**: 需要 - -#### 响应示例 -```json -{ - "success": true, - "message": "获取成功", - "data": { - "id": 1, - "uuid": "550e8400-e29b-41d4-a716-446655440000", - "username": "admin", - "userType": "admin", - "email": "admin@example.com" - } -} -``` - -## 3. 用户管理模块 (UserController) - -### 3.1 获取用户列表 - -#### 接口信息 -- **URL**: `/users` -- **Method**: `GET` -- **描述**: 获取用户列表,支持分页和筛选 -- **认证**: 需要 - -#### 查询参数 -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| page | integer | 否 | 页码,默认1 | -| pageSize | integer | 否 | 每页数量,默认10 | -| userType | string | 否 | 用户类型筛选 | -| status | string | 否 | 用户状态筛选 | - -#### 响应示例 -```json -{ - "success": true, - "message": "获取成功", - "data": { - "list": [ - { - "id": 1, - "uuid": "550e8400-e29b-41d4-a716-446655440000", - "username": "admin", - "realName": "管理员", - "phone": "13800138000", - "email": "admin@example.com", - "userType": "admin", - "status": "active", - "avatar": "https://example.com/avatar.jpg", - "createdAt": "2024-01-01T00:00:00.000Z" - } - ], - "total": 1, - "page": 1, - "pageSize": 10 - } -} -``` - -### 3.2 获取用户详情 - -#### 接口信息 -- **URL**: `/users/{id}` -- **Method**: `GET` -- **描述**: 根据用户ID获取用户详细信息 -- **认证**: 需要 - -#### 路径参数 -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| id | integer | 是 | 用户ID | - -#### 响应示例 -```json -{ - "success": true, - "message": "获取成功", - "data": { - "id": 1, - "uuid": "550e8400-e29b-41d4-a716-446655440000", - "username": "admin", - "realName": "管理员", - "phone": "13800138000", - "email": "admin@example.com", - "userType": "admin", - "status": "active", - "avatar": "https://example.com/avatar.jpg", - "createdAt": "2024-01-01T00:00:00.000Z", - "updatedAt": "2024-01-01T00:00:00.000Z" - } -} -``` - -### 3.3 更新用户信息 - -#### 接口信息 -- **URL**: `/users/{id}` -- **Method**: `PUT` -- **描述**: 更新用户基本信息 -- **认证**: 需要 - -#### 路径参数 -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| id | integer | 是 | 用户ID | - -#### 请求参数 -```json -{ - "realName": "新的真实姓名", - "phone": "13900139000", - "email": "newemail@example.com", - "avatar": "https://example.com/new-avatar.jpg" -} -``` - -#### 响应示例 -```json -{ - "success": true, - "message": "更新成功", - "data": { - "id": 1, - "realName": "新的真实姓名", - "phone": "13900139000", - "email": "newemail@example.com", - "avatar": "https://example.com/new-avatar.jpg", - "updatedAt": "2024-01-20T10:30:00.000Z" - } -} -``` - -### 3.4 更新用户状态 - -#### 接口信息 -- **URL**: `/users/{id}/status` -- **Method**: `PUT` -- **描述**: 更新用户状态(启用/禁用) -- **认证**: 需要 - -#### 路径参数 -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| id | integer | 是 | 用户ID | - -#### 请求参数 -```json -{ - "status": "inactive" -} -``` - -#### 参数说明 -| 参数 | 类型 | 必填 | 说明 | -|------|------|------|------| -| status | string | 是 | 用户状态:active(启用)、inactive(禁用) | - -#### 响应示例 -```json -{ - "success": true, - "message": "状态更新成功", - "data": { - "id": 1, - "status": "inactive", - "updatedAt": "2024-01-20T10:30:00.000Z" - } -} -``` - -## 4. 运输管理模块 (TransportController) - -### 4.1 获取运输列表 - -#### 接口信息 -- **URL**: `/transports` -- **Method**: `GET` -- **描述**: 获取运输记录列表 -- **认证**: 需要 - -### 4.2 获取运输详情 - -#### 接口信息 -- **URL**: `/transports/{id}` -- **Method**: `GET` -- **描述**: 获取运输记录详情 -- **认证**: 需要 - -### 4.3 更新运输状态 - -#### 接口信息 -- **URL**: `/transports/{id}/status` -- **Method**: `PUT` -- **描述**: 更新运输状态 -- **认证**: 需要 - -### 4.4 获取运输统计 - -#### 接口信息 -- **URL**: `/transports/stats` -- **Method**: `GET` -- **描述**: 获取运输统计数据 -- **认证**: 需要 - -## 5. 订单管理模块 (OrderController) - -### 5.1 获取订单列表 - -#### 接口信息 -- **URL**: `/orders` -- **Method**: `GET` -- **描述**: 获取订单列表 -- **认证**: 需要 - -### 5.2 创建订单 - -#### 接口信息 -- **URL**: `/orders` -- **Method**: `POST` -- **描述**: 创建新订单 -- **认证**: 需要 - -### 5.3 获取订单详情 - -#### 接口信息 -- **URL**: `/orders/{id}` -- **Method**: `GET` -- **描述**: 获取订单详情 -- **认证**: 需要 - -### 5.4 更新订单状态 - -#### 接口信息 -- **URL**: `/orders/{id}/status` -- **Method**: `PUT` -- **描述**: 更新订单状态 -- **认证**: 需要 - -## 6. 供应商管理模块 (SupplierController) - -### 6.1 获取供应商列表 - -#### 接口信息 -- **URL**: `/suppliers` -- **Method**: `GET` -- **描述**: 获取供应商列表 -- **认证**: 需要 - -### 6.2 获取供应商详情 - -#### 接口信息 -- **URL**: `/suppliers/{id}` -- **Method**: `GET` -- **描述**: 获取供应商详情 -- **认证**: 需要 - -### 6.3 获取供应商统计 - -#### 接口信息 -- **URL**: `/suppliers/stats` -- **Method**: `GET` -- **描述**: 获取供应商统计数据 -- **认证**: 需要 - -## 7. 司机管理模块 (DriverController) - -### 7.1 获取司机列表 - -#### 接口信息 -- **URL**: `/drivers` -- **Method**: `GET` -- **描述**: 获取司机列表 -- **认证**: 需要 - -### 7.2 获取司机详情 - -#### 接口信息 -- **URL**: `/drivers/{id}` -- **Method**: `GET` -- **描述**: 获取司机详情 -- **认证**: 需要 - -### 7.3 获取司机统计 - -#### 接口信息 -- **URL**: `/drivers/stats` -- **Method**: `GET` -- **描述**: 获取司机统计数据 -- **认证**: 需要 - -## 8. 车辆管理模块 (VehicleController) - -### 8.1 获取车辆列表 - -#### 接口信息 -- **URL**: `/vehicles` -- **Method**: `GET` -- **描述**: 获取车辆列表 -- **认证**: 需要 - -### 8.2 获取车辆详情 - -#### 接口信息 -- **URL**: `/vehicles/{id}` -- **Method**: `GET` -- **描述**: 获取车辆详情 -- **认证**: 需要 - -## 9. 支付管理模块 (PaymentController) - -### 9.1 获取支付记录 - -#### 接口信息 -- **URL**: `/payments` -- **Method**: `GET` -- **描述**: 获取支付记录列表 -- **认证**: 需要 - -### 9.2 创建支付订单 - -#### 接口信息 -- **URL**: `/payments` -- **Method**: `POST` -- **描述**: 创建支付订单 -- **认证**: 需要 - -## 10. 错误码说明 - -### 10.1 通用错误码 - -| 错误码 | 说明 | 描述 | -|--------|------|------| -| 400 | 请求参数错误 | 请求参数格式不正确或缺少必要参数 | -| 401 | 未授权 | 用户未登录或token无效 | -| 403 | 权限不足 | 用户没有访问该资源的权限 | -| 404 | 资源不存在 | 请求的资源不存在 | -| 500 | 服务器内部错误 | 服务器处理请求时发生错误 | - -### 10.2 业务错误码 - -| 错误码 | 说明 | 描述 | -|--------|------|------| -| 1001 | 用户不存在 | 指定的用户ID不存在 | -| 1002 | 用户名或密码错误 | 登录时用户名或密码不正确 | -| 1003 | 用户已被禁用 | 用户账户已被管理员禁用 | -| 2001 | 订单不存在 | 指定的订单ID不存在 | -| 2002 | 订单状态错误 | 订单当前状态不允许该操作 | - -## 11. 开发指南 - -### 11.1 环境配置 - -#### 开发环境 -- Node.js 18+ -- MySQL 8.0+ -- Redis 6.0+ - -#### 环境变量 -```env -NODE_ENV=development -PORT=3000 -DB_HOST=localhost -DB_PORT=3306 -DB_NAME=niumall -DB_USER=root -DB_PASSWORD=password -JWT_SECRET=your-jwt-secret -JWT_EXPIRES_IN=24h -``` - -### 11.2 测试指南 - -#### 单元测试 -```bash -npm test -- tests/unit -``` - -#### 集成测试 -```bash -npm test -- tests/integration -``` - -### 11.3 API调试工具 - -推荐使用以下工具进行API测试: -- Postman -- Insomnia -- curl -- Thunder Client (VS Code插件) - ---- - -**文档维护**:本文档基于实际代码实现编写,与系统保持同步更新。 - -**技术支持**:如有疑问,请联系开发团队。 - -**最后更新时间**:2025年1月20日 \ No newline at end of file diff --git a/fastapi-backend/.env b/fastapi-backend/.env deleted file mode 100644 index f4b9f40..0000000 --- a/fastapi-backend/.env +++ /dev/null @@ -1,15 +0,0 @@ -# Database configuration -DB_HOST=localhost -DB_PORT=3306 -DB_USER=root -DB_PASSWORD=your_mysql_password -DB_NAME=niumall_dev - -# JWT configuration -JWT_SECRET=niumall-jwt-secret -JWT_ALGORITHM=HS256 -JWT_EXPIRATION_MINUTES=1440 - -# Server configuration -SERVER_HOST=0.0.0.0 -SERVER_PORT=8000 \ No newline at end of file diff --git a/fastapi-backend/.env.example b/fastapi-backend/.env.example deleted file mode 100644 index efa3259..0000000 --- a/fastapi-backend/.env.example +++ /dev/null @@ -1,15 +0,0 @@ -# Database configuration -DB_HOST=localhost -DB_PORT=3306 -DB_USER=root -DB_PASSWORD=password -DB_NAME=niumall_dev - -# JWT configuration -JWT_SECRET=niumall-jwt-secret -JWT_ALGORITHM=HS256 -JWT_EXPIRATION_MINUTES=1440 - -# Server configuration -SERVER_HOST=0.0.0.0 -SERVER_PORT=8000 \ No newline at end of file diff --git a/fastapi-backend/README.md b/fastapi-backend/README.md deleted file mode 100644 index ece2e21..0000000 --- a/fastapi-backend/README.md +++ /dev/null @@ -1,42 +0,0 @@ -# FastAPI Backend for 活牛采购智能数字化系统 - -This is a FastAPI implementation of the backend for the 活牛采购智能数字化系统. - -## Features -- User authentication with JWT -- Order management -- Payment processing -- Role-based access control -- Database integration with SQLAlchemy -- API documentation with Swagger UI and ReDoc - -## Requirements -- Python 3.8+ -- FastAPI -- SQLAlchemy -- PyJWT -- Uvicorn - -## Installation -1. Create a virtual environment: - ```bash - python -m venv venv - source venv/bin/activate # On Windows: venv\Scripts\activate - ``` - -2. Install dependencies: - ```bash - pip install -r requirements.txt - ``` - -3. Configure environment variables (see .env.example) - -4. Run the application: - ```bash - uvicorn app.main:app --reload - ``` - -## API Documentation -Once the server is running, you can access: -- Swagger UI: http://localhost:8000/docs -- ReDoc: http://localhost:8000/redoc \ No newline at end of file diff --git a/fastapi-backend/app/__init__.py b/fastapi-backend/app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fastapi-backend/app/api/__init__.py b/fastapi-backend/app/api/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fastapi-backend/app/api/auth.py b/fastapi-backend/app/api/auth.py deleted file mode 100644 index af097e4..0000000 --- a/fastapi-backend/app/api/auth.py +++ /dev/null @@ -1,80 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, status -from fastapi.security import OAuth2PasswordRequestForm, OAuth2PasswordBearer -from sqlalchemy.orm import Session -from app.db.database import get_db -from app.models.user import User -from app.schemas.user import UserCreate, Token, User -from app.core.security import verify_password, create_access_token, decode_access_token -from datetime import timedelta -from app.core.config import settings -import uuid - -router = APIRouter() - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/auth/login") - -@router.post("/login", response_model=Token) -def login(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depends(get_db)): - # Find user by username - user = db.query(User).filter(User.username == form_data.username).first() - if not user or not verify_password(form_data.password, user.password_hash): - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect username or password", - headers={"WWW-Authenticate": "Bearer"}, - ) - - # Create access token - access_token_expires = timedelta(minutes=settings.JWT_EXPIRATION_MINUTES) - access_token = create_access_token( - data={"sub": user.uuid}, expires_delta=access_token_expires - ) - - return {"access_token": access_token, "token_type": "bearer"} - -@router.post("/register", response_model=User) -def register(user: UserCreate, db: Session = Depends(get_db)): - # Check if user already exists - db_user = db.query(User).filter(User.username == user.username).first() - if db_user: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail="Username already registered", - ) - - # Create new user - new_user = User( - uuid=str(uuid.uuid4()), - username=user.username, - user_type=user.user_type, - status=user.status - ) - new_user.set_password(user.password) - - db.add(new_user) - db.commit() - db.refresh(new_user) - - return new_user - -@router.get("/me", response_model=User) -def read_users_me(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)): - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": "Bearer"}, - ) - - payload = decode_access_token(token) - if payload is None: - raise credentials_exception - - uuid: str = payload.get("sub") - if uuid is None: - raise credentials_exception - - user = db.query(User).filter(User.uuid == uuid).first() - if user is None: - raise credentials_exception - - return user \ No newline at end of file diff --git a/fastapi-backend/app/api/orders.py b/fastapi-backend/app/api/orders.py deleted file mode 100644 index f568a39..0000000 --- a/fastapi-backend/app/api/orders.py +++ /dev/null @@ -1,72 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, status -from sqlalchemy.orm import Session -from typing import List -from app.db.database import get_db -from app.models.order import Order -from app.schemas.order import Order, OrderCreate, OrderUpdate -import uuid - -router = APIRouter() - -@router.get("/", response_model=List[Order]) -def read_orders(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): - orders = db.query(Order).offset(skip).limit(limit).all() - return orders - -@router.get("/{order_id}", response_model=Order) -def read_order(order_id: int, db: Session = Depends(get_db)): - db_order = db.query(Order).filter(Order.id == order_id).first() - if db_order is None: - raise HTTPException(status_code=404, detail="Order not found") - return db_order - -@router.post("/", response_model=Order) -def create_order(order: OrderCreate, db: Session = Depends(get_db)): - # Generate unique order number - order_no = f"ORD{uuid.uuid4().hex[:16].upper()}" - - db_order = Order( - order_no=order_no, - buyer_id=order.buyer_id, - seller_id=order.seller_id, - variety_type=order.variety_type, - weight_range=order.weight_range, - weight_actual=order.weight_actual, - price_per_unit=order.price_per_unit, - total_price=order.total_price, - advance_payment=order.advance_payment, - final_payment=order.final_payment, - status=order.status, - delivery_address=order.delivery_address, - delivery_time=order.delivery_time, - remark=order.remark - ) - - db.add(db_order) - db.commit() - db.refresh(db_order) - return db_order - -@router.put("/{order_id}", response_model=Order) -def update_order(order_id: int, order: OrderUpdate, db: Session = Depends(get_db)): - db_order = db.query(Order).filter(Order.id == order_id).first() - if db_order is None: - raise HTTPException(status_code=404, detail="Order not found") - - # Update order fields - for field, value in order.dict(exclude_unset=True).items(): - setattr(db_order, field, value) - - db.commit() - db.refresh(db_order) - return db_order - -@router.delete("/{order_id}", response_model=Order) -def delete_order(order_id: int, db: Session = Depends(get_db)): - db_order = db.query(Order).filter(Order.id == order_id).first() - if db_order is None: - raise HTTPException(status_code=404, detail="Order not found") - - db.delete(db_order) - db.commit() - return db_order \ No newline at end of file diff --git a/fastapi-backend/app/api/payments.py b/fastapi-backend/app/api/payments.py deleted file mode 100644 index 7f6f07a..0000000 --- a/fastapi-backend/app/api/payments.py +++ /dev/null @@ -1,66 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, status -from sqlalchemy.orm import Session -from typing import List -from app.db.database import get_db -from app.models.payment import Payment -from app.schemas.payment import Payment, PaymentCreate, PaymentUpdate -import uuid - -router = APIRouter() - -@router.get("/", response_model=List[Payment]) -def read_payments(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): - payments = db.query(Payment).offset(skip).limit(limit).all() - return payments - -@router.get("/{payment_id}", response_model=Payment) -def read_payment(payment_id: int, db: Session = Depends(get_db)): - db_payment = db.query(Payment).filter(Payment.id == payment_id).first() - if db_payment is None: - raise HTTPException(status_code=404, detail="Payment not found") - return db_payment - -@router.post("/", response_model=Payment) -def create_payment(payment: PaymentCreate, db: Session = Depends(get_db)): - # Generate unique payment number - payment_no = f"PMT{uuid.uuid4().hex[:16].upper()}" - - db_payment = Payment( - payment_no=payment_no, - order_id=payment.order_id, - user_id=payment.user_id, - amount=payment.amount, - payment_type=payment.payment_type, - payment_method=payment.payment_method, - status=payment.status, - transaction_id=payment.transaction_id - ) - - db.add(db_payment) - db.commit() - db.refresh(db_payment) - return db_payment - -@router.put("/{payment_id}", response_model=Payment) -def update_payment(payment_id: int, payment: PaymentUpdate, db: Session = Depends(get_db)): - db_payment = db.query(Payment).filter(Payment.id == payment_id).first() - if db_payment is None: - raise HTTPException(status_code=404, detail="Payment not found") - - # Update payment fields - for field, value in payment.dict(exclude_unset=True).items(): - setattr(db_payment, field, value) - - db.commit() - db.refresh(db_payment) - return db_payment - -@router.delete("/{payment_id}", response_model=Payment) -def delete_payment(payment_id: int, db: Session = Depends(get_db)): - db_payment = db.query(Payment).filter(Payment.id == payment_id).first() - if db_payment is None: - raise HTTPException(status_code=404, detail="Payment not found") - - db.delete(db_payment) - db.commit() - return db_payment \ No newline at end of file diff --git a/fastapi-backend/app/api/users.py b/fastapi-backend/app/api/users.py deleted file mode 100644 index d9093ab..0000000 --- a/fastapi-backend/app/api/users.py +++ /dev/null @@ -1,49 +0,0 @@ -from fastapi import APIRouter, Depends, HTTPException, status -from sqlalchemy.orm import Session -from typing import List -from app.db.database import get_db -from app.models.user import User -from app.schemas.user import User, UserCreate, UserUpdate -from app.api.auth import oauth2_scheme - -router = APIRouter() - -@router.get("/", response_model=List[User]) -def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): - users = db.query(User).offset(skip).limit(limit).all() - return users - -@router.get("/{user_id}", response_model=User) -def read_user(user_id: int, db: Session = Depends(get_db)): - db_user = db.query(User).filter(User.id == user_id).first() - if db_user is None: - raise HTTPException(status_code=404, detail="User not found") - return db_user - -@router.put("/{user_id}", response_model=User) -def update_user(user_id: int, user: UserUpdate, db: Session = Depends(get_db)): - db_user = db.query(User).filter(User.id == user_id).first() - if db_user is None: - raise HTTPException(status_code=404, detail="User not found") - - # Update user fields - if user.username is not None: - db_user.username = user.username - if user.user_type is not None: - db_user.user_type = user.user_type - if user.status is not None: - db_user.status = user.status - - db.commit() - db.refresh(db_user) - return db_user - -@router.delete("/{user_id}", response_model=User) -def delete_user(user_id: int, db: Session = Depends(get_db)): - db_user = db.query(User).filter(User.id == user_id).first() - if db_user is None: - raise HTTPException(status_code=404, detail="User not found") - - db.delete(db_user) - db.commit() - return db_user \ No newline at end of file diff --git a/fastapi-backend/app/core/__init__.py b/fastapi-backend/app/core/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fastapi-backend/app/core/config.py b/fastapi-backend/app/core/config.py deleted file mode 100644 index 4f1d288..0000000 --- a/fastapi-backend/app/core/config.py +++ /dev/null @@ -1,24 +0,0 @@ -import os -from pydantic_settings import BaseSettings - -class Settings(BaseSettings): - # Database configuration - DB_HOST: str = os.getenv("DB_HOST", "localhost") - DB_PORT: int = int(os.getenv("DB_PORT", 3306)) - DB_USER: str = os.getenv("DB_USER", "root") - DB_PASSWORD: str = os.getenv("DB_PASSWORD", "password") - DB_NAME: str = os.getenv("DB_NAME", "niumall_dev") - - # JWT configuration - JWT_SECRET: str = os.getenv("JWT_SECRET", "niumall-jwt-secret") - JWT_ALGORITHM: str = os.getenv("JWT_ALGORITHM", "HS256") - JWT_EXPIRATION_MINUTES: int = int(os.getenv("JWT_EXPIRATION_MINUTES", 1440)) - - # Server configuration - SERVER_HOST: str = os.getenv("SERVER_HOST", "0.0.0.0") - SERVER_PORT: int = int(os.getenv("SERVER_PORT", 8000)) - - class Config: - env_file = ".env" - -settings = Settings() \ No newline at end of file diff --git a/fastapi-backend/app/core/security.py b/fastapi-backend/app/core/security.py deleted file mode 100644 index 40d49ca..0000000 --- a/fastapi-backend/app/core/security.py +++ /dev/null @@ -1,30 +0,0 @@ -from datetime import datetime, timedelta -from typing import Optional -from jose import JWTError, jwt -from passlib.context import CryptContext -from app.core.config import settings - -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") - -def verify_password(plain_password, hashed_password): - return pwd_context.verify(plain_password, hashed_password) - -def get_password_hash(password): - return pwd_context.hash(password) - -def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): - to_encode = data.copy() - if expires_delta: - expire = datetime.utcnow() + expires_delta - else: - expire = datetime.utcnow() + timedelta(minutes=settings.JWT_EXPIRATION_MINUTES) - to_encode.update({"exp": expire}) - encoded_jwt = jwt.encode(to_encode, settings.JWT_SECRET, algorithm=settings.JWT_ALGORITHM) - return encoded_jwt - -def decode_access_token(token: str): - try: - payload = jwt.decode(token, settings.JWT_SECRET, algorithms=[settings.JWT_ALGORITHM]) - return payload - except JWTError: - return None \ No newline at end of file diff --git a/fastapi-backend/app/db/__init__.py b/fastapi-backend/app/db/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fastapi-backend/app/db/database.py b/fastapi-backend/app/db/database.py deleted file mode 100644 index 3374edf..0000000 --- a/fastapi-backend/app/db/database.py +++ /dev/null @@ -1,24 +0,0 @@ -from sqlalchemy import create_engine -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import sessionmaker -from app.core.config import settings - -# Create database URL -SQLALCHEMY_DATABASE_URL = f"mysql+pymysql://{settings.DB_USER}:{settings.DB_PASSWORD}@{settings.DB_HOST}:{settings.DB_PORT}/{settings.DB_NAME}" - -# Create engine -engine = create_engine(SQLALCHEMY_DATABASE_URL, echo=True, pool_pre_ping=True) - -# Create session -SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) - -# Base class for models -Base = declarative_base() - -# Dependency to get DB session -def get_db(): - db = SessionLocal() - try: - yield db - finally: - db.close() \ No newline at end of file diff --git a/fastapi-backend/app/main.py b/fastapi-backend/app/main.py deleted file mode 100644 index f1f1449..0000000 --- a/fastapi-backend/app/main.py +++ /dev/null @@ -1,45 +0,0 @@ -from fastapi import FastAPI, Request, Depends -from fastapi.middleware.cors import CORSMiddleware -from app.api import auth, users, orders, payments -from app.core.config import settings -from app.db.database import engine, Base -from app.middleware.error_handler import error_handler -from fastapi.exceptions import RequestValidationError -from starlette.exceptions import HTTPException as StarletteHTTPException - -# Create database tables -Base.metadata.create_all(bind=engine) - -app = FastAPI( - title="活牛采购智能数字化系统API", - description="活牛采购智能数字化系统后端API接口", - version="1.0.0", -) - -# Add CORS middleware -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], # In production, specify exact origins - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -# Add exception handlers -app.add_exception_handler(StarletteHTTPException, error_handler) -app.add_exception_handler(RequestValidationError, error_handler) -app.add_exception_handler(Exception, error_handler) - -# Include routers -app.include_router(auth.router, prefix="/api/auth", tags=["auth"]) -app.include_router(users.router, prefix="/api/users", tags=["users"]) -app.include_router(orders.router, prefix="/api/orders", tags=["orders"]) -app.include_router(payments.router, prefix="/api/payments", tags=["payments"]) - -@app.get("/") -async def root(): - return {"message": "活牛采购智能数字化系统后端服务", "version": "1.0.0"} - -@app.get("/health") -async def health_check(): - return {"status": "healthy"} \ No newline at end of file diff --git a/fastapi-backend/app/middleware/__init__.py b/fastapi-backend/app/middleware/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fastapi-backend/app/middleware/auth.py b/fastapi-backend/app/middleware/auth.py deleted file mode 100644 index dd45048..0000000 --- a/fastapi-backend/app/middleware/auth.py +++ /dev/null @@ -1,39 +0,0 @@ -from fastapi import HTTPException, status, Depends -from fastapi.security import OAuth2PasswordBearer -from sqlalchemy.orm import Session -from app.db.database import get_db -from app.models.user import User -from app.core.security import decode_access_token - -oauth2_scheme = OAuth2PasswordBearer(tokenUrl="api/auth/login") - -def get_current_user(token: str = Depends(oauth2_scheme), db: Session = Depends(get_db)): - credentials_exception = HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Could not validate credentials", - headers={"WWW-Authenticate": "Bearer"}, - ) - - payload = decode_access_token(token) - if payload is None: - raise credentials_exception - - uuid: str = payload.get("sub") - if uuid is None: - raise credentials_exception - - user = db.query(User).filter(User.uuid == uuid).first() - if user is None: - raise credentials_exception - - return user - -def require_role(required_role: str): - def role_checker(current_user: User = Depends(get_current_user)): - if current_user.user_type != required_role: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail="Insufficient permissions", - ) - return current_user - return role_checker \ No newline at end of file diff --git a/fastapi-backend/app/middleware/error_handler.py b/fastapi-backend/app/middleware/error_handler.py deleted file mode 100644 index 56b225a..0000000 --- a/fastapi-backend/app/middleware/error_handler.py +++ /dev/null @@ -1,25 +0,0 @@ -from fastapi import HTTPException, Request -from fastapi.responses import JSONResponse -from app.utils.response import ErrorResponse - -async def error_handler(request: Request, exc: Exception): - # Handle HTTP exceptions - if isinstance(exc, HTTPException): - return JSONResponse( - status_code=exc.status_code, - content=ErrorResponse( - code=exc.status_code, - message=exc.detail, - data=None - ).dict() - ) - - # Handle general exceptions - return JSONResponse( - status_code=500, - content=ErrorResponse( - code=500, - message="Internal Server Error", - data=str(exc) - ).dict() - ) \ No newline at end of file diff --git a/fastapi-backend/app/models/__init__.py b/fastapi-backend/app/models/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fastapi-backend/app/models/order.py b/fastapi-backend/app/models/order.py deleted file mode 100644 index 0b9d26b..0000000 --- a/fastapi-backend/app/models/order.py +++ /dev/null @@ -1,33 +0,0 @@ -from sqlalchemy import Column, Integer, String, Float, Enum, DateTime, Text, func, ForeignKey -from app.db.database import Base -from enum import Enum as PyEnum - -class OrderStatus(str, PyEnum): - PENDING = "pending" - CONFIRMED = "confirmed" - PROCESSING = "processing" - SHIPPED = "shipped" - DELIVERED = "delivered" - CANCELLED = "cancelled" - COMPLETED = "completed" - -class Order(Base): - __tablename__ = "orders" - - id = Column(Integer, primary_key=True, index=True) - order_no = Column(String(32), unique=True, index=True, nullable=False) - buyer_id = Column(Integer, ForeignKey("users.id"), nullable=False) - seller_id = Column(Integer, ForeignKey("users.id"), nullable=False) - variety_type = Column(String(50), nullable=False) - weight_range = Column(String(50), nullable=False) - weight_actual = Column(Float, nullable=True) - price_per_unit = Column(Float, nullable=False) - total_price = Column(Float, nullable=False) - advance_payment = Column(Float, nullable=False, default=0.0) - final_payment = Column(Float, nullable=False, default=0.0) - status = Column(Enum(OrderStatus), default=OrderStatus.PENDING, nullable=False) - delivery_address = Column(Text, nullable=True) - delivery_time = Column(DateTime, nullable=True) - remark = Column(Text, nullable=True) - created_at = Column(DateTime, default=func.now(), nullable=False) - updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), nullable=False) \ No newline at end of file diff --git a/fastapi-backend/app/models/payment.py b/fastapi-backend/app/models/payment.py deleted file mode 100644 index 4e541f6..0000000 --- a/fastapi-backend/app/models/payment.py +++ /dev/null @@ -1,33 +0,0 @@ -from sqlalchemy import Column, Integer, String, Float, Enum, DateTime, ForeignKey, func -from app.db.database import Base -from enum import Enum as PyEnum - -class PaymentType(str, PyEnum): - ADVANCE = "advance" - FINAL = "final" - -class PaymentMethod(str, PyEnum): - WECHAT = "wechat" - ALIPAY = "alipay" - BANK = "bank" - -class PaymentStatus(str, PyEnum): - PENDING = "pending" - SUCCESS = "success" - FAILED = "failed" - REFUNDED = "refunded" - -class Payment(Base): - __tablename__ = "payments" - - id = Column(Integer, primary_key=True, index=True) - order_id = Column(Integer, ForeignKey("orders.id"), nullable=False) - user_id = Column(Integer, ForeignKey("users.id"), nullable=False) - payment_no = Column(String(32), unique=True, index=True, nullable=False) - amount = Column(Float, nullable=False) - payment_type = Column(Enum(PaymentType), nullable=False) - payment_method = Column(Enum(PaymentMethod), nullable=False) - status = Column(Enum(PaymentStatus), default=PaymentStatus.PENDING, nullable=False) - transaction_id = Column(String(128), nullable=True) - created_at = Column(DateTime, default=func.now(), nullable=False) - updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), nullable=False) \ No newline at end of file diff --git a/fastapi-backend/app/models/user.py b/fastapi-backend/app/models/user.py deleted file mode 100644 index ed84dab..0000000 --- a/fastapi-backend/app/models/user.py +++ /dev/null @@ -1,36 +0,0 @@ -from sqlalchemy import Column, Integer, String, Enum, DateTime, func -from app.db.database import Base -from passlib.context import CryptContext -from enum import Enum as PyEnum - -pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") - -class UserType(str, PyEnum): - CLIENT = "client" - SUPPLIER = "supplier" - DRIVER = "driver" - STAFF = "staff" - ADMIN = "admin" - -class UserStatus(str, PyEnum): - ACTIVE = "active" - INACTIVE = "inactive" - LOCKED = "locked" - -class User(Base): - __tablename__ = "users" - - id = Column(Integer, primary_key=True, index=True) - uuid = Column(String(36), unique=True, index=True, nullable=False) - username = Column(String(50), unique=True, index=True, nullable=False) - password_hash = Column(String(128), nullable=False) - user_type = Column(Enum(UserType), default=UserType.CLIENT, nullable=False) - status = Column(Enum(UserStatus), default=UserStatus.ACTIVE, nullable=False) - created_at = Column(DateTime, default=func.now(), nullable=False) - updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), nullable=False) - - def verify_password(self, plain_password): - return pwd_context.verify(plain_password, self.password_hash) - - def set_password(self, plain_password): - self.password_hash = pwd_context.hash(plain_password) \ No newline at end of file diff --git a/fastapi-backend/app/schemas/__init__.py b/fastapi-backend/app/schemas/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/fastapi-backend/app/schemas/order.py b/fastapi-backend/app/schemas/order.py deleted file mode 100644 index b4eecb7..0000000 --- a/fastapi-backend/app/schemas/order.py +++ /dev/null @@ -1,58 +0,0 @@ -from pydantic import BaseModel -from typing import Optional -from datetime import datetime -from enum import Enum - -class OrderStatus(str, Enum): - PENDING = "pending" - CONFIRMED = "confirmed" - PROCESSING = "processing" - SHIPPED = "shipped" - DELIVERED = "delivered" - CANCELLED = "cancelled" - COMPLETED = "completed" - -class OrderBase(BaseModel): - buyer_id: int - seller_id: int - variety_type: str - weight_range: str - weight_actual: Optional[float] = None - price_per_unit: float - total_price: float - advance_payment: float = 0.0 - final_payment: float = 0.0 - status: OrderStatus = OrderStatus.PENDING - delivery_address: Optional[str] = None - delivery_time: Optional[datetime] = None - remark: Optional[str] = None - -class OrderCreate(OrderBase): - pass - -class OrderUpdate(BaseModel): - buyer_id: Optional[int] = None - seller_id: Optional[int] = None - variety_type: Optional[str] = None - weight_range: Optional[str] = None - weight_actual: Optional[float] = None - price_per_unit: Optional[float] = None - total_price: Optional[float] = None - advance_payment: Optional[float] = None - final_payment: Optional[float] = None - status: Optional[OrderStatus] = None - delivery_address: Optional[str] = None - delivery_time: Optional[datetime] = None - remark: Optional[str] = None - -class OrderInDBBase(OrderBase): - id: int - order_no: str - created_at: datetime - updated_at: datetime - - class Config: - orm_mode = True - -class Order(OrderInDBBase): - pass \ No newline at end of file diff --git a/fastapi-backend/app/schemas/payment.py b/fastapi-backend/app/schemas/payment.py deleted file mode 100644 index b19da9f..0000000 --- a/fastapi-backend/app/schemas/payment.py +++ /dev/null @@ -1,52 +0,0 @@ -from pydantic import BaseModel -from typing import Optional -from datetime import datetime -from enum import Enum - -class PaymentType(str, Enum): - ADVANCE = "advance" - FINAL = "final" - -class PaymentMethod(str, Enum): - WECHAT = "wechat" - ALIPAY = "alipay" - BANK = "bank" - -class PaymentStatus(str, Enum): - PENDING = "pending" - SUCCESS = "success" - FAILED = "failed" - REFUNDED = "refunded" - -class PaymentBase(BaseModel): - order_id: int - user_id: int - amount: float - payment_type: PaymentType - payment_method: PaymentMethod - status: PaymentStatus = PaymentStatus.PENDING - transaction_id: Optional[str] = None - -class PaymentCreate(PaymentBase): - pass - -class PaymentUpdate(BaseModel): - order_id: Optional[int] = None - user_id: Optional[int] = None - amount: Optional[float] = None - payment_type: Optional[PaymentType] = None - payment_method: Optional[PaymentMethod] = None - status: Optional[PaymentStatus] = None - transaction_id: Optional[str] = None - -class PaymentInDBBase(PaymentBase): - id: int - payment_no: str - created_at: datetime - updated_at: datetime - - class Config: - orm_mode = True - -class Payment(PaymentInDBBase): - pass \ No newline at end of file diff --git a/fastapi-backend/app/schemas/user.py b/fastapi-backend/app/schemas/user.py deleted file mode 100644 index 7b31e57..0000000 --- a/fastapi-backend/app/schemas/user.py +++ /dev/null @@ -1,51 +0,0 @@ -from pydantic import BaseModel -from typing import Optional -from datetime import datetime -from enum import Enum - -class UserType(str, Enum): - CLIENT = "client" - SUPPLIER = "supplier" - DRIVER = "driver" - STAFF = "staff" - ADMIN = "admin" - -class UserStatus(str, Enum): - ACTIVE = "active" - INACTIVE = "inactive" - LOCKED = "locked" - -class UserBase(BaseModel): - username: str - user_type: UserType = UserType.CLIENT - status: UserStatus = UserStatus.ACTIVE - -class UserCreate(UserBase): - password: str - -class UserUpdate(BaseModel): - username: Optional[str] = None - user_type: Optional[UserType] = None - status: Optional[UserStatus] = None - -class UserInDBBase(UserBase): - id: int - uuid: str - created_at: datetime - updated_at: datetime - - class Config: - orm_mode = True - -class User(UserInDBBase): - pass - -class UserInDB(UserInDBBase): - password_hash: str - -class Token(BaseModel): - access_token: str - token_type: str - -class TokenData(BaseModel): - uuid: Optional[str] = None \ No newline at end of file diff --git a/fastapi-backend/app/utils/response.py b/fastapi-backend/app/utils/response.py deleted file mode 100644 index 5212ff8..0000000 --- a/fastapi-backend/app/utils/response.py +++ /dev/null @@ -1,26 +0,0 @@ -from typing import Any, Optional, Generic, TypeVar -from pydantic import BaseModel -from datetime import datetime - -T = TypeVar('T') - -class SuccessResponse(BaseModel, Generic[T]): - code: int = 200 - message: str = "Success" - data: Optional[T] = None - timestamp: datetime = datetime.now() - -class ErrorResponse(BaseModel): - code: int = 500 - message: str = "Internal Server Error" - data: Optional[Any] = None - timestamp: datetime = datetime.now() - -class PaginatedResponse(BaseModel, Generic[T]): - code: int = 200 - message: str = "Success" - data: Optional[T] = None - timestamp: datetime = datetime.now() - total: int - page: int - limit: int \ No newline at end of file diff --git a/fastapi-backend/requirements.txt b/fastapi-backend/requirements.txt deleted file mode 100644 index 6dcf563..0000000 --- a/fastapi-backend/requirements.txt +++ /dev/null @@ -1,10 +0,0 @@ -fastapi==0.68.0 -uvicorn[standard]==0.15.0 -sqlalchemy==1.4.23 -databases[mysql]==0.5.3 -pydantic==1.8.2 -python-jose[cryptography]==3.3.0 -passlib[bcrypt]==1.7.4 -python-multipart==0.0.5 -alembic==1.7.1 -python-dotenv==0.18.0 \ No newline at end of file diff --git a/go-backend/.env.example b/go-backend/.env.example deleted file mode 100644 index 7a39461..0000000 --- a/go-backend/.env.example +++ /dev/null @@ -1,13 +0,0 @@ -# Database configuration -DB_HOST=localhost -DB_PORT=3306 -DB_USER=root -DB_PASSWORD= -DB_NAME=niumall_go - -# Server configuration -PORT=8080 -GIN_MODE=debug - -# JWT configuration -JWT_SECRET=your-secret-key-here \ No newline at end of file diff --git a/go-backend/.gitignore b/go-backend/.gitignore deleted file mode 100644 index e874029..0000000 --- a/go-backend/.gitignore +++ /dev/null @@ -1,35 +0,0 @@ -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with go test -c -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories -vendor/ - -# Go workspace file -go.work - -# Environment files -.env - -# IDE-specific files -.vscode/ -.idea/ - -# Docker -docker-compose.override.yml - -# Log files -*.log - -# Build outputs -main -bin/ \ No newline at end of file diff --git a/go-backend/Dockerfile b/go-backend/Dockerfile deleted file mode 100644 index d5781da..0000000 --- a/go-backend/Dockerfile +++ /dev/null @@ -1,44 +0,0 @@ -# 使用国内镜像源的Go镜像作为构建环境 -FROM golang:1.21-alpine AS builder - -# 设置工作目录 -WORKDIR /app - -# 复制go.mod和go.sum文件 -COPY go.mod go.sum ./ - -# 为apk包管理器配置国内镜像源 -RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories - -# 下载依赖 -RUN go mod download - -# 复制源代码 -COPY . . - -# 构建应用 -RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main . - -# 使用Alpine Linux作为运行环境 -FROM alpine:latest - -# 为apk包管理器配置国内镜像源 -RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories - -# 安装ca-certificates以支持HTTPS请求 -RUN apk --no-cache add ca-certificates - -# 设置工作目录 -WORKDIR /root/ - -# 从构建阶段复制二进制文件 -COPY --from=builder /app/main . - -# 复制环境配置文件 -COPY --from=builder /app/.env.example .env - -# 暴露端口 -EXPOSE 8080 - -# 运行应用 -CMD ["./main"] \ No newline at end of file diff --git a/go-backend/Makefile b/go-backend/Makefile deleted file mode 100644 index fad93be..0000000 --- a/go-backend/Makefile +++ /dev/null @@ -1,50 +0,0 @@ -# 定义变量 -BINARY_NAME=main -DOCKER_IMAGE_NAME=niumall-go-backend - -# 默认目标 -.PHONY: help -help: ## 显示帮助信息 - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - -.PHONY: build -build: ## 构建Go应用 - go build -o ${BINARY_NAME} . - -.PHONY: run -run: ## 运行Go应用 - go run main.go - -.PHONY: test -test: ## 运行单元测试 - go test -v ./... - -.PHONY: clean -clean: ## 清理构建文件 - rm -f ${BINARY_NAME} - -.PHONY: docker-build -docker-build: ## 构建Docker镜像 - docker build -t ${DOCKER_IMAGE_NAME} . - -.PHONY: docker-run -docker-run: ## 运行Docker容器 - docker run -p 8080:8080 ${DOCKER_IMAGE_NAME} - -.PHONY: docker-compose-up -docker-compose-up: ## 使用docker-compose启动服务 - docker-compose up -d - -.PHONY: docker-compose-down -docker-compose-down: ## 使用docker-compose停止服务 - docker-compose down - -.PHONY: migrate-up -migrate-up: ## 运行数据库迁移(如果有的话) - @echo "运行数据库迁移..." - # 在这里添加数据库迁移命令 - -.PHONY: migrate-down -migrate-down: ## 回滚数据库迁移(如果有的话) - @echo "回滚数据库迁移..." - # 在这里添加数据库回滚命令 \ No newline at end of file diff --git a/go-backend/README.md b/go-backend/README.md deleted file mode 100644 index 30db02f..0000000 --- a/go-backend/README.md +++ /dev/null @@ -1,147 +0,0 @@ -# NiūMall Go后端 - -这是一个使用Go语言和Gin框架构建的后端服务,为NiūMall活牛采购智能数字化系统提供API支持。 - -## 目录结构 - -``` -go-backend/ -├── config/ # 配置文件 -├── controllers/ # 控制器 -├── docs/ # API文档 -├── middleware/ # 中间件 -├── models/ # 数据模型 -├── routes/ # 路由定义 -├── utils/ # 工具函数 -├── main.go # 主程序入口 -├── go.mod # Go模块定义 -├── go.sum # Go模块校验和 -├── .env.example # 环境变量示例 -├── .env # 本地环境变量配置 -├── Dockerfile # Docker构建文件 -├── docker-compose.yml # Docker编排文件 -├── Makefile # 构建脚本 -├── start_dev.sh # 本地开发启动脚本 -└── README.md # 项目说明 -``` - -## 本地开发 - -### 环境要求 - -- Go 1.21或更高版本 -- MySQL 8.0或更高版本 -- Docker (可选,用于容器化部署) - -### 安装依赖 - -```bash -go mod tidy -``` - -### 配置环境变量 - -复制`.env.example`文件并根据需要修改配置: - -```bash -cp .env.example .env -``` - -### 启动服务 - -#### 方法1:直接运行(需要本地安装Go和MySQL) - -```bash -./start_dev.sh -``` - -#### 方法2:使用Docker(推荐) - -```bash -# 构建并启动所有服务 -docker-compose up -d - -# 查看服务状态 -docker-compose ps - -# 查看服务日志 -docker-compose logs -f -``` - -### API文档 - -API文档位于`docs/`目录下,使用OpenAPI 3.0规范编写: - -- 用户管理: `docs/users.yaml` -- 订单管理: `docs/orders.yaml` -- 支付管理: `docs/payments.yaml` - -可以使用[Swagger UI](https://editor.swagger.io/)等工具查看文档。 - -## 部署 - -### 使用Docker部署 - -```bash -# 构建镜像 -docker build -t niumall-go-backend . - -# 运行容器 -docker run -p 8080:8080 niumall-go-backend -``` - -### 使用Docker Compose部署 - -```bash -# 在生产环境中启动服务 -docker-compose up -d -``` - -## 开发指南 - -### 代码结构 - -- `main.go`: 程序入口,负责初始化和启动服务 -- `config/`: 数据库连接等配置 -- `models/`: 数据模型定义 -- `controllers/`: 业务逻辑处理 -- `routes/`: 路由注册 -- `middleware/`: 中间件 -- `utils/`: 工具函数 - -### 添加新功能 - -1. 在`models/`目录下创建数据模型 -2. 在`controllers/`目录下创建控制器 -3. 在`routes/routes.go`中注册路由 -4. 更新`docs/`目录下的API文档 - -### 测试 - -运行单元测试: - -```bash -go test -v ./... -``` - -## 故障排除 - -### 网络连接问题 - -如果在构建Docker镜像时遇到网络连接问题,请配置Docker使用国内镜像源: - -1. 在Docker Desktop中打开Settings → Docker Engine -2. 添加以下配置: - ```json - { - "registry-mirrors": [ - "https://docker.mirrors.ustc.edu.cn", - "https://hub-mirror.c.163.com" - ] - } - ``` -3. 点击"Apply & Restart" - -### 数据库连接问题 - -确保MySQL服务正在运行,并且在`.env`文件中配置了正确的数据库连接信息。 \ No newline at end of file diff --git a/go-backend/config/database.go b/go-backend/config/database.go deleted file mode 100644 index 2b00d2a..0000000 --- a/go-backend/config/database.go +++ /dev/null @@ -1,33 +0,0 @@ -package config - -import ( - "log" - "os" - - "gorm.io/driver/mysql" - "gorm.io/gorm" -) - -var DB *gorm.DB - -func InitDB() { - var err error - - // Get database configuration from environment variables - host := os.Getenv("DB_HOST") - port := os.Getenv("DB_PORT") - user := os.Getenv("DB_USER") - password := os.Getenv("DB_PASSWORD") - dbname := os.Getenv("DB_NAME") - - // Create DSN (Data Source Name) - dsn := user + ":" + password + "@tcp(" + host + ":" + port + ")/" + dbname + "?charset=utf8mb4&parseTime=True&loc=Local" - - // Connect to database - DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) - if err != nil { - log.Fatal("Failed to connect to database:", err) - } - - log.Println("Database connection established") -} \ No newline at end of file diff --git a/go-backend/controllers/order_controller.go b/go-backend/controllers/order_controller.go deleted file mode 100644 index c319746..0000000 --- a/go-backend/controllers/order_controller.go +++ /dev/null @@ -1,177 +0,0 @@ -package controllers - -import ( - "net/http" - "strconv" - - "github.com/gin-gonic/gin" - "github.com/google/uuid" - "gorm.io/gorm" - - "niumall-go/config" - "niumall-go/models" -) - -// GetOrders retrieves a list of orders with pagination -func GetOrders(c *gin.Context) { - var orders []models.Order - skip, _ := strconv.Atoi(c.DefaultQuery("skip", "0")) - limit, _ := strconv.Atoi(c.DefaultQuery("limit", "100")) - - if err := config.DB.Offset(skip).Limit(limit).Find(&orders).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, orders) -} - -// GetOrderByID retrieves an order by ID -func GetOrderByID(c *gin.Context) { - id := c.Param("id") - var order models.Order - - if err := config.DB.First(&order, id).Error; err != nil { - if err == gorm.ErrRecordNotFound { - c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"}) - return - } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, order) -} - -// CreateOrder creates a new order -func CreateOrder(c *gin.Context) { - var input models.Order - if err := c.ShouldBindJSON(&input); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - // Generate unique order number - orderNo := "ORD" + uuid.New().String()[:16] - - // Create order - order := models.Order{ - OrderNo: orderNo, - BuyerID: input.BuyerID, - SellerID: input.SellerID, - VarietyType: input.VarietyType, - WeightRange: input.WeightRange, - WeightActual: input.WeightActual, - PricePerUnit: input.PricePerUnit, - TotalPrice: input.TotalPrice, - AdvancePayment: input.AdvancePayment, - FinalPayment: input.FinalPayment, - Status: input.Status, - DeliveryAddress: input.DeliveryAddress, - DeliveryTime: input.DeliveryTime, - Remark: input.Remark, - } - - if err := config.DB.Create(&order).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, order) -} - -// UpdateOrder updates an order's information -func UpdateOrder(c *gin.Context) { - id := c.Param("id") - var order models.Order - - // Check if order exists - if err := config.DB.First(&order, id).Error; err != nil { - if err == gorm.ErrRecordNotFound { - c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"}) - return - } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Parse input - var input models.Order - if err := c.ShouldBindJSON(&input); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - // Update order fields - if input.BuyerID != 0 { - order.BuyerID = input.BuyerID - } - if input.SellerID != 0 { - order.SellerID = input.SellerID - } - if input.VarietyType != "" { - order.VarietyType = input.VarietyType - } - if input.WeightRange != "" { - order.WeightRange = input.WeightRange - } - if input.WeightActual != 0 { - order.WeightActual = input.WeightActual - } - if input.PricePerUnit != 0 { - order.PricePerUnit = input.PricePerUnit - } - if input.TotalPrice != 0 { - order.TotalPrice = input.TotalPrice - } - if input.AdvancePayment != 0 { - order.AdvancePayment = input.AdvancePayment - } - if input.FinalPayment != 0 { - order.FinalPayment = input.FinalPayment - } - if input.Status != "" { - order.Status = input.Status - } - if input.DeliveryAddress != "" { - order.DeliveryAddress = input.DeliveryAddress - } - if input.DeliveryTime != nil { - order.DeliveryTime = input.DeliveryTime - } - if input.Remark != "" { - order.Remark = input.Remark - } - - // Save updated order - if err := config.DB.Save(&order).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, order) -} - -// DeleteOrder deletes an order by ID -func DeleteOrder(c *gin.Context) { - id := c.Param("id") - var order models.Order - - // Check if order exists - if err := config.DB.First(&order, id).Error; err != nil { - if err == gorm.ErrRecordNotFound { - c.JSON(http.StatusNotFound, gin.H{"error": "Order not found"}) - return - } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Delete order - if err := config.DB.Delete(&order).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, order) -} \ No newline at end of file diff --git a/go-backend/controllers/payment_controller.go b/go-backend/controllers/payment_controller.go deleted file mode 100644 index 130c475..0000000 --- a/go-backend/controllers/payment_controller.go +++ /dev/null @@ -1,153 +0,0 @@ -package controllers - -import ( - "net/http" - "strconv" - - "github.com/gin-gonic/gin" - "github.com/google/uuid" - "gorm.io/gorm" - - "niumall-go/config" - "niumall-go/models" -) - -// GetPayments retrieves a list of payments with pagination -func GetPayments(c *gin.Context) { - var payments []models.Payment - skip, _ := strconv.Atoi(c.DefaultQuery("skip", "0")) - limit, _ := strconv.Atoi(c.DefaultQuery("limit", "100")) - - if err := config.DB.Offset(skip).Limit(limit).Find(&payments).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, payments) -} - -// GetPaymentByID retrieves a payment by ID -func GetPaymentByID(c *gin.Context) { - id := c.Param("id") - var payment models.Payment - - if err := config.DB.First(&payment, id).Error; err != nil { - if err == gorm.ErrRecordNotFound { - c.JSON(http.StatusNotFound, gin.H{"error": "Payment not found"}) - return - } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, payment) -} - -// CreatePayment creates a new payment -func CreatePayment(c *gin.Context) { - var input models.Payment - if err := c.ShouldBindJSON(&input); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - // Generate unique payment number - paymentNo := "PMT" + uuid.New().String()[:16] - - // Create payment - payment := models.Payment{ - PaymentNo: paymentNo, - OrderID: input.OrderID, - UserID: input.UserID, - Amount: input.Amount, - PaymentType: input.PaymentType, - PaymentMethod: input.PaymentMethod, - Status: input.Status, - TransactionID: input.TransactionID, - } - - if err := config.DB.Create(&payment).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, payment) -} - -// UpdatePayment updates a payment's information -func UpdatePayment(c *gin.Context) { - id := c.Param("id") - var payment models.Payment - - // Check if payment exists - if err := config.DB.First(&payment, id).Error; err != nil { - if err == gorm.ErrRecordNotFound { - c.JSON(http.StatusNotFound, gin.H{"error": "Payment not found"}) - return - } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Parse input - var input models.Payment - if err := c.ShouldBindJSON(&input); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - // Update payment fields - if input.OrderID != 0 { - payment.OrderID = input.OrderID - } - if input.UserID != 0 { - payment.UserID = input.UserID - } - if input.Amount != 0 { - payment.Amount = input.Amount - } - if input.PaymentType != "" { - payment.PaymentType = input.PaymentType - } - if input.PaymentMethod != "" { - payment.PaymentMethod = input.PaymentMethod - } - if input.Status != "" { - payment.Status = input.Status - } - if input.TransactionID != "" { - payment.TransactionID = input.TransactionID - } - - // Save updated payment - if err := config.DB.Save(&payment).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, payment) -} - -// DeletePayment deletes a payment by ID -func DeletePayment(c *gin.Context) { - id := c.Param("id") - var payment models.Payment - - // Check if payment exists - if err := config.DB.First(&payment, id).Error; err != nil { - if err == gorm.ErrRecordNotFound { - c.JSON(http.StatusNotFound, gin.H{"error": "Payment not found"}) - return - } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Delete payment - if err := config.DB.Delete(&payment).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, payment) -} \ No newline at end of file diff --git a/go-backend/controllers/user_controller.go b/go-backend/controllers/user_controller.go deleted file mode 100644 index 70b9e3d..0000000 --- a/go-backend/controllers/user_controller.go +++ /dev/null @@ -1,153 +0,0 @@ -package controllers - -import ( - "net/http" - "strconv" - - "github.com/gin-gonic/gin" - "gorm.io/gorm" - - "niumall-go/config" - "niumall-go/models" - "niumall-go/utils" -) - -// GetUserByID retrieves a user by ID -func GetUserByID(c *gin.Context) { - id := c.Param("id") - var user models.User - - if err := config.DB.First(&user, id).Error; err != nil { - if err == gorm.ErrRecordNotFound { - c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) - return - } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, user) -} - -// GetUsers retrieves a list of users with pagination -func GetUsers(c *gin.Context) { - var users []models.User - skip, _ := strconv.Atoi(c.DefaultQuery("skip", "0")) - limit, _ := strconv.Atoi(c.DefaultQuery("limit", "100")) - - if err := config.DB.Offset(skip).Limit(limit).Find(&users).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, users) -} - -// UpdateUser updates a user's information -func UpdateUser(c *gin.Context) { - id := c.Param("id") - var user models.User - - // Check if user exists - if err := config.DB.First(&user, id).Error; err != nil { - if err == gorm.ErrRecordNotFound { - c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) - return - } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Parse input - var input models.User - if err := c.ShouldBindJSON(&input); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - // Update user fields - if input.Username != "" { - user.Username = input.Username - } - if input.UserType != "" { - user.UserType = input.UserType - } - if input.Status != "" { - user.Status = input.Status - } - - // Save updated user - if err := config.DB.Save(&user).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, user) -} - -// DeleteUser deletes a user by ID -func DeleteUser(c *gin.Context) { - id := c.Param("id") - var user models.User - - // Check if user exists - if err := config.DB.First(&user, id).Error; err != nil { - if err == gorm.ErrRecordNotFound { - c.JSON(http.StatusNotFound, gin.H{"error": "User not found"}) - return - } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Delete user - if err := config.DB.Delete(&user).Error; err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, user) -} - -// Login handles user login and returns a JWT token -func Login(c *gin.Context) { - var input struct { - Username string `json:"username" binding:"required"` - Password string `json:"password" binding:"required"` - } - - // Parse input - if err := c.ShouldBindJSON(&input); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - // Find user by username - var user models.User - if err := config.DB.Where("username = ?", input.Username).First(&user).Error; err != nil { - if err == gorm.ErrRecordNotFound { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"}) - return - } - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Check password - if !utils.CheckPasswordHash(input.Password, user.Password) { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"}) - return - } - - // Generate JWT token - token, err := utils.GenerateJWT(user.UUID) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"}) - return - } - - c.JSON(http.StatusOK, gin.H{ - "access_token": token, - "token_type": "bearer", - }) -} \ No newline at end of file diff --git a/go-backend/docker-compose.yml b/go-backend/docker-compose.yml deleted file mode 100644 index 5c228a2..0000000 --- a/go-backend/docker-compose.yml +++ /dev/null @@ -1,29 +0,0 @@ -version: '3.8' - -services: - app: - build: . - ports: - - "8080:8080" - environment: - - DB_HOST=db - - DB_PORT=3306 - - DB_USER=root - - DB_PASSWORD=root - - DB_NAME=niumall - depends_on: - - db - - db: - image: mysql:8.0 - environment: - MYSQL_ROOT_PASSWORD: root - MYSQL_DATABASE: niumall - ports: - - "3306:3306" - volumes: - - db_data:/var/lib/mysql - command: --default-authentication-plugin=mysql_native_password - -volumes: - db_data: \ No newline at end of file diff --git a/go-backend/docs/orders.yaml b/go-backend/docs/orders.yaml deleted file mode 100644 index fd5883c..0000000 --- a/go-backend/docs/orders.yaml +++ /dev/null @@ -1,412 +0,0 @@ -openapi: 3.0.0 -info: - title: 订单管理API - description: 订单管理相关接口文档 - version: 1.0.0 - -paths: - /api/orders: - get: - summary: 获取订单列表 - description: 获取系统中的订单列表,支持分页(需要认证) - security: - - bearerAuth: [] - parameters: - - name: skip - in: query - description: 跳过的记录数 - required: false - schema: - type: integer - default: 0 - - name: limit - in: query - description: 返回的记录数 - required: false - schema: - type: integer - default: 100 - responses: - '200': - description: 成功返回订单列表 - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Order' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - post: - summary: 创建订单 - description: 创建一个新的订单(需要认证) - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/OrderCreate' - responses: - '200': - description: 成功创建订单 - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - '400': - description: 请求参数验证失败 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /api/orders/{id}: - get: - summary: 获取订单详情 - description: 根据订单ID获取订单详细信息(需要认证) - security: - - bearerAuth: [] - parameters: - - name: id - in: path - description: 订单ID - required: true - schema: - type: integer - responses: - '200': - description: 成功返回订单信息 - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: 订单未找到 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - put: - summary: 更新订单信息 - description: 根据订单ID更新订单信息(需要认证) - security: - - bearerAuth: [] - parameters: - - name: id - in: path - description: 订单ID - required: true - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/OrderUpdate' - responses: - '200': - description: 成功更新订单信息 - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - '400': - description: 请求参数验证失败 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: 订单未找到 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - delete: - summary: 删除订单 - description: 根据订单ID删除订单(需要认证) - security: - - bearerAuth: [] - parameters: - - name: id - in: path - description: 订单ID - required: true - schema: - type: integer - responses: - '200': - description: 成功删除订单 - content: - application/json: - schema: - $ref: '#/components/schemas/Order' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: 订单未找到 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - -components: - schemas: - Order: - type: object - properties: - id: - type: integer - description: 订单ID - order_no: - type: string - description: 订单号 - buyer_id: - type: integer - description: 买家ID - seller_id: - type: integer - description: 卖家ID - variety_type: - type: string - description: 品种类型 - weight_range: - type: string - description: 重量范围 - weight_actual: - type: number - format: float - description: 实际重量 - price_per_unit: - type: number - format: float - description: 单价 - total_price: - type: number - format: float - description: 总价 - advance_payment: - type: number - format: float - description: 预付款 - final_payment: - type: number - format: float - description: 尾款 - status: - type: string - enum: [pending, confirmed, processing, shipped, delivered, cancelled, completed] - description: 订单状态 - delivery_address: - type: string - description: 收货地址 - delivery_time: - type: string - format: date-time - description: 交付时间 - remark: - type: string - description: 备注 - created_at: - type: string - format: date-time - description: 创建时间 - updated_at: - type: string - format: date-time - description: 更新时间 - required: - - id - - order_no - - buyer_id - - seller_id - - variety_type - - weight_range - - price_per_unit - - total_price - - advance_payment - - final_payment - - status - - created_at - - updated_at - - OrderCreate: - type: object - properties: - buyer_id: - type: integer - description: 买家ID - seller_id: - type: integer - description: 卖家ID - variety_type: - type: string - description: 品种类型 - weight_range: - type: string - description: 重量范围 - weight_actual: - type: number - format: float - description: 实际重量 - price_per_unit: - type: number - format: float - description: 单价 - total_price: - type: number - format: float - description: 总价 - advance_payment: - type: number - format: float - description: 预付款 - final_payment: - type: number - format: float - description: 尾款 - status: - type: string - enum: [pending, confirmed, processing, shipped, delivered, cancelled, completed] - description: 订单状态 - delivery_address: - type: string - description: 收货地址 - delivery_time: - type: string - format: date-time - description: 交付时间 - remark: - type: string - description: 备注 - required: - - buyer_id - - seller_id - - variety_type - - weight_range - - price_per_unit - - total_price - - OrderUpdate: - type: object - properties: - buyer_id: - type: integer - description: 买家ID - seller_id: - type: integer - description: 卖家ID - variety_type: - type: string - description: 品种类型 - weight_range: - type: string - description: 重量范围 - weight_actual: - type: number - format: float - description: 实际重量 - price_per_unit: - type: number - format: float - description: 单价 - total_price: - type: number - format: float - description: 总价 - advance_payment: - type: number - format: float - description: 预付款 - final_payment: - type: number - format: float - description: 尾款 - status: - type: string - enum: [pending, confirmed, processing, shipped, delivered, cancelled, completed] - description: 订单状态 - delivery_address: - type: string - description: 收货地址 - delivery_time: - type: string - format: date-time - description: 交付时间 - remark: - type: string - description: 备注 - - Error: - type: object - properties: - error: - type: string - description: 错误信息 - required: - - error - - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT \ No newline at end of file diff --git a/go-backend/docs/payments.yaml b/go-backend/docs/payments.yaml deleted file mode 100644 index 17f0d61..0000000 --- a/go-backend/docs/payments.yaml +++ /dev/null @@ -1,355 +0,0 @@ -openapi: 3.0.0 -info: - title: 支付管理API - description: 支付管理相关接口文档 - version: 1.0.0 - -paths: - /api/payments: - get: - summary: 获取支付列表 - description: 获取系统中的支付列表,支持分页(需要认证) - security: - - bearerAuth: [] - parameters: - - name: skip - in: query - description: 跳过的记录数 - required: false - schema: - type: integer - default: 0 - - name: limit - in: query - description: 返回的记录数 - required: false - schema: - type: integer - default: 100 - responses: - '200': - description: 成功返回支付列表 - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/Payment' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - post: - summary: 创建支付 - description: 创建一个新的支付(需要认证) - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/PaymentCreate' - responses: - '200': - description: 成功创建支付 - content: - application/json: - schema: - $ref: '#/components/schemas/Payment' - '400': - description: 请求参数验证失败 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /api/payments/{id}: - get: - summary: 获取支付详情 - description: 根据支付ID获取支付详细信息(需要认证) - security: - - bearerAuth: [] - parameters: - - name: id - in: path - description: 支付ID - required: true - schema: - type: integer - responses: - '200': - description: 成功返回支付信息 - content: - application/json: - schema: - $ref: '#/components/schemas/Payment' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: 支付未找到 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - put: - summary: 更新支付信息 - description: 根据支付ID更新支付信息(需要认证) - security: - - bearerAuth: [] - parameters: - - name: id - in: path - description: 支付ID - required: true - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/PaymentUpdate' - responses: - '200': - description: 成功更新支付信息 - content: - application/json: - schema: - $ref: '#/components/schemas/Payment' - '400': - description: 请求参数验证失败 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: 支付未找到 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - delete: - summary: 删除支付 - description: 根据支付ID删除支付(需要认证) - security: - - bearerAuth: [] - parameters: - - name: id - in: path - description: 支付ID - required: true - schema: - type: integer - responses: - '200': - description: 成功删除支付 - content: - application/json: - schema: - $ref: '#/components/schemas/Payment' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: 支付未找到 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - -components: - schemas: - Payment: - type: object - properties: - id: - type: integer - description: 支付ID - payment_no: - type: string - description: 支付编号 - order_id: - type: integer - description: 关联订单ID - amount: - type: number - format: float - description: 支付金额 - payment_type: - type: string - enum: [advance, final] - description: 支付类型 - payment_method: - type: string - enum: [alipay, wechat, bank] - description: 支付方式 - status: - type: string - enum: [pending, paid, failed, refunded] - description: 支付状态 - transaction_id: - type: string - description: 第三方交易ID - paid_at: - type: string - format: date-time - description: 支付时间 - remark: - type: string - description: 备注 - created_at: - type: string - format: date-time - description: 创建时间 - updated_at: - type: string - format: date-time - description: 更新时间 - required: - - id - - payment_no - - order_id - - amount - - payment_type - - payment_method - - status - - created_at - - updated_at - - PaymentCreate: - type: object - properties: - order_id: - type: integer - description: 关联订单ID - amount: - type: number - format: float - description: 支付金额 - payment_type: - type: string - enum: [advance, final] - description: 支付类型 - payment_method: - type: string - enum: [alipay, wechat, bank] - description: 支付方式 - status: - type: string - enum: [pending, paid, failed, refunded] - description: 支付状态 - transaction_id: - type: string - description: 第三方交易ID - paid_at: - type: string - format: date-time - description: 支付时间 - remark: - type: string - description: 备注 - required: - - order_id - - amount - - payment_type - - payment_method - - PaymentUpdate: - type: object - properties: - order_id: - type: integer - description: 关联订单ID - amount: - type: number - format: float - description: 支付金额 - payment_type: - type: string - enum: [advance, final] - description: 支付类型 - payment_method: - type: string - enum: [alipay, wechat, bank] - description: 支付方式 - status: - type: string - enum: [pending, paid, failed, refunded] - description: 支付状态 - transaction_id: - type: string - description: 第三方交易ID - paid_at: - type: string - format: date-time - description: 支付时间 - remark: - type: string - description: 备注 - - Error: - type: object - properties: - error: - type: string - description: 错误信息 - required: - - error - - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT \ No newline at end of file diff --git a/go-backend/docs/users.yaml b/go-backend/docs/users.yaml deleted file mode 100644 index 520620a..0000000 --- a/go-backend/docs/users.yaml +++ /dev/null @@ -1,280 +0,0 @@ -openapi: 3.0.0 -info: - title: 用户管理API - description: 用户管理相关接口文档 - version: 1.0.0 - -paths: - /api/login: - post: - summary: 用户登录 - description: 用户登录并获取JWT令牌 - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - username: - type: string - description: 用户名 - password: - type: string - description: 密码 - required: - - username - - password - responses: - '200': - description: 登录成功,返回访问令牌 - content: - application/json: - schema: - type: object - properties: - access_token: - type: string - description: JWT访问令牌 - token_type: - type: string - description: 令牌类型 - '400': - description: 请求参数错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: 用户名或密码错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /api/users: - get: - summary: 获取用户列表 - description: 获取系统中的用户列表,支持分页 - parameters: - - name: skip - in: query - description: 跳过的记录数 - required: false - schema: - type: integer - default: 0 - - name: limit - in: query - description: 返回的记录数 - required: false - schema: - type: integer - default: 100 - responses: - '200': - description: 成功返回用户列表 - content: - application/json: - schema: - type: array - items: - $ref: '#/components/schemas/User' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - /api/users/{id}: - get: - summary: 获取用户详情 - description: 根据用户ID获取用户详细信息 - parameters: - - name: id - in: path - description: 用户ID - required: true - schema: - type: integer - responses: - '200': - description: 成功返回用户信息 - content: - application/json: - schema: - $ref: '#/components/schemas/User' - '404': - description: 用户未找到 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - put: - summary: 更新用户信息 - description: 根据用户ID更新用户信息(需要认证) - security: - - bearerAuth: [] - parameters: - - name: id - in: path - description: 用户ID - required: true - schema: - type: integer - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/UserUpdate' - responses: - '200': - description: 成功更新用户信息 - content: - application/json: - schema: - $ref: '#/components/schemas/User' - '400': - description: 请求参数验证失败 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: 用户未找到 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - delete: - summary: 删除用户 - description: 根据用户ID删除用户(需要认证) - security: - - bearerAuth: [] - parameters: - - name: id - in: path - description: 用户ID - required: true - schema: - type: integer - responses: - '200': - description: 成功删除用户 - content: - application/json: - schema: - $ref: '#/components/schemas/User' - '401': - description: 未授权 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '404': - description: 用户未找到 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '500': - description: 服务器内部错误 - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - -components: - schemas: - User: - type: object - properties: - id: - type: integer - description: 用户ID - uuid: - type: string - description: 用户UUID - username: - type: string - description: 用户名 - user_type: - type: string - enum: [client, supplier, driver, staff, admin] - description: 用户类型 - status: - type: string - enum: [active, inactive, locked] - description: 用户状态 - created_at: - type: string - format: date-time - description: 创建时间 - updated_at: - type: string - format: date-time - description: 更新时间 - required: - - id - - uuid - - username - - user_type - - status - - created_at - - updated_at - - UserUpdate: - type: object - properties: - username: - type: string - description: 用户名 - user_type: - type: string - enum: [client, supplier, driver, staff, admin] - description: 用户类型 - status: - type: string - enum: [active, inactive, locked] - description: 用户状态 - - Error: - type: object - properties: - error: - type: string - description: 错误信息 - required: - - error - - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT \ No newline at end of file diff --git a/go-backend/go.mod b/go-backend/go.mod deleted file mode 100644 index a1a3a1c..0000000 --- a/go-backend/go.mod +++ /dev/null @@ -1,42 +0,0 @@ -module niumall-go - -go 1.19 - -require ( - github.com/gin-gonic/gin v1.9.1 - github.com/golang-jwt/jwt/v5 v5.0.0 - github.com/google/uuid v1.6.0 - github.com/joho/godotenv v1.5.1 - golang.org/x/crypto v0.10.0 - gorm.io/driver/mysql v1.5.1 - gorm.io/gorm v1.25.1 -) - -require ( - github.com/bytedance/sonic v1.9.1 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect - github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-playground/locales v0.14.1 // indirect - github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.14.0 // indirect - github.com/go-sql-driver/mysql v1.7.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.5 // indirect - github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect - github.com/leodido/go-urn v1.2.4 // indirect - github.com/mattn/go-isatty v0.0.19 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect - github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect - golang.org/x/arch v0.3.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sys v0.9.0 // indirect - golang.org/x/text v0.10.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/go-backend/go.sum b/go-backend/go.sum deleted file mode 100644 index 53fd24b..0000000 --- a/go-backend/go.sum +++ /dev/null @@ -1,101 +0,0 @@ -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= -github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= -github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= -github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= -github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= -github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= -github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= -github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= -github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/mysql v1.5.1 h1:WUEH5VF9obL/lTtzjmML/5e6VfFR/788coz2uaVCAZw= -gorm.io/driver/mysql v1.5.1/go.mod h1:Jo3Xu7mMhCyj8dlrb3WoCaRd1FhsVh+yMXb1jUInf5o= -gorm.io/gorm v1.25.1 h1:nsSALe5Pr+cM3V1qwwQ7rOkw+6UeLrX5O4v3llhHa64= -gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/go-backend/main.go b/go-backend/main.go deleted file mode 100644 index ca3ebfb..0000000 --- a/go-backend/main.go +++ /dev/null @@ -1,45 +0,0 @@ -package main - -import ( - "log" - "os" - - "github.com/gin-gonic/gin" - "github.com/joho/godotenv" - - "niumall-go/config" - "niumall-go/routes" -) - -func main() { - // Load environment variables - if err := godotenv.Load(); err != nil { - log.Println("No .env file found") - } - - // Initialize database - config.InitDB() - - // Set Gin to release mode in production - if os.Getenv("GIN_MODE") == "release" { - gin.SetMode(gin.ReleaseMode) - } - - // Create Gin router - router := gin.Default() - - // Register routes - routes.RegisterRoutes(router) - - // Get port from environment variable or use default - port := os.Getenv("PORT") - if port == "" { - port = "8080" - } - - // Start server - log.Printf("Server starting on port %s", port) - if err := router.Run(":" + port); err != nil { - log.Fatalf("Failed to start server: %v", err) - } -} \ No newline at end of file diff --git a/go-backend/middleware/auth.go b/go-backend/middleware/auth.go deleted file mode 100644 index 7382fd9..0000000 --- a/go-backend/middleware/auth.go +++ /dev/null @@ -1,45 +0,0 @@ -package middleware - -import ( - "net/http" - "strings" - - "github.com/gin-gonic/gin" - - "niumall-go/utils" -) - -// AuthMiddleware authenticates requests using JWT -func AuthMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - // Get authorization header - authHeader := c.GetHeader("Authorization") - if authHeader == "" { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"}) - c.Abort() - return - } - - // Check if header has Bearer prefix - if !strings.HasPrefix(authHeader, "Bearer ") { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid authorization header format"}) - c.Abort() - return - } - - // Extract token - tokenString := strings.TrimPrefix(authHeader, "Bearer ") - - // Parse and validate token - claims, err := utils.ParseJWT(tokenString) - if err != nil { - c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid or expired token"}) - c.Abort() - return - } - - // Set user UUID in context for use in handlers - c.Set("user_uuid", claims.UUID) - c.Next() - } -} \ No newline at end of file diff --git a/go-backend/models/order.go b/go-backend/models/order.go deleted file mode 100644 index b2d3492..0000000 --- a/go-backend/models/order.go +++ /dev/null @@ -1,44 +0,0 @@ -package models - -import ( - "time" - - "gorm.io/gorm" -) - -type OrderStatus string - -const ( - OrderStatusPending OrderStatus = "pending" - OrderStatusConfirmed OrderStatus = "confirmed" - OrderStatusProcessing OrderStatus = "processing" - OrderStatusShipped OrderStatus = "shipped" - OrderStatusDelivered OrderStatus = "delivered" - OrderStatusCancelled OrderStatus = "cancelled" - OrderStatusCompleted OrderStatus = "completed" -) - -type Order struct { - ID uint `gorm:"primaryKey" json:"id"` - OrderNo string `gorm:"uniqueIndex;not null" json:"order_no"` - BuyerID uint `gorm:"not null" json:"buyer_id"` - SellerID uint `gorm:"not null" json:"seller_id"` - VarietyType string `gorm:"not null" json:"variety_type"` - WeightRange string `gorm:"not null" json:"weight_range"` - WeightActual float64 `json:"weight_actual"` - PricePerUnit float64 `gorm:"not null" json:"price_per_unit"` - TotalPrice float64 `gorm:"not null" json:"total_price"` - AdvancePayment float64 `gorm:"default:0.0" json:"advance_payment"` - FinalPayment float64 `gorm:"default:0.0" json:"final_payment"` - Status OrderStatus `gorm:"default:pending" json:"status"` - DeliveryAddress string `json:"delivery_address"` - DeliveryTime *time.Time `json:"delivery_time"` - Remark string `json:"remark"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` -} - -func (Order) TableName() string { - return "orders" -} \ No newline at end of file diff --git a/go-backend/models/payment.go b/go-backend/models/payment.go deleted file mode 100644 index 963d34a..0000000 --- a/go-backend/models/payment.go +++ /dev/null @@ -1,44 +0,0 @@ -package models - -import ( - "time" - - "gorm.io/gorm" -) - -type PaymentType string -type PaymentMethod string -type PaymentStatus string - -const ( - PaymentTypeAdvance PaymentType = "advance" - PaymentTypeFinal PaymentType = "final" - - PaymentMethodWechat PaymentMethod = "wechat" - PaymentMethodAlipay PaymentMethod = "alipay" - PaymentMethodBank PaymentMethod = "bank" - - PaymentStatusPending PaymentStatus = "pending" - PaymentStatusSuccess PaymentStatus = "success" - PaymentStatusFailed PaymentStatus = "failed" - PaymentStatusRefunded PaymentStatus = "refunded" -) - -type Payment struct { - ID uint `gorm:"primaryKey" json:"id"` - PaymentNo string `gorm:"uniqueIndex;not null" json:"payment_no"` - OrderID uint `gorm:"not null" json:"order_id"` - UserID uint `gorm:"not null" json:"user_id"` - Amount float64 `gorm:"not null" json:"amount"` - PaymentType PaymentType `gorm:"not null" json:"payment_type"` - PaymentMethod PaymentMethod `gorm:"not null" json:"payment_method"` - Status PaymentStatus `gorm:"default:pending" json:"status"` - TransactionID string `json:"transaction_id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` -} - -func (Payment) TableName() string { - return "payments" -} \ No newline at end of file diff --git a/go-backend/models/user.go b/go-backend/models/user.go deleted file mode 100644 index 5747ca6..0000000 --- a/go-backend/models/user.go +++ /dev/null @@ -1,38 +0,0 @@ -package models - -import ( - "time" - - "gorm.io/gorm" -) - -type UserType string -type UserStatus string - -const ( - UserTypeClient UserType = "client" - UserTypeSupplier UserType = "supplier" - UserTypeDriver UserType = "driver" - UserTypeStaff UserType = "staff" - UserTypeAdmin UserType = "admin" - - UserStatusActive UserStatus = "active" - UserStatusInactive UserStatus = "inactive" - UserStatusLocked UserStatus = "locked" -) - -type User struct { - ID uint `gorm:"primaryKey" json:"id"` - UUID string `gorm:"uniqueIndex;not null" json:"uuid"` - Username string `gorm:"not null" json:"username"` - Password string `gorm:"not null" json:"-"` - UserType UserType `gorm:"default:client" json:"user_type"` - Status UserStatus `gorm:"default:active" json:"status"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` -} - -func (User) TableName() string { - return "users" -} \ No newline at end of file diff --git a/go-backend/niumall-go-backend b/go-backend/niumall-go-backend deleted file mode 100755 index 4d8a4b7..0000000 Binary files a/go-backend/niumall-go-backend and /dev/null differ diff --git a/go-backend/routes/routes.go b/go-backend/routes/routes.go deleted file mode 100644 index d70000d..0000000 --- a/go-backend/routes/routes.go +++ /dev/null @@ -1,44 +0,0 @@ -package routes - -import ( - "github.com/gin-gonic/gin" - - "niumall-go/controllers" - "niumall-go/middleware" -) - -func RegisterRoutes(router *gin.Engine) { - // Public routes - public := router.Group("/api") - { - // User authentication - public.POST("/login", controllers.Login) - - // Public user routes - public.GET("/users", controllers.GetUsers) - public.GET("/users/:id", controllers.GetUserByID) - } - - // Protected routes - protected := router.Group("/api") - protected.Use(middleware.AuthMiddleware()) - { - // User routes - protected.PUT("/users/:id", controllers.UpdateUser) - protected.DELETE("/users/:id", controllers.DeleteUser) - - // Order routes - protected.GET("/orders", controllers.GetOrders) - protected.GET("/orders/:id", controllers.GetOrderByID) - protected.POST("/orders", controllers.CreateOrder) - protected.PUT("/orders/:id", controllers.UpdateOrder) - protected.DELETE("/orders/:id", controllers.DeleteOrder) - - // Payment routes - protected.GET("/payments", controllers.GetPayments) - protected.GET("/payments/:id", controllers.GetPaymentByID) - protected.POST("/payments", controllers.CreatePayment) - protected.PUT("/payments/:id", controllers.UpdatePayment) - protected.DELETE("/payments/:id", controllers.DeletePayment) - } -} \ No newline at end of file diff --git a/go-backend/start_dev.sh b/go-backend/start_dev.sh deleted file mode 100755 index c43ddfc..0000000 --- a/go-backend/start_dev.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# 本地开发启动脚本 - -echo "正在启动NiūMall Go后端开发环境..." - -# 检查是否安装了Go -if ! command -v go &> /dev/null -then - echo "未检测到Go环境,请先安装Go 1.21或更高版本" - exit 1 -fi - -# 检查是否安装了Docker -if ! command -v docker &> /dev/null -then - echo "未检测到Docker,请先安装Docker" - exit 1 -fi - -# 检查是否安装了docker-compose -if ! command -v docker-compose &> /dev/null -then - echo "未检测到docker-compose,请先安装docker-compose" - exit 1 -fi - -# 设置环境变量 -export DB_HOST=localhost -export DB_PORT=3306 -export DB_USER=root -export DB_PASSWORD= -export DB_NAME=niumall_dev -export PORT=8080 -export GIN_MODE=debug -export JWT_SECRET=mysecretkey - -# 创建开发数据库(如果不存在) -echo "正在创建开发数据库..." -mysql -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASSWORD -e "CREATE DATABASE IF NOT EXISTS $DB_NAME;" 2>/dev/null || { - echo "警告:无法创建数据库,请确保MySQL服务正在运行且凭据正确" -} - -# 启动Go应用 -echo "正在启动Go应用..." -go run main.go \ No newline at end of file diff --git a/go-backend/utils/jwt.go b/go-backend/utils/jwt.go deleted file mode 100644 index 392325e..0000000 --- a/go-backend/utils/jwt.go +++ /dev/null @@ -1,62 +0,0 @@ -package utils - -import ( - "os" - "time" - - "github.com/golang-jwt/jwt/v5" -) - -var jwtSecret = []byte(os.Getenv("JWT_SECRET")) - -type Claims struct { - UUID string `json:"uuid"` - jwt.RegisteredClaims -} - -// GenerateJWT generates a new JWT token for a user -func GenerateJWT(uuid string) (string, error) { - // Set expiration time (24 hours from now) - expirationTime := time.Now().Add(24 * time.Hour) - - // Create claims - claims := &Claims{ - UUID: uuid, - RegisteredClaims: jwt.RegisteredClaims{ - ExpiresAt: jwt.NewNumericDate(expirationTime), - IssuedAt: jwt.NewNumericDate(time.Now()), - }, - } - - // Create token with claims - token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) - - // Generate encoded token - tokenString, err := token.SignedString(jwtSecret) - if err != nil { - return "", err - } - - return tokenString, nil -} - -// ParseJWT parses and validates a JWT token -func ParseJWT(tokenString string) (*Claims, error) { - claims := &Claims{} - - // Parse token - token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) { - return jwtSecret, nil - }) - - if err != nil { - return nil, err - } - - // Check if token is valid - if !token.Valid { - return nil, jwt.ErrTokenMalformed - } - - return claims, nil -} \ No newline at end of file diff --git a/go-backend/utils/password.go b/go-backend/utils/password.go deleted file mode 100644 index 1c2da0d..0000000 --- a/go-backend/utils/password.go +++ /dev/null @@ -1,17 +0,0 @@ -package utils - -import ( - "golang.org/x/crypto/bcrypt" -) - -// HashPassword generates a bcrypt hash of the password -func HashPassword(password string) (string, error) { - bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - return string(bytes), err -} - -// CheckPasswordHash compares a bcrypt hashed password with its possible plaintext equivalent -func CheckPasswordHash(password, hash string) bool { - err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password)) - return err == nil -} \ No newline at end of file diff --git a/test-order-query.js b/test-order-query.js new file mode 100644 index 0000000..2717d85 --- /dev/null +++ b/test-order-query.js @@ -0,0 +1,31 @@ +const axios = require('axios'); + +async function testOrderQuery() { + try { + // 首先登录获取token + const loginResponse = await axios.post('http://localhost:4330/api/auth/login', { + username: 'testuser', + password: 'testpassword' + }, { + headers: { 'Content-Type': 'application/json' } + }); + + const token = loginResponse.data.data.token; + console.log('登录成功,Token:', token); + + // 测试订单查询 + const ordersResponse = await axios.get('http://localhost:4330/api/orders', { + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + } + }); + + console.log('订单查询成功:', ordersResponse.data); + + } catch (error) { + console.error('测试失败:', error.response?.data || error.message); + } +} + +testOrderQuery(); \ No newline at end of file diff --git a/test-orders.js b/test-orders.js new file mode 100644 index 0000000..07e97f7 --- /dev/null +++ b/test-orders.js @@ -0,0 +1,32 @@ +const axios = require('axios'); + +async function testOrders() { + try { + // 使用已知的有效测试账户 + const loginResponse = await axios.post('http://localhost:4330/api/auth/login', { + username: 'admin', + password: 'admin123' + }, { + headers: { 'Content-Type': 'application/json' } + }); + + const token = loginResponse.data.data.token; + console.log('登录成功,Token:', token); + + // 测试订单查询 + const ordersResponse = await axios.get('http://localhost:4330/api/orders', { + headers: { + 'Authorization': `Bearer ${token}`, + 'Content-Type': 'application/json' + } + }); + + console.log('订单查询成功:', JSON.stringify(ordersResponse.data, null, 2)); + + } catch (error) { + console.error('测试失败:', error.response?.data || error.message); + } +} + +// 等待服务器启动 +setTimeout(testOrders, 3000); \ No newline at end of file