实现订单管理核心功能,包括订单创建、查询、取消和状态管理
This commit is contained in:
13
mini_program/driver-mp/package.json
Normal file
13
mini_program/driver-mp/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "driver-mp",
|
||||
"version": "1.0.0",
|
||||
"description": "活牛运输司机小程序",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "uni -p mp-weixin"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "^3.0.0",
|
||||
"pinia": "^2.0.0"
|
||||
}
|
||||
}
|
||||
13
mini_program/sales-mp/package.json
Normal file
13
mini_program/sales-mp/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "sales-mp",
|
||||
"version": "1.0.0",
|
||||
"description": "活牛销售小程序",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "uni -p mp-weixin"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "^3.0.0",
|
||||
"pinia": "^2.0.0"
|
||||
}
|
||||
}
|
||||
15
mini_program/sales-mp/src/pages/index/index.vue
Normal file
15
mini_program/sales-mp/src/pages/index/index.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
// 活牛销售首页
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<text>活牛销售小程序首页</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
</style>
|
||||
48
mini_program/staff-mp/.eslintrc.js
Normal file
48
mini_program/staff-mp/.eslintrc.js
Normal file
@@ -0,0 +1,48 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
browser: true,
|
||||
es2021: true
|
||||
},
|
||||
extends: [
|
||||
'eslint:recommended',
|
||||
'@vue/typescript/recommended'
|
||||
],
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
parser: '@typescript-eslint/parser',
|
||||
sourceType: 'module'
|
||||
},
|
||||
rules: {
|
||||
// 基本规则
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
|
||||
// TypeScript 规则
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
|
||||
// Vue 规则
|
||||
'vue/multi-word-component-names': 'off',
|
||||
'vue/no-v-model-argument': 'off',
|
||||
|
||||
// 代码风格
|
||||
'indent': ['error', 2],
|
||||
'quotes': ['error', 'single'],
|
||||
'semi': ['error', 'always'],
|
||||
'comma-dangle': ['error', 'never'],
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
'array-bracket-spacing': ['error', 'never']
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: ['*.vue'],
|
||||
parser: 'vue-eslint-parser',
|
||||
parserOptions: {
|
||||
parser: '@typescript-eslint/parser'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
7
mini_program/staff-mp/.prettierrc
Normal file
7
mini_program/staff-mp/.prettierrc
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none",
|
||||
"endOfLine": "auto"
|
||||
}
|
||||
29
mini_program/staff-mp/eslint.config.js
Normal file
29
mini_program/staff-mp/eslint.config.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import js from '@eslint/js';
|
||||
import typescript from '@typescript-eslint/eslint-plugin';
|
||||
import typescriptParser from '@typescript-eslint/parser';
|
||||
|
||||
export default [
|
||||
js.configs.recommended,
|
||||
{
|
||||
files: ['**/*.{js,ts}'],
|
||||
languageOptions: {
|
||||
parser: typescriptParser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module'
|
||||
}
|
||||
},
|
||||
plugins: {
|
||||
'@typescript-eslint': typescript
|
||||
},
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/no-unused-vars': 'error',
|
||||
'indent': ['error', 2],
|
||||
'quotes': ['error', 'single'],
|
||||
'semi': ['error', 'always']
|
||||
}
|
||||
}
|
||||
];
|
||||
13469
mini_program/staff-mp/package-lock.json
generated
Normal file
13469
mini_program/staff-mp/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
mini_program/staff-mp/package.json
Normal file
37
mini_program/staff-mp/package.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "staff-mp",
|
||||
"version": "1.0.0",
|
||||
"description": "活牛采购内部员工小程序",
|
||||
"type": "module",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "npx uniapp-cli -p mp-weixin",
|
||||
"build": "npx uniapp-cli build -p mp-weixin",
|
||||
"lint": "eslint --ext .ts src/",
|
||||
"prettier": "prettier --write src/"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "^3.0.0-alpha-3070620220707001",
|
||||
"pinia": "^2.0.0",
|
||||
"vue": "^2.6.0 || ^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@dcloudio/types": "^3.0.0-alpha-3070620220707001",
|
||||
"@dcloudio/uni-cli-i18n": "^2.0.2-4070620250821001",
|
||||
"@dcloudio/uni-cli-shared": "^3.0.0-alpha-3070620220707001",
|
||||
"@dcloudio/uni-mp-weixin": "^3.0.0-alpha-3070620220707001",
|
||||
"@dcloudio/vue-cli-plugin-uni": "^2.0.2-4070620250821001",
|
||||
"@dcloudio/webpack-uni-pages-loader": "^2.0.2-4070620250821001",
|
||||
"@eslint/js": "^9.35.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.44.0",
|
||||
"@typescript-eslint/parser": "^8.44.0",
|
||||
"@vue/cli-service": "^5.0.9",
|
||||
"eslint": "^9.35.0",
|
||||
"eslint-plugin-vue": "^10.4.0",
|
||||
"miniprogram-api-typings": "^3.0.0",
|
||||
"typescript": "^5.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vue": "^2.6.0 || ^3.0.0"
|
||||
}
|
||||
}
|
||||
19
mini_program/staff-mp/src/manifest.json
Normal file
19
mini_program/staff-mp/src/manifest.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "staff-mp",
|
||||
"appid": "__UNI__STAFFMP",
|
||||
"description": "活牛采购内部员工小程序",
|
||||
"versionName": "1.0.0",
|
||||
"versionCode": "100",
|
||||
"transformPx": false,
|
||||
"mp-weixin": {
|
||||
"appid": "wx-your-appid-here",
|
||||
"setting": {
|
||||
"urlCheck": false,
|
||||
"es6": true,
|
||||
"postcss": true,
|
||||
"minified": true
|
||||
},
|
||||
"usingComponents": true
|
||||
},
|
||||
"vueVersion": "3"
|
||||
}
|
||||
72
mini_program/staff-mp/src/pages.json
Normal file
72
mini_program/staff-mp/src/pages.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/order/order-monitor",
|
||||
"style": {
|
||||
"navigationBarTitleText": "订单监控"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/transport/transport-monitor",
|
||||
"style": {
|
||||
"navigationBarTitleText": "运输监控"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/statistics/data-dashboard",
|
||||
"style": {
|
||||
"navigationBarTitleText": "数据统计"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/system/system-settings",
|
||||
"style": {
|
||||
"navigationBarTitleText": "系统设置"
|
||||
}
|
||||
}
|
||||
],
|
||||
"globalStyle": {
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationBarTitleText": "活牛采购系统",
|
||||
"navigationBarBackgroundColor": "#f8f8f8",
|
||||
"backgroundColor": "#f8f8f8"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#7A7E83",
|
||||
"selectedColor": "#1989fa",
|
||||
"borderStyle": "black",
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/index/index",
|
||||
"iconPath": "static/tabbar/home.png",
|
||||
"selectedIconPath": "static/tabbar/home-active.png",
|
||||
"text": "首页"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/order/order-monitor",
|
||||
"iconPath": "static/tabbar/order.png",
|
||||
"selectedIconPath": "static/tabbar/order-active.png",
|
||||
"text": "订单"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/transport/transport-monitor",
|
||||
"iconPath": "static/tabbar/transport.png",
|
||||
"selectedIconPath": "static/tabbar/transport-active.png",
|
||||
"text": "运输"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/statistics/data-dashboard",
|
||||
"iconPath": "static/tabbar/statistics.png",
|
||||
"selectedIconPath": "static/tabbar/statistics-active.png",
|
||||
"text": "统计"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
169
mini_program/staff-mp/src/pages/index/index.vue
Normal file
169
mini_program/staff-mp/src/pages/index/index.vue
Normal file
@@ -0,0 +1,169 @@
|
||||
<script setup lang="ts">
|
||||
// 首页
|
||||
import { ref } from 'vue';
|
||||
|
||||
const quickActions = ref([
|
||||
{
|
||||
icon: 'order',
|
||||
title: '订单管理',
|
||||
path: '/pages/order/order-monitor'
|
||||
},
|
||||
{
|
||||
icon: 'transport',
|
||||
title: '运输监控',
|
||||
path: '/pages/transport/transport-monitor'
|
||||
},
|
||||
{
|
||||
icon: 'statistics',
|
||||
title: '数据统计',
|
||||
path: '/pages/statistics/data-dashboard'
|
||||
},
|
||||
{
|
||||
icon: 'settings',
|
||||
title: '系统设置',
|
||||
path: '/pages/system/system-settings'
|
||||
}
|
||||
]);
|
||||
|
||||
const navigateTo = (path: string) => {
|
||||
uni.navigateTo({
|
||||
url: path
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header">
|
||||
<text class="welcome">欢迎使用活牛采购系统</text>
|
||||
<text class="subtitle">内部员工工作台</text>
|
||||
</view>
|
||||
|
||||
<view class="quick-actions">
|
||||
<view
|
||||
v-for="(action, index) in quickActions"
|
||||
:key="index"
|
||||
class="action-card"
|
||||
@click="navigateTo(action.path)"
|
||||
>
|
||||
<view class="action-icon">
|
||||
<text class="icon">{{ action.icon }}</text>
|
||||
</view>
|
||||
<text class="action-title">{{ action.title }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="recent-section">
|
||||
<text class="section-title">最近动态</text>
|
||||
<view class="recent-list">
|
||||
<view class="recent-item">
|
||||
<text class="recent-text">新订单 #20250001 待审核</text>
|
||||
<text class="recent-time">10分钟前</text>
|
||||
</view>
|
||||
<view class="recent-item">
|
||||
<text class="recent-text">运输车辆 京A12345 已出发</text>
|
||||
<text class="recent-time">30分钟前</text>
|
||||
</view>
|
||||
<view class="recent-item">
|
||||
<text class="recent-text">订单 #20249999 已完成</text>
|
||||
<text class="recent-time">1小时前</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
padding: 40rpx 0;
|
||||
|
||||
.welcome {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
color: #666;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.quick-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.action-card {
|
||||
background: #fff;
|
||||
padding: 30rpx;
|
||||
border-radius: 12rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.action-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background: #1989fa;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 auto 20rpx;
|
||||
|
||||
.icon {
|
||||
color: #fff;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.action-title {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.recent-section {
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
margin-bottom: 20rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.recent-list {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.recent-item {
|
||||
padding: 24rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.recent-text {
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.recent-time {
|
||||
color: #999;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
138
mini_program/staff-mp/src/pages/order/order-monitor.vue
Normal file
138
mini_program/staff-mp/src/pages/order/order-monitor.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<script setup lang="ts">
|
||||
// 订单监控页面
|
||||
import { ref } from 'vue';
|
||||
|
||||
const orders = ref([]);
|
||||
const loading = ref(false);
|
||||
|
||||
// 模拟订单数据
|
||||
const mockOrders = [
|
||||
{ id: '1', orderNo: 'ORDER2025001', supplier: '张三养殖场', status: 'pending', quantity: 50, amount: 250000 },
|
||||
{ id: '2', orderNo: 'ORDER2025002', supplier: '李四牧场', status: 'confirmed', quantity: 30, amount: 150000 },
|
||||
{ id: '3', orderNo: 'ORDER2025003', supplier: '王五畜牧', status: 'in_transit', quantity: 80, amount: 400000 }
|
||||
];
|
||||
|
||||
const loadOrders = async () => {
|
||||
loading.value = true;
|
||||
// 模拟API调用
|
||||
setTimeout(() => {
|
||||
orders.value = mockOrders;
|
||||
loading.value = false;
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
loadOrders();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header">
|
||||
<text class="title">订单监控</text>
|
||||
</view>
|
||||
|
||||
<view class="filter-bar">
|
||||
<picker mode="selector" :range="['全部', '待确认', '已确认', '运输中']">
|
||||
<view class="filter-item">筛选状态</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="order-list">
|
||||
<view v-if="loading" class="loading">加载中...</view>
|
||||
|
||||
<view v-for="order in orders" :key="order.id" class="order-item">
|
||||
<view class="order-header">
|
||||
<text class="order-no">{{ order.orderNo }}</text>
|
||||
<text :class="`status-${order.status}`">{{ order.status }}</text>
|
||||
</view>
|
||||
<view class="order-info">
|
||||
<text>供应商: {{ order.supplier }}</text>
|
||||
<text>数量: {{ order.quantity }}头</text>
|
||||
<text>金额: ¥{{ order.amount }}</text>
|
||||
</view>
|
||||
<view class="order-actions">
|
||||
<button size="mini" @click="handleViewDetail(order.id)">查看详情</button>
|
||||
<button v-if="order.status === 'pending'" size="mini" type="primary" @click="handleApprove(order.id)">审核通过</button>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 20rpx 0;
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-bar {
|
||||
background: #fff;
|
||||
padding: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
.filter-item {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.order-list {
|
||||
height: calc(100vh - 200rpx);
|
||||
}
|
||||
|
||||
.order-item {
|
||||
background: #fff;
|
||||
padding: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
|
||||
.order-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15rpx;
|
||||
|
||||
.order-no {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
color: #ff9900;
|
||||
}
|
||||
.status-confirmed {
|
||||
color: #1989fa;
|
||||
}
|
||||
.status-in_transit {
|
||||
color: #3cc51f;
|
||||
}
|
||||
}
|
||||
|
||||
.order-info {
|
||||
margin-bottom: 15rpx;
|
||||
text {
|
||||
display: block;
|
||||
margin-bottom: 5rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.order-actions {
|
||||
display: flex;
|
||||
gap: 10rpx;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 40rpx;
|
||||
color: #999;
|
||||
}
|
||||
</style>
|
||||
131
mini_program/staff-mp/src/pages/statistics/data-dashboard.vue
Normal file
131
mini_program/staff-mp/src/pages/statistics/data-dashboard.vue
Normal file
@@ -0,0 +1,131 @@
|
||||
<script setup lang="ts">
|
||||
// 数据统计仪表板
|
||||
import { ref } from 'vue';
|
||||
|
||||
const stats = ref({
|
||||
totalOrders: 0,
|
||||
totalAmount: 0,
|
||||
pendingOrders: 0,
|
||||
completedOrders: 0
|
||||
});
|
||||
|
||||
const loadStatistics = async () => {
|
||||
// 模拟API调用
|
||||
setTimeout(() => {
|
||||
stats.value = {
|
||||
totalOrders: 156,
|
||||
totalAmount: 7800000,
|
||||
pendingOrders: 23,
|
||||
completedOrders: 133
|
||||
};
|
||||
}, 500);
|
||||
};
|
||||
|
||||
loadStatistics();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header">
|
||||
<text class="title">数据统计</text>
|
||||
</view>
|
||||
|
||||
<view class="stats-grid">
|
||||
<view class="stat-card">
|
||||
<text class="stat-value">{{ stats.totalOrders }}</text>
|
||||
<text class="stat-label">总订单数</text>
|
||||
</view>
|
||||
<view class="stat-card">
|
||||
<text class="stat-value">¥{{ stats.totalAmount.toLocaleString() }}</text>
|
||||
<text class="stat-label">总金额</text>
|
||||
</view>
|
||||
<view class="stat-card">
|
||||
<text class="stat-value">{{ stats.pendingOrders }}</text>
|
||||
<text class="stat-label">待处理</text>
|
||||
</view>
|
||||
<view class="stat-card">
|
||||
<text class="stat-value">{{ stats.completedOrders }}</text>
|
||||
<text class="stat-label">已完成</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="charts-section">
|
||||
<view class="chart-container">
|
||||
<text class="chart-title">订单状态分布</text>
|
||||
<view class="chart-placeholder">图表组件加载中...</view>
|
||||
</view>
|
||||
|
||||
<view class="chart-container">
|
||||
<text class="chart-title">月度采购趋势</text>
|
||||
<view class="chart-placeholder">图表组件加载中...</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 20rpx 0;
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.stat-card {
|
||||
background: #fff;
|
||||
padding: 30rpx;
|
||||
border-radius: 8rpx;
|
||||
text-align: center;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.stat-value {
|
||||
display: block;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #1989fa;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
color: #666;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.charts-section {
|
||||
.chart-container {
|
||||
background: #fff;
|
||||
padding: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.chart-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 15rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chart-placeholder {
|
||||
height: 200rpx;
|
||||
background: #f5f5f5;
|
||||
border-radius: 4rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
113
mini_program/staff-mp/src/pages/system/system-settings.vue
Normal file
113
mini_program/staff-mp/src/pages/system/system-settings.vue
Normal file
@@ -0,0 +1,113 @@
|
||||
<script setup lang="ts">
|
||||
// 系统设置页面
|
||||
import { ref } from 'vue';
|
||||
|
||||
const settings = ref({
|
||||
notifications: true,
|
||||
autoRefresh: true,
|
||||
refreshInterval: 30,
|
||||
theme: 'light'
|
||||
});
|
||||
|
||||
const saveSettings = async () => {
|
||||
// 模拟保存设置
|
||||
uni.showToast({
|
||||
title: '设置已保存',
|
||||
icon: 'success'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header">
|
||||
<text class="title">系统设置</text>
|
||||
</view>
|
||||
|
||||
<view class="settings-list">
|
||||
<view class="setting-item">
|
||||
<text class="setting-label">消息通知</text>
|
||||
<switch :checked="settings.notifications" @change="settings.notifications = $event.detail.value" />
|
||||
</view>
|
||||
|
||||
<view class="setting-item">
|
||||
<text class="setting-label">自动刷新</text>
|
||||
<switch :checked="settings.autoRefresh" @change="settings.autoRefresh = $event.detail.value" />
|
||||
</view>
|
||||
|
||||
<view class="setting-item">
|
||||
<text class="setting-label">刷新间隔(秒)</text>
|
||||
<slider :value="settings.refreshInterval" min="10" max="60" @change="settings.refreshInterval = $event.detail.value" />
|
||||
<text class="slider-value">{{ settings.refreshInterval }}秒</text>
|
||||
</view>
|
||||
|
||||
<view class="setting-item">
|
||||
<text class="setting-label">主题模式</text>
|
||||
<picker :value="settings.theme" :range="['light', 'dark']" @change="settings.theme = $event.detail.value[0]">
|
||||
<view class="picker-value">{{ settings.theme === 'light' ? '浅色' : '深色' }}</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="action-buttons">
|
||||
<button type="primary" @click="saveSettings">保存设置</button>
|
||||
<button @click="uni.navigateBack()">取消</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 20rpx 0;
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.settings-list {
|
||||
background: #fff;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 30rpx;
|
||||
|
||||
.setting-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.setting-label {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.slider-value {
|
||||
color: #666;
|
||||
font-size: 24rpx;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.picker-value {
|
||||
color: #1989fa;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
button {
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
135
mini_program/staff-mp/src/pages/transport/transport-monitor.vue
Normal file
135
mini_program/staff-mp/src/pages/transport/transport-monitor.vue
Normal file
@@ -0,0 +1,135 @@
|
||||
<script setup lang="ts">
|
||||
// 运输监控页面
|
||||
import { ref } from 'vue';
|
||||
|
||||
const transports = ref([]);
|
||||
const mapReady = ref(false);
|
||||
|
||||
// 模拟运输数据
|
||||
const mockTransports = [
|
||||
{ id: '1', orderNo: 'ORDER2025001', driver: '张师傅', phone: '13800138000', currentLocation: '北京市朝阳区', status: 'transporting' },
|
||||
{ id: '2', orderNo: 'ORDER2025002', driver: '李师傅', phone: '13900139000', currentLocation: '天津市南开区', status: 'transporting' },
|
||||
{ id: '3', orderNo: 'ORDER2025003', driver: '王师傅', phone: '13700137000', currentLocation: '河北省石家庄市', status: 'arrived' }
|
||||
];
|
||||
|
||||
const loadTransports = async () => {
|
||||
// 模拟API调用
|
||||
setTimeout(() => {
|
||||
transports.value = mockTransports;
|
||||
}, 500);
|
||||
};
|
||||
|
||||
loadTransports();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<view class="header">
|
||||
<text class="title">运输监控</text>
|
||||
</view>
|
||||
|
||||
<view class="map-container">
|
||||
<text class="map-placeholder">地图组件加载中...</text>
|
||||
</view>
|
||||
|
||||
<scroll-view scroll-y class="transport-list">
|
||||
<view v-for="transport in transports" :key="transport.id" class="transport-item">
|
||||
<view class="transport-header">
|
||||
<text class="order-no">{{ transport.orderNo }}</text>
|
||||
<text :class="`status-${transport.status}`">
|
||||
{{ transport.status === 'transporting' ? '运输中' : '已到达' }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="driver-info">
|
||||
<text>司机: {{ transport.driver }}</text>
|
||||
<text>电话: {{ transport.phone }}</text>
|
||||
</view>
|
||||
|
||||
<view class="location-info">
|
||||
<text>当前位置: {{ transport.currentLocation }}</text>
|
||||
</view>
|
||||
|
||||
<view class="transport-actions">
|
||||
<button size="mini" @click="handleCallDriver(transport.phone)">联系司机</button>
|
||||
<button size="mini" type="primary" @click="handleViewTrack(transport.id)">查看轨迹</button>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 20rpx 0;
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.map-container {
|
||||
height: 300rpx;
|
||||
background: #f5f5f5;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.map-placeholder {
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.transport-list {
|
||||
height: calc(100vh - 400rpx);
|
||||
}
|
||||
|
||||
.transport-item {
|
||||
background: #fff;
|
||||
padding: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
border-radius: 8rpx;
|
||||
|
||||
.transport-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15rpx;
|
||||
|
||||
.order-no {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-transporting {
|
||||
color: #1989fa;
|
||||
}
|
||||
.status-arrived {
|
||||
color: #3cc51f;
|
||||
}
|
||||
}
|
||||
|
||||
.driver-info, .location-info {
|
||||
margin-bottom: 10rpx;
|
||||
|
||||
text {
|
||||
display: block;
|
||||
margin-bottom: 5rpx;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.transport-actions {
|
||||
display: flex;
|
||||
gap: 10rpx;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
15
mini_program/staff-mp/src/static/tabbar/README.md
Normal file
15
mini_program/staff-mp/src/static/tabbar/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# 标签栏图标
|
||||
|
||||
请在此目录放置标签栏图标文件:
|
||||
|
||||
- home.png / home-active.png - 首页图标
|
||||
- order.png / order-active.png - 订单图标
|
||||
- transport.png / transport-active.png - 运输图标
|
||||
- statistics.png / statistics-active.png - 统计图标
|
||||
|
||||
图标要求:
|
||||
- 尺寸:50x50 像素
|
||||
- 格式:PNG 透明背景
|
||||
- 颜色:默认灰色,激活状态主题色
|
||||
|
||||
如果没有图标文件,系统会使用文本标签代替。
|
||||
98
mini_program/staff-mp/src/stores/orderStore.ts
Normal file
98
mini_program/staff-mp/src/stores/orderStore.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref, computed } from 'vue';
|
||||
import { getOrderList, getTransportData } from '@/utils/api';
|
||||
|
||||
export interface Order {
|
||||
id: string;
|
||||
orderNumber: string;
|
||||
customerName: string;
|
||||
status: 'pending' | 'processing' | 'shipped' | 'delivered' | 'cancelled';
|
||||
totalAmount: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface TransportData {
|
||||
orderId: string;
|
||||
currentLocation: string;
|
||||
estimatedArrival: string;
|
||||
driverName: string;
|
||||
driverPhone: string;
|
||||
vehicleNumber: string;
|
||||
temperature: number;
|
||||
humidity: number;
|
||||
}
|
||||
|
||||
export const useOrderStore = defineStore('order', () => {
|
||||
const orders = ref<Order[]>([]);
|
||||
const currentOrder = ref<Order | null>(null);
|
||||
const transportData = ref<TransportData | null>(null);
|
||||
const loading = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
|
||||
// 计算属性
|
||||
const pendingOrders = computed(() =>
|
||||
orders.value.filter(order => order.status === 'pending')
|
||||
);
|
||||
|
||||
const processingOrders = computed(() =>
|
||||
orders.value.filter(order => order.status === 'processing')
|
||||
);
|
||||
|
||||
const shippedOrders = computed(() =>
|
||||
orders.value.filter(order => order.status === 'shipped')
|
||||
);
|
||||
|
||||
// 动作
|
||||
const fetchOrders = async () => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
const response = await getOrderList({ page: 1, pageSize: 50 });
|
||||
orders.value = response.data.list;
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : '获取订单列表失败';
|
||||
// console.error('Failed to fetch orders:', err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const fetchTransportData = async (orderId: string) => {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
try {
|
||||
const response = await getTransportData(orderId);
|
||||
transportData.value = response.data;
|
||||
} catch (err) {
|
||||
error.value = err instanceof Error ? err.message : '获取运输数据失败';
|
||||
// console.error('Failed to fetch transport data:', err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const updateOrderStatus = (orderId: string, status: Order['status']) => {
|
||||
const order = orders.value.find(o => o.id === orderId);
|
||||
if (order) {
|
||||
order.status = status;
|
||||
order.updatedAt = new Date().toISOString();
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
orders,
|
||||
currentOrder,
|
||||
transportData,
|
||||
loading,
|
||||
error,
|
||||
pendingOrders,
|
||||
processingOrders,
|
||||
shippedOrders,
|
||||
fetchOrders,
|
||||
fetchTransportData,
|
||||
updateOrderStatus,
|
||||
};
|
||||
});
|
||||
87
mini_program/staff-mp/src/utils/api.ts
Normal file
87
mini_program/staff-mp/src/utils/api.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
// API 工具函数
|
||||
export interface ApiResponse<T = unknown> {
|
||||
code: number;
|
||||
data: T;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface PaginationParams {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
export interface PaginationResult<T> {
|
||||
list: T[];
|
||||
total: number;
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一的 API 请求函数
|
||||
*/
|
||||
export async function request<T>(
|
||||
url: string,
|
||||
options?: { method?: string; headers?: Record<string, string>; body?: unknown }
|
||||
): Promise<ApiResponse<T>> {
|
||||
declare const uni: unknown;
|
||||
|
||||
const response = await uni.request({
|
||||
url,
|
||||
method: options?.method || 'GET',
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
...options?.headers,
|
||||
},
|
||||
data: options?.body,
|
||||
});
|
||||
|
||||
if (response.statusCode !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response.statusCode}`);
|
||||
}
|
||||
|
||||
const data = response.data as ApiResponse<T>;
|
||||
|
||||
if (data.code !== 200) {
|
||||
throw new Error(data.message || 'API request failed');
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取订单列表
|
||||
*/
|
||||
export async function getOrderList() {
|
||||
return request<PaginationResult<Order>>('/api/orders', {
|
||||
method: 'GET',
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取运输监控数据
|
||||
*/
|
||||
export async function getTransportData(orderId: string) {
|
||||
return request<TransportData>(`/api/transport/${orderId}`);
|
||||
}
|
||||
|
||||
interface Order {
|
||||
id: string;
|
||||
orderNumber: string;
|
||||
customerName: string;
|
||||
status: string;
|
||||
totalAmount: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
interface TransportData {
|
||||
orderId: string;
|
||||
currentLocation: string;
|
||||
estimatedArrival: string;
|
||||
driverName: string;
|
||||
driverPhone: string;
|
||||
vehicleNumber: string;
|
||||
temperature: number;
|
||||
humidity: number;
|
||||
}
|
||||
23
mini_program/staff-mp/tsconfig.json
Normal file
23
mini_program/staff-mp/tsconfig.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"moduleResolution": "node",
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"skipLibCheck": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
},
|
||||
"types": [
|
||||
"@dcloudio/types",
|
||||
"miniprogram-api-typings",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
17
mini_program/staff-mp/vue.config.js
Normal file
17
mini_program/staff-mp/vue.config.js
Normal file
@@ -0,0 +1,17 @@
|
||||
const { defineConfig } = require('@vue/cli-service')
|
||||
|
||||
module.exports = defineConfig({
|
||||
transpileDependencies: true,
|
||||
configureWebpack: {
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': require('path').resolve(__dirname, 'src')
|
||||
}
|
||||
}
|
||||
},
|
||||
pluginOptions: {
|
||||
'uni-app': {
|
||||
platform: 'mp-weixin'
|
||||
}
|
||||
}
|
||||
})
|
||||
0
mini_program/staff极速快3-mp/package.json
Normal file
0
mini_program/staff极速快3-mp/package.json
Normal file
13
mini_program/supplier-mp/package.json
Normal file
13
mini_program/supplier-mp/package.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "supplier-mp",
|
||||
"version": "1.0.0",
|
||||
"description": "活牛供应商小程序",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "uni -p mp-weixin"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dcloudio/uni-app": "^3.0.0",
|
||||
"pinia": "^2.0.0"
|
||||
}
|
||||
}
|
||||
15
mini_program/supplier-mp/src/pages/index/index.vue
Normal file
15
mini_program/supplier-mp/src/pages/index/index.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<script setup lang="ts">
|
||||
// 供应商小程序首页
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="container">
|
||||
<text>供应商小程序首页</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.container {
|
||||
padding: 20rpx;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user