更新项目文档,明确小程序独立架构和技术选型
This commit is contained in:
34
mini_program/client-mp/package.json
Normal file
34
mini_program/client-mp/package.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "client-mp",
|
||||
"version": "1.0.0",
|
||||
"description": "活牛采购智能数字化系统 - 客户端小程序",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "hbuilderx",
|
||||
"build": "hbuilderx build"
|
||||
},
|
||||
"keywords": [
|
||||
"活牛采购",
|
||||
"小程序",
|
||||
"uni-app"
|
||||
],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "^3.0.0-alpha-3070320230701001",
|
||||
"pinia": "^2.1.0",
|
||||
"vue": "^3.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
||||
"@typescript-eslint/parser": "^5.0.0",
|
||||
"@vue/tsconfig": "^0.4.0",
|
||||
"eslint": "^8.0.0",
|
||||
"eslint-config-prettier": "^8.0.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"eslint-plugin-vue": "^9.0.0",
|
||||
"prettier": "^2.0.0",
|
||||
"typescript": "^5.0.0"
|
||||
}
|
||||
}
|
||||
0
mini_program/client-mp/src/App.vue
Normal file
0
mini_program/client-mp/src/App.vue
Normal file
30
mini_program/client-mp/src/api/order.ts
Normal file
30
mini_program/client-mp/src/api/order.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { request } from '@/utils/request';
|
||||
import type { IOrder, IOrderStats } from '@/types/order';
|
||||
|
||||
// 获取订单统计
|
||||
export const fetchOrderStats = async (): Promise<IOrderStats> => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/order/stats',
|
||||
method: 'GET'
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('获取订单统计失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取最近订单
|
||||
export const fetchRecentOrders = async (): Promise<IOrder[]> => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/order/recent',
|
||||
method: 'GET'
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('获取最近订单失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
16
mini_program/client-mp/src/api/user.ts
Normal file
16
mini_program/client-mp/src/api/user.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { request } from '@/utils/request';
|
||||
import type { IUser } from '@/types/user';
|
||||
|
||||
// 获取用户信息
|
||||
export const fetchUserInfo = async (): Promise<IUser> => {
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/user/info',
|
||||
method: 'GET'
|
||||
});
|
||||
return res.data;
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
30
mini_program/client-mp/src/main.ts
Normal file
30
mini_program/client-mp/src/main.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { createSSRApp } from 'vue';
|
||||
import App from './App.vue';
|
||||
import { createPinia } from 'pinia';
|
||||
import * as Pinia from 'pinia';
|
||||
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App);
|
||||
const pinia = createPinia();
|
||||
|
||||
// 配置Pinia
|
||||
pinia.use(({ store }) => {
|
||||
// 持久化存储
|
||||
const storageKey = `pinia_${store.$id}`;
|
||||
const savedState = uni.getStorageSync(storageKey);
|
||||
if (savedState) {
|
||||
store.$patch(JSON.parse(savedState));
|
||||
}
|
||||
|
||||
store.$subscribe((mutation, state) => {
|
||||
uni.setStorageSync(storageKey, JSON.stringify(state));
|
||||
});
|
||||
});
|
||||
|
||||
app.use(pinia);
|
||||
|
||||
return {
|
||||
app,
|
||||
pinia
|
||||
};
|
||||
}
|
||||
84
mini_program/client-mp/src/manifest.json
Normal file
84
mini_program/client-mp/src/manifest.json
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"name": "活牛采购-客户端",
|
||||
"appid": "",
|
||||
"description": "活牛采购智能数字化系统客户端小程序",
|
||||
"versionName": "1.0.0",
|
||||
"versionCode": "100",
|
||||
"transformPx": false,
|
||||
"app-plus": {
|
||||
"usingComponents": true,
|
||||
"nvueStyleCompiler": "uni-app",
|
||||
"compilerVersion": 3,
|
||||
"splashscreen": {
|
||||
"alwaysShowBeforeRender": true,
|
||||
"waiting": true,
|
||||
"autoclose": true,
|
||||
"delay": 0
|
||||
},
|
||||
"modules": {},
|
||||
"distribute": {
|
||||
"android": {
|
||||
"permissions": [
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.INTERNET\"/>",
|
||||
"<uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
|
||||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||
"<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>"
|
||||
]
|
||||
},
|
||||
"ios": {
|
||||
"dSYMs": false,
|
||||
"privacyDescription": {
|
||||
"NSLocationWhenInUseUsageDescription": "此应用需要访问您的位置信息,以便提供运输跟踪服务",
|
||||
"NSCameraUsageDescription": "此应用需要访问您的相机,以便上传照片和视频",
|
||||
"NSPhotoLibraryUsageDescription": "此应用需要访问您的相册,以便选择照片和视频",
|
||||
"NSMicrophoneUsageDescription": "此应用需要访问您的麦克风,以便录制视频"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"mp-weixin": {
|
||||
"appid": "wx0123456789abcdef",
|
||||
"setting": {
|
||||
"urlCheck": false,
|
||||
"es6": true,
|
||||
"postcss": true,
|
||||
"minified": true
|
||||
},
|
||||
"usingComponents": true,
|
||||
"permission": {
|
||||
"scope.userLocation": {
|
||||
"desc": "您的位置信息将用于运输跟踪服务"
|
||||
}
|
||||
},
|
||||
"requiredPrivateInfos": [
|
||||
"getLocation",
|
||||
"chooseLocation"
|
||||
]
|
||||
},
|
||||
"mp-alipay": {
|
||||
"usingComponents": true,
|
||||
"appid": "2021000000000000"
|
||||
},
|
||||
"vueVersion": "3",
|
||||
"h5": {
|
||||
"router": {
|
||||
"mode": "hash",
|
||||
"base": "/"
|
||||
},
|
||||
"title": "活牛采购-客户端",
|
||||
"optimization": {
|
||||
"treeShaking": {
|
||||
"enable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
140
mini_program/client-mp/src/pages.json
Normal file
140
mini_program/client-mp/src/pages.json
Normal file
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "活牛采购",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/order-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订单管理",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/order-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订单详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/order-create",
|
||||
"style": {
|
||||
"navigationBarTitleText": "创建订单"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/tracking/tracking-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "运输跟踪"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/tracking/tracking-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "运输详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/acceptance/acceptance-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "验收管理"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/acceptance/acceptance-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "验收详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/payment/payment-list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "结算支付"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/payment/payment-detail",
|
||||
"style": {
|
||||
"navigationBarTitleText": "结算详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/statistics/statistics",
|
||||
"style": {
|
||||
"navigationBarTitleText": "数据统计"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/auth/login",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/auth/register",
|
||||
"style": {
|
||||
"navigationBarTitleText": "注册"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/user/profile",
|
||||
"style": {
|
||||
"navigationBarTitleText": "个人中心"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/user/settings",
|
||||
"style": {
|
||||
"navigationBarTitleText": "设置"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "活牛采购",
|
||||
"navigationBarBackgroundColor": "#F8F8F8",
|
||||
"backgroundColor": "#F8F8F8"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#7A7E83",
|
||||
"selectedColor": "#3cc51f",
|
||||
"borderStyle": "black",
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/index/index",
|
||||
"iconPath": "static/images/tabbar/home.png",
|
||||
"selectedIconPath": "static/images/tabbar/home-active.png",
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/order/order-list",
|
||||
"iconPath": "static/images/tabbar/order.png",
|
||||
"selectedIconPath": "static/images/tabbar/order-active.png",
|
||||
"text": "订单"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/tracking/tracking-list",
|
||||
"iconPath": "static/images/tabbar/tracking.png",
|
||||
"selectedIconPath": "static/images/tabbar/tracking-active.png",
|
||||
"text": "跟踪"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/user/profile",
|
||||
"iconPath": "static/images/tabbar/user.png",
|
||||
"selectedIconPath": "static/images/tabbar/user-active.png",
|
||||
"text": "我的"
|
||||
}
|
||||
]
|
||||
},
|
||||
"easycom": {
|
||||
"autoscan": true,
|
||||
"custom": {
|
||||
"^uni-(.*)": "@dcloudio/uni-ui/lib/uni-$1/uni-$1.vue"
|
||||
}
|
||||
}
|
||||
}
|
||||
289
mini_program/client-mp/src/pages/index/index.vue
Normal file
289
mini_program/client-mp/src/pages/index/index.vue
Normal file
@@ -0,0 +1,289 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useOrderStore } from '@/stores/order';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
import type { IHomeData } from './types';
|
||||
|
||||
// 状态管理
|
||||
const orderStore = useOrderStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
// 页面数据
|
||||
const homeData = ref<IHomeData>({
|
||||
pendingOrders: 0,
|
||||
inTransitOrders: 0,
|
||||
pendingAcceptance: 0,
|
||||
pendingPayment: 0,
|
||||
recentOrders: [],
|
||||
statistics: {
|
||||
totalAmount: 0,
|
||||
totalWeight: 0,
|
||||
averagePrice: 0
|
||||
}
|
||||
});
|
||||
|
||||
// 加载数据
|
||||
const loading = ref(false);
|
||||
const loadData = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
await Promise.all([
|
||||
orderStore.fetchOrderStats(),
|
||||
orderStore.fetchRecentOrders(),
|
||||
userStore.fetchUserInfo()
|
||||
]);
|
||||
|
||||
homeData.value = {
|
||||
pendingOrders: orderStore.pendingCount,
|
||||
inTransitOrders: orderStore.inTransitCount,
|
||||
pendingAcceptance: orderStore.pendingAcceptanceCount,
|
||||
pendingPayment: orderStore.pendingPaymentCount,
|
||||
recentOrders: orderStore.recentOrders.slice(0, 5),
|
||||
statistics: {
|
||||
totalAmount: orderStore.totalAmount,
|
||||
totalWeight: orderStore.totalWeight,
|
||||
averagePrice: orderStore.averagePrice
|
||||
}
|
||||
};
|
||||
} catch (error) {
|
||||
uni.showToast({
|
||||
title: '加载数据失败',
|
||||
icon: 'none'
|
||||
});
|
||||
console.error('加载首页数据失败:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 页面生命周期
|
||||
onMounted(() => {
|
||||
loadData();
|
||||
});
|
||||
|
||||
// 下拉刷新
|
||||
const onRefresh = () => {
|
||||
loadData();
|
||||
};
|
||||
|
||||
// 跳转到订单列表
|
||||
const navigateToOrderList = (type: string) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/order/order-list?type=${type}`
|
||||
});
|
||||
};
|
||||
|
||||
// 跳转到订单详情
|
||||
const navigateToOrderDetail = (id: string) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/order/order-detail?id=${id}`
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<!-- 下拉刷新 -->
|
||||
<scroll-view
|
||||
scroll-y
|
||||
refresher-enabled
|
||||
:refresher-triggered="loading"
|
||||
@refresherrefresh="onRefresh"
|
||||
>
|
||||
<!-- 用户信息 -->
|
||||
<view class="user-info card">
|
||||
<view class="flex-between">
|
||||
<view>
|
||||
<text class="text-bold">欢迎回来,{{ userStore.userInfo.name }}</text>
|
||||
<view class="margin-top-sm text-gray">
|
||||
<text>上次登录: {{ userStore.userInfo.lastLogin }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<image
|
||||
:src="userStore.userInfo.avatar"
|
||||
mode="aspectFill"
|
||||
class="avatar"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 订单概览 -->
|
||||
<view class="order-overview card">
|
||||
<view class="flex-between">
|
||||
<text class="text-bold">订单概览</text>
|
||||
<text class="text-primary" @tap="navigateToOrderList('all')">查看全部</text>
|
||||
</view>
|
||||
|
||||
<view class="flex-between margin-top">
|
||||
<view
|
||||
class="overview-item"
|
||||
@tap="navigateToOrderList('pending')"
|
||||
>
|
||||
<text class="overview-count">{{ homeData.pendingOrders }}</text>
|
||||
<text class="overview-label">待处理</text>
|
||||
</view>
|
||||
<view
|
||||
class="overview-item"
|
||||
@tap="navigateToOrderList('in_transit')"
|
||||
>
|
||||
<text class="overview-count">{{ homeData.inTransitOrders }}</text>
|
||||
<text class="overview-label">运输中</text>
|
||||
</view>
|
||||
<view
|
||||
class="overview-item"
|
||||
@tap="navigateToOrderList('pending_acceptance')"
|
||||
>
|
||||
<text class="overview-count">{{ homeData.pendingAcceptance }}</text>
|
||||
<text class="overview-label">待验收</text>
|
||||
</view>
|
||||
<view
|
||||
class="overview-item"
|
||||
@tap="navigateToOrderList('pending_payment')"
|
||||
>
|
||||
<text class="overview-count">{{ homeData.pendingPayment }}</text>
|
||||
<text class="overview-label">待支付</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 统计信息 -->
|
||||
<view class="statistics card">
|
||||
<view class="flex-between">
|
||||
<text class="text-bold">采购统计</text>
|
||||
<text class="text-primary">本月</text>
|
||||
</view>
|
||||
|
||||
<view class="flex-between margin-top">
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">¥{{ homeData.statistics.totalAmount }}</text>
|
||||
<text class="stat-label">总金额</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">{{ homeData.statistics.totalWeight }}kg</text>
|
||||
<text class="stat-label">总重量</text>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<text class="stat-value">¥{{ homeData.statistics.averagePrice }}</text>
|
||||
<text class="stat-label">均价/kg</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 最近订单 -->
|
||||
<view class="recent-orders card">
|
||||
<view class="flex-between">
|
||||
<text class="text-bold">最近订单</text>
|
||||
<text class="text-primary" @tap="navigateToOrderList('all')">查看全部</text>
|
||||
</view>
|
||||
|
||||
<view class="margin-top">
|
||||
<view
|
||||
v-for="order in homeData.recentOrders"
|
||||
:key="order.id"
|
||||
class="order-item"
|
||||
@tap="navigateToOrderDetail(order.id)"
|
||||
>
|
||||
<view class="flex-between">
|
||||
<text class="text-bold">订单号: {{ order.orderNo }}</text>
|
||||
<text :class="`status-${order.status}`">{{ order.statusText }}</text>
|
||||
</view>
|
||||
<view class="flex-between margin-top-sm">
|
||||
<text>供应商: {{ order.supplierName }}</text>
|
||||
<text>{{ order.createTime }}</text>
|
||||
</view>
|
||||
<view class="flex-between margin-top-sm">
|
||||
<text>数量: {{ order.quantity }}头</text>
|
||||
<text>重量: {{ order.weight }}kg</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: #fff;
|
||||
border-radius: 8rpx;
|
||||
box-shadow: 0 2rpx 12rpx 0 rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 20rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
.avatar {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.overview-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.overview-count {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #3cc51f;
|
||||
}
|
||||
|
||||
.overview-label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.stat-value {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.order-item {
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
color: #ff9900;
|
||||
}
|
||||
|
||||
.status-in_transit {
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.status-pending_acceptance {
|
||||
color: #ff9900;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
color: #3cc51f;
|
||||
}
|
||||
|
||||
.status-canceled {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
25
mini_program/client-mp/src/pages/index/types.ts
Normal file
25
mini_program/client-mp/src/pages/index/types.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
// 首页数据类型定义
|
||||
export interface IHomeData {
|
||||
pendingOrders: number;
|
||||
inTransitOrders: number;
|
||||
pendingAcceptance: number;
|
||||
pendingPayment: number;
|
||||
recentOrders: IRecentOrder[];
|
||||
statistics: {
|
||||
totalAmount: number;
|
||||
totalWeight: number;
|
||||
averagePrice: number;
|
||||
};
|
||||
}
|
||||
|
||||
// 最近订单类型定义
|
||||
export interface IRecentOrder {
|
||||
id: string;
|
||||
orderNo: string;
|
||||
supplierName: string;
|
||||
quantity: number;
|
||||
weight: number;
|
||||
status: string;
|
||||
statusText: string;
|
||||
createTime: string;
|
||||
}
|
||||
59
mini_program/client-mp/src/stores/order.ts
Normal file
59
mini_program/client-mp/src/stores/order.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import type { IOrder, IOrderStats } from '@/types/order';
|
||||
import { fetchOrderStats, fetchRecentOrders } from '@/api/order';
|
||||
|
||||
export const useOrderStore = defineStore('order', () => {
|
||||
// 订单统计
|
||||
const pendingCount = ref(0);
|
||||
const inTransitCount = ref(0);
|
||||
const pendingAcceptanceCount = ref(0);
|
||||
const pendingPaymentCount = ref(0);
|
||||
const totalAmount = ref(0);
|
||||
const totalWeight = ref(0);
|
||||
const averagePrice = ref(0);
|
||||
|
||||
// 最近订单
|
||||
const recentOrders = ref<IOrder[]>([]);
|
||||
|
||||
// 获取订单统计
|
||||
const fetchOrderStats = async () => {
|
||||
try {
|
||||
const stats = await fetchOrderStats();
|
||||
pendingCount.value = stats.pendingCount;
|
||||
inTransitCount.value = stats.inTransitCount;
|
||||
pendingAcceptanceCount.value = stats.pendingAcceptanceCount;
|
||||
pendingPaymentCount.value = stats.pendingPaymentCount;
|
||||
totalAmount.value = stats.totalAmount;
|
||||
totalWeight.value = stats.totalWeight;
|
||||
averagePrice.value = stats.averagePrice;
|
||||
} catch (error) {
|
||||
console.error('获取订单统计失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
// 获取最近订单
|
||||
const fetchRecentOrders = async () => {
|
||||
try {
|
||||
const orders = await fetchRecentOrders();
|
||||
recentOrders.value = orders;
|
||||
} catch (error) {
|
||||
console.error('获取最近订单失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
pendingCount,
|
||||
inTransitCount,
|
||||
pendingAcceptanceCount,
|
||||
pendingPaymentCount,
|
||||
totalAmount,
|
||||
totalWeight,
|
||||
averagePrice,
|
||||
recentOrders,
|
||||
fetchOrderStats,
|
||||
fetchRecentOrders
|
||||
};
|
||||
});
|
||||
33
mini_program/client-mp/src/stores/user.ts
Normal file
33
mini_program/client-mp/src/stores/user.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref } from 'vue';
|
||||
import type { IUser } from '@/types/user';
|
||||
import { fetchUserInfo } from '@/api/user';
|
||||
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
// 用户信息
|
||||
const userInfo = ref<IUser>({
|
||||
id: '',
|
||||
name: '加载中...',
|
||||
avatar: '/static/images/default-avatar.png',
|
||||
lastLogin: '',
|
||||
phone: '',
|
||||
company: '',
|
||||
role: 'client'
|
||||
});
|
||||
|
||||
// 获取用户信息
|
||||
const fetchUserInfo = async () => {
|
||||
try {
|
||||
const info = await fetchUserInfo();
|
||||
userInfo.value = info;
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
userInfo,
|
||||
fetchUserInfo
|
||||
};
|
||||
});
|
||||
35
mini_program/client-mp/src/types/order.ts
Normal file
35
mini_program/client-mp/src/types/order.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
// 订单状态类型
|
||||
export type OrderStatus =
|
||||
| 'pending'
|
||||
| 'confirmed'
|
||||
| 'in_transit'
|
||||
| 'pending_acceptance'
|
||||
| 'completed'
|
||||
| 'canceled';
|
||||
|
||||
// 订单基础信息
|
||||
export interface IOrder {
|
||||
id: string;
|
||||
orderNo: string;
|
||||
supplierId: string;
|
||||
supplierName: string;
|
||||
quantity: number;
|
||||
weight: number;
|
||||
price: number;
|
||||
totalAmount: number;
|
||||
status: OrderStatus;
|
||||
statusText: string;
|
||||
createTime: string;
|
||||
updateTime: string;
|
||||
}
|
||||
|
||||
// 订单统计信息
|
||||
export interface IOrderStats {
|
||||
pendingCount: number;
|
||||
inTransitCount: number;
|
||||
pendingAcceptanceCount: number;
|
||||
pendingPaymentCount: number;
|
||||
totalAmount: number;
|
||||
totalWeight: number;
|
||||
averagePrice: number;
|
||||
}
|
||||
14
mini_program/client-mp/src/types/request.ts
Normal file
14
mini_program/client-mp/src/types/request.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
// 请求选项
|
||||
export interface RequestOptions {
|
||||
url: string;
|
||||
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
||||
data?: any;
|
||||
header?: Record<string, string>;
|
||||
}
|
||||
|
||||
// 响应数据
|
||||
export interface ResponseData<T = any> {
|
||||
code: number;
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
17
mini_program/client-mp/src/types/user.ts
Normal file
17
mini_program/client-mp/src/types/user.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
// 用户角色类型
|
||||
export type UserRole =
|
||||
| 'client'
|
||||
| 'supplier'
|
||||
| 'driver'
|
||||
| 'staff';
|
||||
|
||||
// 用户信息
|
||||
export interface IUser {
|
||||
id: string;
|
||||
name: string;
|
||||
avatar: string;
|
||||
lastLogin: string;
|
||||
phone: string;
|
||||
company: string;
|
||||
role: UserRole;
|
||||
}
|
||||
86
mini_program/client-mp/src/utils/request.ts
Normal file
86
mini_program/client-mp/src/utils/request.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import type { RequestOptions } from '@/types/request';
|
||||
|
||||
// 环境配置
|
||||
const config = {
|
||||
development: {
|
||||
baseURL: 'http://localhost:3001/api',
|
||||
wsURL: 'ws://localhost:3001'
|
||||
},
|
||||
production: {
|
||||
baseURL: 'https://api.niumall.com/api',
|
||||
wsURL: 'wss://api.niumall.com'
|
||||
}
|
||||
};
|
||||
|
||||
// 当前环境
|
||||
const env = process.env.NODE_ENV === 'production' ? 'production' : 'development';
|
||||
const { baseURL, wsURL } = config[env];
|
||||
|
||||
// 请求封装
|
||||
export const request = (options: RequestOptions) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
url: baseURL + options.url,
|
||||
method: options.method || 'GET',
|
||||
data: options.data,
|
||||
header: {
|
||||
'Authorization': `Bearer ${getToken()}`,
|
||||
'Content-Type': 'application/json',
|
||||
...options.header
|
||||
},
|
||||
success: (res) => {
|
||||
if (res.statusCode >= 200 && res.statusCode < 300) {
|
||||
resolve(res.data);
|
||||
} else {
|
||||
handleError(res);
|
||||
reject(res);
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
handleError(err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// WebSocket连接
|
||||
export const connectWebSocket = () => {
|
||||
return uni.connectSocket({
|
||||
url: wsURL,
|
||||
success: () => {
|
||||
console.log('WebSocket连接成功');
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('WebSocket连接失败:', err);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 获取token
|
||||
const getToken = (): string => {
|
||||
try {
|
||||
const token = uni.getStorageSync('token');
|
||||
return token || '';
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
|
||||
// 错误处理
|
||||
const handleError = (error: any) => {
|
||||
console.error('请求错误:', error);
|
||||
|
||||
// 未授权
|
||||
if (error.statusCode === 401) {
|
||||
uni.redirectTo({
|
||||
url: '/pages/auth/login'
|
||||
});
|
||||
}
|
||||
|
||||
// 其他错误
|
||||
uni.showToast({
|
||||
title: error.data?.message || '请求失败',
|
||||
icon: 'none'
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user