@ -0,0 +1,23 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
dist/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
*.log
|
||||
|
||||
tests/**/coverage/
|
||||
tests/e2e/reports
|
||||
selenium-debug.log
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.local
|
||||
|
||||
package-lock.json
|
||||
yarn.lock
|
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/png" href="/hear.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>快递系统</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "practical_project",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.7",
|
||||
"element-china-area-data": "^6.1.0",
|
||||
"element-plus": "^2.8.7",
|
||||
"mitt": "^3.0.1",
|
||||
"pinia": "^2.2.5",
|
||||
"vue": "^3.5.10",
|
||||
"vue-router": "4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"vite": "^5.4.8"
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<router-view />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@import url("./assets/css/base.css");
|
||||
</style>
|
@ -0,0 +1,103 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 运单查询相关接口
|
||||
export const trackingAPI = {
|
||||
// 查询运单信息
|
||||
getPackageInfo: (trackingNumber: string) =>
|
||||
request.get('/api/tracking/${trackingNumber}'),
|
||||
|
||||
// 获取已寄出的包裹列表
|
||||
getSentPackages: () =>
|
||||
request.get('/api/tracking/sent'),
|
||||
|
||||
// 获取已收到的包裹列表
|
||||
getReceivedPackages: () =>
|
||||
request.get('/api/tracking/received')
|
||||
}
|
||||
|
||||
// 投诉相关接口
|
||||
export const complaintAPI = {
|
||||
// 提交投诉
|
||||
submitComplaint: (data: {
|
||||
orderNumber: string,
|
||||
reason: string,
|
||||
description: string,
|
||||
contact: string
|
||||
}) => request.post('/api/complaints', data)
|
||||
}
|
||||
|
||||
// 寄件相关接口
|
||||
export const deliveryAPI = {
|
||||
// 提交寄件信息
|
||||
submitDelivery: (data: {
|
||||
sender: {
|
||||
name: string,
|
||||
phone: string,
|
||||
province: string[],
|
||||
address: string,
|
||||
company?: string
|
||||
},
|
||||
receiver: {
|
||||
name: string,
|
||||
phone: string,
|
||||
province: string[],
|
||||
address: string,
|
||||
company?: string
|
||||
},
|
||||
sendType: number
|
||||
}) => request.post('/api/delivery', data),
|
||||
|
||||
// 获取地址簿
|
||||
getAddressBook: () =>
|
||||
request.get('/api/address-book')
|
||||
}
|
||||
|
||||
// 反馈相关接口
|
||||
export const feedbackAPI = {
|
||||
// 提交反馈
|
||||
submitFeedback: (data: {
|
||||
title: string,
|
||||
content: string,
|
||||
contact?: string
|
||||
}) => request.post('/api/feedback', data)
|
||||
}
|
||||
|
||||
// 用户资料相关接口
|
||||
export const profileAPI = {
|
||||
// 获取用户信息
|
||||
getUserProfile: () =>
|
||||
request.get('/api/user/profile'),
|
||||
|
||||
// 更新用户信息
|
||||
updateProfile: (data: {
|
||||
name: string,
|
||||
email: string,
|
||||
phone: string,
|
||||
gender: string,
|
||||
birthday: string,
|
||||
address: string
|
||||
}) => request.put('/api/user/profile', data),
|
||||
|
||||
// 更新头像
|
||||
updateAvatar: (formData: FormData) =>
|
||||
request.post('/api/user/avatar', formData),
|
||||
|
||||
// 地址管理相关
|
||||
getAddresses: () =>
|
||||
request.get('/api/user/addresses'),
|
||||
|
||||
addAddress: (data: {
|
||||
name: string,
|
||||
address: string,
|
||||
phone: string
|
||||
}) => request.post('/api/user/addresses', data),
|
||||
|
||||
updateAddress: (id: number, data: {
|
||||
name: string,
|
||||
address: string,
|
||||
phone: string
|
||||
}) => request.put(`/api/user/addresses/${id}`, data),
|
||||
|
||||
deleteAddress: (id: number) =>
|
||||
request.delete(`/api/user/addresses/${id}`)
|
||||
}
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 419 B |
@ -0,0 +1,44 @@
|
||||
.content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
|
||||
}
|
||||
|
||||
/* 水平布局 居中*/
|
||||
.horizontalView {
|
||||
position: relative;
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 垂直布局居中 */
|
||||
.verticalView {
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 居中 */
|
||||
.center {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
font-size: 28px;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.w100 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.h100 {
|
||||
height: 100%;
|
||||
}
|
||||
.icon-svg {
|
||||
width: 1.4rem;
|
||||
height: 1.4rem;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
After Width: | Height: | Size: 295 KiB |
After Width: | Height: | Size: 6.1 KiB |
After Width: | Height: | Size: 6.2 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 490 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 184 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 2.8 KiB |
@ -0,0 +1,246 @@
|
||||
<template>
|
||||
<div class="layout-container">
|
||||
<!-- 左侧导航栏 -->
|
||||
<div class="sidebar">
|
||||
<div class="logo">
|
||||
<h2>快递系统</h2>
|
||||
</div>
|
||||
<el-menu
|
||||
default-active="/home"
|
||||
class="sidebar-menu"
|
||||
router
|
||||
background-color="#304156"
|
||||
text-color="#fff"
|
||||
>
|
||||
<el-menu-item index="/home">
|
||||
<el-icon><HomeFilled /></el-icon>
|
||||
<span>首页</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/delivery">
|
||||
<el-icon><Van /></el-icon>
|
||||
<span>寄件</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/check">
|
||||
<el-icon><Search /></el-icon>
|
||||
<span>查件</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="/service">
|
||||
<el-icon><Service /></el-icon>
|
||||
<span>服务查询</span>
|
||||
</el-menu-item>
|
||||
|
||||
<el-sub-menu index="/problem">
|
||||
<template #title>
|
||||
<el-icon><Warning /></el-icon>
|
||||
<span>问题反馈</span>
|
||||
</template>
|
||||
<el-menu-item index="/feedback">我有建议</el-menu-item>
|
||||
<el-menu-item index="/complaint">快递投诉</el-menu-item>
|
||||
</el-sub-menu>
|
||||
|
||||
<el-sub-menu index="/profile">
|
||||
<template #title>
|
||||
<el-icon><User /></el-icon>
|
||||
<span>个人中心</span>
|
||||
</template>
|
||||
<el-menu-item index="/profile">我的资料/地址簿</el-menu-item>
|
||||
</el-sub-menu>
|
||||
</el-menu>
|
||||
</div>
|
||||
|
||||
<!-- 顶部标题栏 -->
|
||||
<div class="header">
|
||||
<div class="header-left">
|
||||
<el-icon class="toggle-icon" @click="toggleSidebar">
|
||||
<Fold v-if="!isCollapse" />
|
||||
<Expand v-else />
|
||||
</el-icon>
|
||||
<span class="current-route">{{ currentRoute }}</span>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<el-dropdown>
|
||||
<span class="user-info">
|
||||
<el-avatar :size="30" :src="avatarUrl" />
|
||||
<span class="username">{{ username }}</span>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="goToProfile">个人中心</el-dropdown-item>
|
||||
<el-dropdown-item @click="logout">退出登录</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.layout-container {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 侧边栏样式 */
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 220px;
|
||||
background-color: #304156;
|
||||
transition: width 0.3s;
|
||||
z-index: 1000;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
/* 顶部标题栏样式 */
|
||||
.header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: calc(100% - 220px); /* 减去侧边栏宽度 */
|
||||
height: 60px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
z-index: 999;
|
||||
transition: width 0.3s;
|
||||
}
|
||||
|
||||
.sidebar.collapsed + .header {
|
||||
width: calc(100% - 64px); /* 侧边栏折叠时的宽度 */
|
||||
}
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.toggle-icon {
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
.current-route {
|
||||
font-size: 16px;
|
||||
color: #303133;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
}
|
||||
|
||||
/* Logo样式 */
|
||||
.logo {
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.logo h2 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 菜单样式 */
|
||||
.sidebar-menu {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
/* 响应式布局 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.sidebar {
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
.header {
|
||||
width: calc(100% - 64px);
|
||||
}
|
||||
|
||||
.username {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.current-route {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Element Plus 样式覆盖 */
|
||||
:deep(.el-menu-item.is-active) {
|
||||
background-color: #263445 !important;
|
||||
}
|
||||
|
||||
:deep(.el-menu-item:hover),
|
||||
:deep(.el-sub-menu__title:hover) {
|
||||
background-color: #263445 !important;
|
||||
}
|
||||
|
||||
:deep(.el-menu) {
|
||||
border-right: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { Fold, Expand } from '@element-plus/icons-vue';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const isCollapse = ref(false);
|
||||
const avatarUrl = ref('path/to/avatar.jpg');
|
||||
const username = ref('用户名');
|
||||
|
||||
// 计算当前路由名称
|
||||
const currentRoute = computed(() => {
|
||||
return route.meta.title || route.name || '首页';
|
||||
});
|
||||
|
||||
// 切换侧边栏
|
||||
const toggleSidebar = () => {
|
||||
isCollapse.value = !isCollapse.value;
|
||||
const sidebar = document.querySelector('.sidebar');
|
||||
if (sidebar) {
|
||||
sidebar.classList.toggle('collapsed');
|
||||
}
|
||||
};
|
||||
|
||||
// 跳转到个人中心
|
||||
const goToProfile = () => {
|
||||
router.push('/profile');
|
||||
};
|
||||
|
||||
// 退出登录
|
||||
const logout = () => {
|
||||
router.push({ name: 'login' });
|
||||
};
|
||||
</script>
|
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<div class="not-found">
|
||||
<h1>404 - 页面未找到</h1>
|
||||
<p>您访问的页面不存在。</p>
|
||||
<el-button @click="goBack">返回</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
const goBack = () => {
|
||||
router.go(-1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.not-found {
|
||||
text-align: center;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 18px;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,9 @@
|
||||
// src/hooks/useEmitter.js
|
||||
import { getCurrentInstance } from 'vue'
|
||||
|
||||
export default function useEmitter() {
|
||||
const internalInstance = getCurrentInstance()
|
||||
const emitter = internalInstance.appContext.config.globalProperties.emitter
|
||||
|
||||
return emitter
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
import { createApp } from 'vue'
|
||||
|
||||
import ElementPlus from 'element-plus'
|
||||
import 'element-plus/dist/index.css'
|
||||
import * as Icons from '@element-plus/icons-vue'
|
||||
import mitt from 'mitt';
|
||||
|
||||
import Header from './components/Header.vue';
|
||||
import backIndex from './components/backIndex.vue';
|
||||
|
||||
import router from './router'
|
||||
import App from './App.vue'
|
||||
|
||||
const app = createApp(App)
|
||||
const emitter = mitt()
|
||||
|
||||
Object.keys(Icons).forEach((key) => {
|
||||
app.component(key, Icons[key]);
|
||||
});
|
||||
|
||||
app.use(ElementPlus)
|
||||
app.use(router)
|
||||
app.config.globalProperties.emitter = emitter;
|
||||
|
||||
app.component('Header', Header);
|
||||
app.component('backIndex', backIndex);
|
||||
|
||||
app.mount('#app')
|
@ -0,0 +1,8 @@
|
||||
import axios from "axios";
|
||||
import { ElEmpty } from "element-plus";
|
||||
|
||||
const request = axios.create({
|
||||
baseURL: 'http://localhost:8081'
|
||||
})
|
||||
|
||||
export default request
|
@ -0,0 +1,114 @@
|
||||
import { createRouter, createWebHashHistory } from "vue-router"
|
||||
|
||||
const routes= [
|
||||
// 登录相关
|
||||
{
|
||||
path: "/",
|
||||
name: 'login',
|
||||
component: () => import("../components/Login.vue")
|
||||
},
|
||||
{
|
||||
path: "/backLogin",
|
||||
name: 'backLogin',
|
||||
component: () => import("../views/back/backLogin.vue")
|
||||
},
|
||||
{
|
||||
path: '/rescue',
|
||||
name: 'rescue',
|
||||
component: () => import("../components/Rescue.vue")
|
||||
},
|
||||
{
|
||||
path: '/backIndex',
|
||||
name: 'backIndex',
|
||||
component: () => import('../components/backIndex.vue')
|
||||
},
|
||||
|
||||
// 页面组件
|
||||
{
|
||||
path: "/header",
|
||||
name: 'header',
|
||||
component: () => import("../components/Header.vue")
|
||||
},
|
||||
// 前台用户相关页面
|
||||
{
|
||||
path: '/home',
|
||||
name: 'home',
|
||||
component: () => import("../views/Home.vue")
|
||||
},
|
||||
{
|
||||
path: '/delivery',
|
||||
name: 'delivery',
|
||||
component: () => import('../views/fore/delivery.vue')
|
||||
},
|
||||
{
|
||||
path: '/check',
|
||||
name: 'check',
|
||||
component: () => import('../views/fore/check.vue')
|
||||
},
|
||||
{
|
||||
path: '/service',
|
||||
name: 'service',
|
||||
component: () => import('../views/fore/service.vue')
|
||||
},
|
||||
{
|
||||
path: '/profile',
|
||||
name: 'profile',
|
||||
component: () => import('../views/fore/profile.vue')
|
||||
},
|
||||
{
|
||||
path: '/complaint',
|
||||
name: 'complaint',
|
||||
component: () => import('../views/fore/complaint.vue')
|
||||
},
|
||||
{
|
||||
path: '/feedback',
|
||||
name: 'feedback',
|
||||
component: () => import('../views/fore/feedback.vue')
|
||||
},
|
||||
|
||||
// 后台管理页面
|
||||
|
||||
{
|
||||
path: '/shopp',
|
||||
name: 'shopp',
|
||||
component: () => import('../views/back/shopp.vue')
|
||||
},
|
||||
{
|
||||
path: '/addkuaidi',
|
||||
name: 'addkuaidi',
|
||||
component: () => import('../views/back/addkuaidi.vue')
|
||||
},
|
||||
{
|
||||
path: '/personal',
|
||||
name: 'personal',
|
||||
component: () => import('../views/back/personal.vue')
|
||||
},
|
||||
{
|
||||
path: '/problem',
|
||||
name: 'problem',
|
||||
component: () => import('../views/back/problem.vue')
|
||||
},
|
||||
{
|
||||
path: '/notice',
|
||||
name: 'notice',
|
||||
component: () => import('../views/back/notice.vue')
|
||||
},
|
||||
|
||||
// 快递员页面
|
||||
{
|
||||
path: '/indexDeliveryman',
|
||||
name: 'indexDeliveryman',
|
||||
component: () => import('../views/courier/index.vue')
|
||||
},
|
||||
|
||||
// 404 页面
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
component: () => import('../components/NotFound.vue')
|
||||
}
|
||||
]
|
||||
const router = createRouter({
|
||||
history: createWebHashHistory(), routes
|
||||
})
|
||||
|
||||
export default router
|
@ -0,0 +1,18 @@
|
||||
import {
|
||||
defineStore
|
||||
}
|
||||
from "pinia";
|
||||
|
||||
export const userStore = defineStore('storeId', {
|
||||
state: () => {
|
||||
return {
|
||||
loginState: false // 登录状态, 已经登录true没有登录false
|
||||
}
|
||||
},
|
||||
getters: {},
|
||||
actions: {
|
||||
setLoginState(state) {
|
||||
this.loginState = state
|
||||
}
|
||||
}
|
||||
})
|
@ -0,0 +1,79 @@
|
||||
:root {
|
||||
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
// 包裹信息接口
|
||||
export interface Package {
|
||||
trackingNumber: string
|
||||
packageName: string
|
||||
sender: string
|
||||
senderaddress: string
|
||||
receiver: string
|
||||
receiveraddress: string
|
||||
status: string
|
||||
latestLocation: string
|
||||
}
|
||||
|
||||
// 投诉表单接口
|
||||
export interface ComplaintForm {
|
||||
orderNumber: string
|
||||
reason: string
|
||||
description: string
|
||||
contact: string
|
||||
}
|
||||
|
||||
// 寄件信息接口
|
||||
export interface DeliveryForm {
|
||||
sender: {
|
||||
name: string
|
||||
phone: string
|
||||
province: string[]
|
||||
address: string
|
||||
company?: string
|
||||
}
|
||||
receiver: {
|
||||
name: string
|
||||
phone: string
|
||||
province: string[]
|
||||
address: string
|
||||
company?: string
|
||||
}
|
||||
sendType: number
|
||||
}
|
||||
|
||||
// 反馈表单接口
|
||||
export interface FeedbackForm {
|
||||
title: string
|
||||
content: string
|
||||
contact?: string
|
||||
}
|
||||
|
||||
// 用户信息接口
|
||||
export interface UserProfile {
|
||||
name: string
|
||||
email: string
|
||||
phone: string
|
||||
gender: string
|
||||
birthday: string
|
||||
address: string
|
||||
}
|
||||
|
||||
// 地址信息接口
|
||||
export interface Address {
|
||||
id: number
|
||||
name: string
|
||||
address: string
|
||||
phone: string
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
import axios from 'axios'
|
||||
import { ElMessage } from 'element-plus'
|
||||
|
||||
// 创建axios实例
|
||||
const request = axios.create({
|
||||
baseURL: process.env.VUE_APP_BASE_API || '',
|
||||
timeout: 5000
|
||||
})
|
||||
|
||||
// 请求拦截器
|
||||
request.interceptors.request.use(
|
||||
config => {
|
||||
// 可以在这里添加token等认证信息
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
config.headers['Authorization'] = `Bearer ${token}`
|
||||
}
|
||||
return config
|
||||
},
|
||||
error => {
|
||||
console.log(error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
request.interceptors.response.use(
|
||||
response => {
|
||||
const res = response.data
|
||||
|
||||
// 这里可以根据后端的响应结构进行适当的处理
|
||||
if (res.code !== 200) {
|
||||
ElMessage({
|
||||
message: res.message || 'Error',
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(new Error(res.message || 'Error'))
|
||||
}
|
||||
return res
|
||||
},
|
||||
error => {
|
||||
console.log('err' + error)
|
||||
ElMessage({
|
||||
message: error.message,
|
||||
type: 'error',
|
||||
duration: 5 * 1000
|
||||
})
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
export default request
|
@ -0,0 +1,131 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
import { reactive, ref } from 'vue';
|
||||
|
||||
// 表单数据
|
||||
const form = reactive({
|
||||
trackingNumber: '',
|
||||
company: '',
|
||||
recipientName: '',
|
||||
phoneNumber: '',
|
||||
adminName: '',
|
||||
});
|
||||
|
||||
// 表单校验规则
|
||||
const rules = {
|
||||
trackingNumber: [{ required: true, message: '请输入快递单号', trigger: 'blur' }],
|
||||
company: [{ required: true, message: '请选择快递公司', trigger: 'change' }],
|
||||
recipientName: [{ required: true, message: '请输入收件人姓名', trigger: 'blur' }],
|
||||
phoneNumber: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
|
||||
adminName: [{ required: true, message: '请输入管理员姓名', trigger: 'blur' }],
|
||||
};
|
||||
|
||||
// 表单引用
|
||||
const formRef = ref(null);
|
||||
|
||||
// 提交表单函数
|
||||
const submitForm = () => {
|
||||
if (formRef) {
|
||||
console.log('表单提交成功', form);
|
||||
alert('快递信息提交成功!');
|
||||
} else {
|
||||
alert('请填写完整信息!');
|
||||
}
|
||||
// });
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<el-container>
|
||||
<!-- 顶部导航 -->
|
||||
<el-header>
|
||||
<backIndex />
|
||||
</el-header>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<el-container>
|
||||
<el-main>
|
||||
<div style="
|
||||
padding: 20px;
|
||||
max-width: 600px;
|
||||
margin: 30px auto;
|
||||
background: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
">
|
||||
<h2>录入快件</h2>
|
||||
<!-- 表单部分 -->
|
||||
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px">
|
||||
<el-form-item label="单号" prop="trackingNumber">
|
||||
<el-input v-model="form.trackingNumber" placeholder="请输入快递单号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="快递公司" prop="company">
|
||||
<el-select v-model="form.company" placeholder="请选择快递公司">
|
||||
<el-option label="顺丰速运" value="顺丰速运" />
|
||||
<el-option label="中通快递" value="中通快递" />
|
||||
<el-option label="圆通速递" value="圆通速递" />
|
||||
<el-option label="韵达快递" value="韵达快递" />
|
||||
<el-option label="京东物流" value="京东物流" />
|
||||
<el-option label="菜鸟裹裹" value="菜鸟裹裹" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="收件人姓名" prop="recipientName">
|
||||
<el-input v-model="form.recipientName" placeholder="请输入收件人姓名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="手机号" prop="phoneNumber">
|
||||
<el-input v-model="form.phoneNumber" placeholder="请输入手机号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="管理员姓名" prop="adminName">
|
||||
<el-input v-model="form.adminName" placeholder="请输入管理员姓名" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<!-- 提交按钮 -->
|
||||
<div style="text-align: center; margin-top: 20px;">
|
||||
<el-button type="primary" :disabled="!form.trackingNumber ||
|
||||
!form.company ||
|
||||
!form.recipientName ||
|
||||
!form.phoneNumber ||
|
||||
!form.adminName
|
||||
" @click="submitForm">
|
||||
立即提交
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
|
||||
|
||||
<style scoped>
|
||||
h2 {
|
||||
text-align: center;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 30px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
div[style*='max-width: 600px;'] {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
div[style*='max-width: 600px;'] {
|
||||
max-width: 90%;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,527 @@
|
||||
<template>
|
||||
<el-container>
|
||||
<el-header>
|
||||
<backIndex />
|
||||
</el-header>
|
||||
|
||||
<el-container>
|
||||
<el-main class="emain">
|
||||
<div class="management-container">
|
||||
<!-- 用户管理 -->
|
||||
<div class="section">
|
||||
<h3>用户管理</h3>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- 搜索框和添加用户按钮的容器 -->
|
||||
<div class="toolbar">
|
||||
<!-- 用户搜索框 -->
|
||||
<el-input v-model="userSearch" placeholder="输入员工id或用户id" class="user-search" prefix-icon="el-icon-search">
|
||||
</el-input>
|
||||
|
||||
<!-- 添加用户按钮 -->
|
||||
<el-button @click="handleAddUser" type="primary" class="add-user-button">
|
||||
添加用户
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 用户表格 -->
|
||||
<el-table :data="paginatedUsers" stripe style="width: 90%; margin: 20px auto;" border>
|
||||
<el-table-column prop="id" label="用户ID" align="center"></el-table-column>
|
||||
<el-table-column prop="email" label="邮箱" align="center"></el-table-column>
|
||||
<el-table-column prop="password" label="密码" align="center"></el-table-column>
|
||||
<el-table-column prop="phone" label="电话号" align="center"></el-table-column>
|
||||
<el-table-column prop="lastLogin" label="最后登录时间" align="center"></el-table-column>
|
||||
<el-table-column prop="registerTime" label="注册时间" align="center"></el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center">
|
||||
<template v-slot="scope">
|
||||
<div class="button-group">
|
||||
<el-button @click="handleEditUser(scope.row)" size="mini" type="primary" plain>编辑</el-button>
|
||||
<el-button @click="handleDeleteUser(scope.row)" size="mini" type="danger" plain>删除</el-button>
|
||||
<el-button @click="handleViewUser(scope.row)" size="mini" type="info" plain>查看详情</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页控件 -->
|
||||
<el-pagination :current-page="userCurrentPage" :page-size="userPageSize" :total="userData.length"
|
||||
@current-change="handleUserPageChange" layout="prev, pager, next, jumper" class="pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 快递员管理 -->
|
||||
<div class="section">
|
||||
<h3>快递员管理</h3>
|
||||
|
||||
<!-- 添加快递员按钮 -->
|
||||
<div class="action-buttons">
|
||||
<el-button @click="handleAddCourier" type="primary">添加快递员</el-button>
|
||||
</div>
|
||||
|
||||
<el-table :data="paginatedCouriers" stripe style="width: 90%; margin: 0 auto;" border>
|
||||
<el-table-column prop="id" label="员工号" align="center"></el-table-column>
|
||||
<el-table-column prop="name" label="姓名" align="center"></el-table-column>
|
||||
<el-table-column prop="status" label="在职状态" align="center"></el-table-column>
|
||||
<el-table-column prop="phone" label="电话" align="center"></el-table-column>
|
||||
<el-table-column prop="entryTime" label="入职时间" align="center"></el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center">
|
||||
<template v-slot="scope">
|
||||
<div class="button-group">
|
||||
<el-button @click="handleEditCourier(scope.row)" size="mini" type="primary" plain>编辑</el-button>
|
||||
<el-button @click="handleDeleteCourier(scope.row)" size="mini" type="danger" plain>删除</el-button>
|
||||
<el-button @click="handleViewCourier(scope.row)" size="mini" type="info" plain>查看详情</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页控件 -->
|
||||
<el-pagination :current-page="courierCurrentPage" :page-size="courierPageSize" :total="courierData.length"
|
||||
@current-change="handleCourierPageChange" layout="prev, pager, next, jumper" class="pagination" />
|
||||
</div>
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
<el-footer>
|
||||
<Footer />
|
||||
</el-footer>
|
||||
|
||||
<!-- 编辑用户对话框 -->
|
||||
<el-dialog title="编辑用户" v-model="editUserDialogVisible">
|
||||
<el-form :model="currentUser">
|
||||
<el-form-item label="用户ID">
|
||||
<el-input v-model="currentUser.id" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱">
|
||||
<el-input v-model="currentUser.email" />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码">
|
||||
<el-input v-model="currentUser.password" />
|
||||
</el-form-item>
|
||||
<el-form-item label="电话号">
|
||||
<el-input v-model="currentUser.phone" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="editUserDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSaveUserEdit">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 添加用户对话框 -->
|
||||
<el-dialog title="添加用户" v-model="addUserDialogVisible">
|
||||
<el-form :model="newUser" label-width="100px">
|
||||
<el-form-item label="用户ID">
|
||||
<el-input v-model="newUser.id" placeholder="请输入用户ID" />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱">
|
||||
<el-input v-model="newUser.email" placeholder="请输入邮箱" />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码">
|
||||
<el-input v-model="newUser.password" placeholder="请输入密码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="电话号">
|
||||
<el-input v-model="newUser.phone" placeholder="请输入电话号码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="注册时间">
|
||||
<el-date-picker v-model="newUser.registerTime" type="date" placeholder="选择注册时间" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="addUserDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSaveNewUser">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 编辑快递员对话框 -->
|
||||
<el-dialog title="编辑快递员" v-model="editCourierDialogVisible">
|
||||
<el-form :model="currentCourier">
|
||||
<el-form-item label="员工号">
|
||||
<el-input v-model="currentCourier.id" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="currentCourier.name" />
|
||||
</el-form-item>
|
||||
<el-form-item label="在职状态">
|
||||
<el-input v-model="currentCourier.status" />
|
||||
</el-form-item>
|
||||
<el-form-item label="电话">
|
||||
<el-input v-model="currentCourier.phone" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="editCourierDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSaveCourierEdit">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 添加快递员对话框 -->
|
||||
<el-dialog title="添加快递员" v-model="addCourierDialogVisible">
|
||||
<el-form :model="newCourier" label-width="100px">
|
||||
<el-form-item label="员工号">
|
||||
<el-input v-model="newCourier.id" placeholder="请输入员工号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="newCourier.name" placeholder="请输入姓名" />
|
||||
</el-form-item>
|
||||
<el-form-item label="在职状态">
|
||||
<el-input v-model="newCourier.status" placeholder="请输入在职状态(如:在职、离职)" />
|
||||
</el-form-item>
|
||||
<el-form-item label="电话">
|
||||
<el-input v-model="newCourier.phone" placeholder="请输入电话号码" />
|
||||
</el-form-item>
|
||||
<el-form-item label="入职时间">
|
||||
<el-date-picker v-model="newCourier.entryTime" type="date" placeholder="选择入职时间" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="addCourierDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleSaveNewCourier">保存</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
<!-- 查看快递员详情对话框 -->
|
||||
<el-dialog title="快递员详情" v-model="viewCourierDialogVisible">
|
||||
<el-form :model="currentCourier" label-width="100px">
|
||||
<el-form-item label="员工号">
|
||||
<el-input v-model="currentCourier.id" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="姓名">
|
||||
<el-input v-model="currentCourier.name" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="在职状态">
|
||||
<el-input v-model="currentCourier.status" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="电话">
|
||||
<el-input v-model="currentCourier.phone" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="入职时间">
|
||||
<el-input v-model="currentCourier.entryTime" readonly />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="viewCourierDialogVisible = false">关闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 查看详情对话框 -->
|
||||
<!-- 查看用户详情对话框 -->
|
||||
<el-dialog title="查看用户详情" v-model="viewUserDialogVisible">
|
||||
<el-form :model="currentUser" label-width="100px" readonly>
|
||||
<el-form-item label="用户ID">
|
||||
<el-input v-model="currentUser.id" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱">
|
||||
<el-input v-model="currentUser.email" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="密码">
|
||||
<el-input v-model="currentUser.password" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="电话号">
|
||||
<el-input v-model="currentUser.phone" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="最后登录时间">
|
||||
<el-input v-model="currentUser.lastLogin" readonly />
|
||||
</el-form-item>
|
||||
<el-form-item label="注册时间">
|
||||
<el-input v-model="currentUser.registerTime" readonly />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="viewUserDialogVisible = false">关闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||
// 查看用户详情
|
||||
const viewUserDialogVisible = ref(false)
|
||||
|
||||
|
||||
const handleViewUser = (user) => {
|
||||
currentUser.value = { ...user } // 将选中的用户数据赋值给当前用户对象
|
||||
viewUserDialogVisible.value = true // 显示查看详情对话框
|
||||
}
|
||||
// 查看快递员
|
||||
const viewCourierDialogVisible = ref(false) // 控制查看对话框的显示
|
||||
const handleViewCourier = (courier: any) => {
|
||||
currentCourier.value = { ...courier } // 将当前选择的快递员数据赋值
|
||||
viewCourierDialogVisible.value = true // 打开查看对话框
|
||||
}
|
||||
|
||||
// 添加用户
|
||||
const addUserDialogVisible = ref(false) // 控制添加用户对话框的显示
|
||||
const newUser = ref({
|
||||
id: '', // 用户ID
|
||||
email: '', // 用户邮箱
|
||||
password: '', // 用户密码
|
||||
phone: '', // 用户电话
|
||||
registerTime: '' // 注册时间
|
||||
})
|
||||
|
||||
const handleAddUser = () => {
|
||||
newUser.value = { id: '', email: '', password: '', phone: '', registerTime: '' } // 初始化表单
|
||||
addUserDialogVisible.value = true // 打开添加对话框
|
||||
}
|
||||
|
||||
const handleSaveNewUser = () => {
|
||||
if (!newUser.value.id || !newUser.value.email || !newUser.value.phone) {
|
||||
ElMessage.warning('请完整填写信息')
|
||||
return
|
||||
}
|
||||
// 添加到用户数据
|
||||
|
||||
ElMessage.success('用户添加成功')
|
||||
addUserDialogVisible.value = false // 关闭对话框
|
||||
}
|
||||
|
||||
// 用户和快递员数据
|
||||
const userData = ref([
|
||||
{ id: '001', email: 'user1@example.com', password: 'password123', phone: '13800000001', lastLogin: '2024-11-01 10:30:00', registerTime: '2023-01-15 14:20:00' },
|
||||
{ id: '002', email: 'user2@example.com', password: 'password123', phone: '13800000002', lastLogin: '2024-11-02 12:00:00', registerTime: '2023-02-10 09:15:00' },
|
||||
|
||||
|
||||
// ... 其他用户数据
|
||||
]);
|
||||
const courierData = ref([
|
||||
{ id: '001', name: '小刘', status: '在职', phone: '13800000001', entryTime: '2022-03-01' },
|
||||
{ id: '002', name: '小王', status: '离职', phone: '13800000002', entryTime: '2021-06-15' },
|
||||
// ... 其他快递员数据
|
||||
{ id: '001', name: '小刘', status: '在职', phone: '13800000001', entryTime: '2022-03-01' },
|
||||
{ id: '002', name: '小王', status: '离职', phone: '13800000002', entryTime: '2021-06-15' },
|
||||
{ id: '001', name: '小刘', status: '在职', phone: '13800000001', entryTime: '2022-03-01' },
|
||||
{ id: '002', name: '小王', status: '离职', phone: '13800000002', entryTime: '2021-06-15' },
|
||||
{ id: '001', name: '小刘', status: '在职', phone: '13800000001', entryTime: '2022-03-01' },
|
||||
{ id: '002', name: '小王', status: '离职', phone: '13800000002', entryTime: '2021-06-15' },
|
||||
{ id: '001', name: '小刘', status: '在职', phone: '13800000001', entryTime: '2022-03-01' },
|
||||
{ id: '002', name: '小王', status: '离职', phone: '13800000002', entryTime: '2021-06-15' },
|
||||
{ id: '001', name: '小刘', status: '在职', phone: '13800000001', entryTime: '2022-03-01' },
|
||||
|
||||
{ id: '002', name: '小王', status: '离职', phone: '13800000002', entryTime: '2021-06-15' },
|
||||
{ id: '001', name: '小刘', status: '在职', phone: '13800000001', entryTime: '2022-03-01' },
|
||||
{ id: '002', name: '小王', status: '离职', phone: '13800000002', entryTime: '2021-06-15' },
|
||||
{ id: '001', name: '小刘', status: '在职', phone: '13800000001', entryTime: '2022-03-01' },
|
||||
{ id: '002', name: '小王', status: '离职', phone: '13800000002', entryTime: '2021-06-15' },
|
||||
{ id: '001', name: '小刘', status: '在职', phone: '13800000001', entryTime: '2022-03-01' },
|
||||
{ id: '002', name: '小王', status: '离职', phone: '13800000002', entryTime: '2021-06-15' },
|
||||
{ id: '001', name: '小刘', status: '在职', phone: '13800000001', entryTime: '2022-03-01' },
|
||||
{ id: '002', name: '小王', status: '离职', phone: '13800000002', entryTime: '2021-06-15' },
|
||||
|
||||
]);
|
||||
|
||||
// 当前用户/快递员
|
||||
const currentUser = ref<any>({})
|
||||
const currentCourier = ref<any>({})
|
||||
|
||||
// 对话框可见性
|
||||
const editUserDialogVisible = ref(false)
|
||||
const editCourierDialogVisible = ref(false)
|
||||
|
||||
// 当前页和分页大小
|
||||
const userPageSize = 5
|
||||
const courierPageSize = 5
|
||||
const userCurrentPage = ref(1)
|
||||
const courierCurrentPage = ref(1)
|
||||
const userSearch = ref('')
|
||||
// 添加快递员
|
||||
const addCourierDialogVisible = ref(false) // 控制添加快递员对话框的显示
|
||||
const newCourier = ref({
|
||||
id: '', // 员工号
|
||||
name: '', // 姓名
|
||||
status: '', // 在职状态
|
||||
phone: '', // 电话
|
||||
entryTime: '' // 入职时间
|
||||
})
|
||||
|
||||
const handleAddCourier = () => {
|
||||
newCourier.value = { id: '', name: '', status: '', phone: '', entryTime: '' } // 初始化表单
|
||||
addCourierDialogVisible.value = true // 打开添加对话框
|
||||
}
|
||||
|
||||
const handleSaveNewCourier = () => {
|
||||
if (!newCourier.value.id || !newCourier.value.name || !newCourier.value.phone) {
|
||||
ElMessage.warning('请完整填写信息')
|
||||
return
|
||||
}
|
||||
// 添加到快递员数据
|
||||
courierData.value.push({ ...newCourier.value })
|
||||
ElMessage.success('快递员添加成功')
|
||||
addCourierDialogVisible.value = false // 关闭对话框
|
||||
}
|
||||
|
||||
// 分页后的用户和快递员数据
|
||||
const paginatedUsers = computed(() => {
|
||||
const start = (userCurrentPage.value - 1) * userPageSize
|
||||
return userData.value.slice(start, start + userPageSize)
|
||||
})
|
||||
const paginatedCouriers = computed(() => {
|
||||
const start = (courierCurrentPage.value - 1) * courierPageSize
|
||||
return courierData.value.slice(start, start + courierPageSize)
|
||||
})
|
||||
|
||||
// 编辑用户
|
||||
const handleEditUser = (user: any) => {
|
||||
currentUser.value = { ...user }
|
||||
editUserDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 编辑快递员
|
||||
const handleEditCourier = (courier: any) => {
|
||||
currentCourier.value = { ...courier }
|
||||
editCourierDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 删除用户
|
||||
const handleDeleteUser = (user: any) => {
|
||||
ElMessageBox.confirm(
|
||||
'确定删除该用户吗?',
|
||||
'删除确认',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
// 删除操作
|
||||
const index = userData.value.findIndex(u => u.id === user.id)
|
||||
if (index !== -1) userData.value.splice(index, 1)
|
||||
ElMessage.success('删除成功')
|
||||
}).catch(() => {
|
||||
ElMessage.info('删除已取消')
|
||||
})
|
||||
}
|
||||
|
||||
// 删除快递员
|
||||
const handleDeleteCourier = (courier: any) => {
|
||||
ElMessageBox.confirm(
|
||||
'确定删除该快递员吗?',
|
||||
'删除确认',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}
|
||||
).then(() => {
|
||||
// 删除操作
|
||||
const index = courierData.value.findIndex(c => c.id === courier.id)
|
||||
if (index !== -1) courierData.value.splice(index, 1)
|
||||
ElMessage.success('删除成功')
|
||||
}).catch(() => {
|
||||
ElMessage.info('删除已取消')
|
||||
})
|
||||
}
|
||||
|
||||
// 保存用户编辑
|
||||
const handleSaveUserEdit = () => {
|
||||
const index = userData.value.findIndex(u => u.id === currentUser.value.id)
|
||||
if (index !== -1) {
|
||||
userData.value[index] = { ...currentUser.value }
|
||||
ElMessage.success('用户信息已更新')
|
||||
}
|
||||
editUserDialogVisible.value = false
|
||||
}
|
||||
|
||||
// 保存快递员编辑
|
||||
const handleSaveCourierEdit = () => {
|
||||
const index = courierData.value.findIndex(c => c.id === currentCourier.value.id)
|
||||
if (index !== -1) {
|
||||
courierData.value[index] = { ...currentCourier.value }
|
||||
ElMessage.success('快递员信息已更新')
|
||||
}
|
||||
editCourierDialogVisible.value = false
|
||||
}
|
||||
|
||||
// 分页变化
|
||||
const handleUserPageChange = (page: number) => userCurrentPage.value = page
|
||||
const handleCourierPageChange = (page: number) => courierCurrentPage.value = page
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.toolbar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
/* 将内容对齐到右边 */
|
||||
align-items: center;
|
||||
width: 90%;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.user-search {
|
||||
flex: 0 0 200px;
|
||||
/* 搜索框的固定宽度 */
|
||||
margin-right: 10px;
|
||||
/* 可以根据需要调整这个值 */
|
||||
}
|
||||
|
||||
/* 添加用户按钮 */
|
||||
.add-user-button {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.emain {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.management-container {
|
||||
padding: 20px;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.management-container h2 {
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.section h3 {
|
||||
font-size: 20px;
|
||||
color: #666;
|
||||
margin-bottom: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
min-width: 60px;
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.el-table-column {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-table__header-wrapper th {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.action-buttons {
|
||||
text-align: right;
|
||||
margin-top: 20px;
|
||||
margin-right: 100px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,268 @@
|
||||
<template>
|
||||
<el-container>
|
||||
<el-header>
|
||||
<backIndex />
|
||||
</el-header>
|
||||
<el-container>
|
||||
<el-main class="emain">
|
||||
<div class="problem-container">
|
||||
|
||||
<!-- 用户问题表格 -->
|
||||
<div class="section">
|
||||
<h3>用户问题</h3>
|
||||
<el-table :data="paginatedUserProblems" stripe style="width: 90%; margin: 0 auto;" border>
|
||||
<el-table-column prop="id" label="ID" align="center"></el-table-column>
|
||||
<el-table-column prop="username" label="用户名" align="center"></el-table-column>
|
||||
<el-table-column prop="title" label="问题标题" align="center" header-align="center"></el-table-column>
|
||||
|
||||
<el-table-column prop="status" label="问题状态" align="center">
|
||||
<template v-slot="scope">
|
||||
<el-tag :type="scope.row.status === '已解决' ? 'success' : 'warning'" disable-transitions>
|
||||
{{ scope.row.status }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="merchantStatus" label="商家回复" width="120" align="center">
|
||||
<template v-slot="scope">
|
||||
<el-tag :type="scope.row.merchantStatus === '已回复' ? 'success' : 'danger'" disable-transitions>
|
||||
{{ scope.row.merchantStatus }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center">
|
||||
<template v-slot="scope">
|
||||
<div class="button-group">
|
||||
<el-button @click="handleResolve(scope.row)" size="mini" type="success" plain>解决</el-button>
|
||||
<el-button @click="handleDelete(scope.row)" size="mini" type="danger" plain>删除</el-button>
|
||||
<el-button @click="handleContact(scope.row)" size="mini" type="primary" plain>联系客户</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页控件 -->
|
||||
<el-pagination :current-page="userCurrentPage" :page-size="userPageSize" :total="userProblemData.length"
|
||||
@current-change="handleUserPageChange" layout="prev, pager, next, jumper" class="pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 快递员问题表格 -->
|
||||
<div class="section">
|
||||
<h3>快递员问题</h3>
|
||||
<el-table :data="paginatedCourierProblems" stripe style="width: 90%; margin: 0 auto;" border>
|
||||
<el-table-column prop="id" label="ID" align="center"></el-table-column>
|
||||
<el-table-column prop="courierName" label="快递员姓名" align="center"></el-table-column>
|
||||
<el-table-column prop="title" label="问题标题" align="center" header-align="center"></el-table-column>
|
||||
|
||||
<el-table-column prop="status" label="问题状态" align="center">
|
||||
<template v-slot="scope">
|
||||
<el-tag :type="scope.row.status === '已解决' ? 'success' : 'warning'" disable-transitions>
|
||||
{{ scope.row.status }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="companyReply" label="公司回复" width="120" align="center">
|
||||
<template v-slot="scope">
|
||||
<el-tag :type="scope.row.companyReply === '已回复' ? 'success' : 'danger'" disable-transitions>
|
||||
{{ scope.row.companyReply }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="220" align="center">
|
||||
<template v-slot="scope">
|
||||
<div class="button-group">
|
||||
<el-button @click="handleResolve(scope.row)" size="mini" type="success" plain>解决</el-button>
|
||||
<el-button @click="handleDelete(scope.row)" size="mini" type="danger" plain>删除</el-button>
|
||||
<el-button @click="handleContactCourier(scope.row)" size="mini" type="primary"
|
||||
plain>联系快递员</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页控件 -->
|
||||
<el-pagination :current-page="courierCurrentPage" :page-size="courierPageSize"
|
||||
:total="courierProblemData.length" @current-change="handleCourierPageChange"
|
||||
layout="prev, pager, next, jumper" class="pagination" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
const userProblemData = ref([
|
||||
{ id: 1, username: '张三', title: '快递丢失', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 2, username: '李四', title: '配送延迟', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 3, username: '王五', title: '包裹损坏', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 4, username: '赵六', title: '地址错误', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 5, username: '孙七', title: '包装破损', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 6, username: '周八', title: '收件人地址错误', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 7, username: '吴九', title: '物品破损', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 8, username: '郑十', title: '配送信息不符', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 9, username: '钱十一', title: '签收问题', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 10, username: '孙十二', title: '快递丢失', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 11, username: '李十三', title: '包裹迟迟未到', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 12, username: '王十四', title: '派送时效不符合', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 13, username: '赵十五', title: '包装破损', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 14, username: '孙十六', title: '快递迟到', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 15, username: '周十七', title: '配送路线问题', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 16, username: '吴十八', title: '物品丢失', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 17, username: '郑十九', title: '快递员态度差', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 18, username: '钱二十', title: '快递员迟到', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 19, username: '孙二十一', title: '商品损坏', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 20, username: '李二十二', title: '配送不及时', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 21, username: '王二十三', title: '包裹未送达', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 22, username: '赵二十四', title: '地址不清晰', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 23, username: '孙二十五', title: '收件地址错误', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 24, username: '周二十六', title: '派送延误', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 25, username: '吴二十七', title: '包裹破损', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 26, username: '郑二十八', title: '配送信息错误', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 27, username: '钱二十九', title: '包裹无法签收', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 28, username: '孙三十', title: '派送时效问题', status: '已解决', merchantStatus: '已回复' },
|
||||
{ id: 29, username: '李三十一', title: '快递包裹丢失', status: '未解决', merchantStatus: '未回复' },
|
||||
{ id: 30, username: '王三十二', title: '物流追踪问题', status: '已解决', merchantStatus: '已回复' }
|
||||
])
|
||||
|
||||
const courierProblemData = ref([
|
||||
{ id: 1, courierName: '小刘', title: '车辆故障', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 2, courierName: '小王', title: '路线不清', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 3, courierName: '小李', title: '客户未取件', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 4, courierName: '小张', title: '包裹丢失', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 5, courierName: '小赵', title: '快递迟到', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 3, courierName: '小李', title: '客户未取件', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 4, courierName: '小张', title: '包裹丢失', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 5, courierName: '小赵', title: '快递迟到', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 6, courierName: '小陈', title: '包裹损坏', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 7, courierName: '小黄', title: '快递错发', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 8, courierName: '小李', title: '包裹丢失', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 9, courierName: '小刘', title: '客户未取件', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 10, courierName: '小王', title: '快递迟到', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 11, courierName: '小张', title: '车辆故障', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 12, courierName: '小赵', title: '路线不清', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 13, courierName: '小陈', title: '包裹丢失', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 14, courierName: '小黄', title: '客户未取件', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 15, courierName: '小李', title: '快递错发', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 16, courierName: '小刘', title: '车辆故障', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 17, courierName: '小王', title: '快递迟到', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 18, courierName: '小张', title: '客户未取件', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 19, courierName: '小赵', title: '包裹丢失', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 20, courierName: '小陈', title: '快递错发', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 21, courierName: '小黄', title: '包裹损坏', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 22, courierName: '小李', title: '路线不清', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 23, courierName: '小刘', title: '快递迟到', status: '已解决', companyReply: '已回复' },
|
||||
{ id: 24, courierName: '小王', title: '车辆故障', status: '未解决', companyReply: '未回复' },
|
||||
{ id: 25, courierName: '小张', title: '快递错发', status: '已解决', companyReply: '已回复' },
|
||||
// 可以继续增加数据
|
||||
])
|
||||
|
||||
const userPageSize = 10 // 每页显示的数量
|
||||
const courierPageSize = 10 // 每页显示的数量
|
||||
|
||||
const userCurrentPage = ref(1) // 当前页数
|
||||
const courierCurrentPage = ref(1) // 当前页数
|
||||
|
||||
// 分页后的用户问题数据
|
||||
const paginatedUserProblems = computed(() => {
|
||||
const start = (userCurrentPage.value - 1) * userPageSize
|
||||
return userProblemData.value.slice(start, start + userPageSize)
|
||||
})
|
||||
|
||||
// 分页后的快递员问题数据
|
||||
const paginatedCourierProblems = computed(() => {
|
||||
const start = (courierCurrentPage.value - 1) * courierPageSize
|
||||
return courierProblemData.value.slice(start, start + courierPageSize)
|
||||
})
|
||||
|
||||
// 用户问题页数变化时
|
||||
const handleUserPageChange = (page: number) => {
|
||||
userCurrentPage.value = page
|
||||
}
|
||||
|
||||
// 快递员问题页数变化时
|
||||
const handleCourierPageChange = (page: number) => {
|
||||
courierCurrentPage.value = page
|
||||
}
|
||||
|
||||
const handleResolve = (row: any) => {
|
||||
console.log('解决问题', row)
|
||||
row.status = '已解决'
|
||||
}
|
||||
|
||||
const handleDelete = (row: any) => {
|
||||
console.log('删除问题', row)
|
||||
}
|
||||
|
||||
const handleContact = (row: any) => {
|
||||
console.log('联系客户', row)
|
||||
}
|
||||
|
||||
const handleContactCourier = (row: any) => {
|
||||
console.log('联系快递员', row)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.emain {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.problem-container {
|
||||
padding: 20px;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.problem-container h2 {
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.section h3 {
|
||||
font-size: 20px;
|
||||
color: #666;
|
||||
margin-bottom: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.button-group {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
|
||||
}
|
||||
|
||||
.el-button {
|
||||
min-width: 60px;
|
||||
font-size: 12px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
/* 居中分页 */
|
||||
}
|
||||
|
||||
.el-table-column {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-table__header-wrapper th {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,226 @@
|
||||
<template>
|
||||
<el-container style="height: 100vh;">
|
||||
<!-- 顶部标题 -->
|
||||
<el-header style="background-color: #A8B9C9; color: #F2F8FE; text-align: center; font-size: 24px; padding: 20px;">
|
||||
快递员中心
|
||||
</el-header>
|
||||
|
||||
<el-container>
|
||||
<!-- 左侧菜单栏 -->
|
||||
<el-aside width="250px" style="background-color: #f4f6f9;">
|
||||
<el-menu :default-active="currentTab" class="el-menu-vertical-demo" @select="handleTabChange">
|
||||
<el-menu-item index="toDeliver">待配送订单</el-menu-item>
|
||||
<el-menu-item index="history">历史订单</el-menu-item>
|
||||
</el-menu>
|
||||
</el-aside>
|
||||
|
||||
<!-- 主内容区域 -->
|
||||
<el-main style="padding: 20px;">
|
||||
<!-- 待配送订单 -->
|
||||
<el-row v-if="currentTab === 'toDeliver'" class="order-card">
|
||||
<h3>待配送订单</h3>
|
||||
<div class="button-container">
|
||||
<el-button type="primary" @click="openAddOrderDialog" class="btn">新增订单</el-button>
|
||||
</div>
|
||||
<el-table :data="toDeliverOrders" border stripe>
|
||||
<el-table-column prop="id" label="订单编号" width="180" />
|
||||
<el-table-column prop="receiver" label="收件人" width="180" />
|
||||
<el-table-column prop="address" label="地址" />
|
||||
<el-table-column prop="status" label="状态" width="120" />
|
||||
<el-table-column label="操作" width="180">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.status === '待取件'" type="primary" size="small"
|
||||
@click="updateStatus(row, '配送中')">开始配送</el-button>
|
||||
<el-button v-if="row.status === '配送中'" type="success" size="small"
|
||||
@click="updateStatus(row, '已完成')">完成配送</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-row>
|
||||
|
||||
<!-- 历史订单 -->
|
||||
<el-row v-if="currentTab === 'history'" class="order-card">
|
||||
<h3>历史订单</h3>
|
||||
<el-table :data="historyOrders" border stripe>
|
||||
<el-table-column prop="id" label="订单编号" width="180" />
|
||||
<el-table-column prop="receiver" label="收件人" width="180" />
|
||||
<el-table-column prop="address" label="地址" />
|
||||
<el-table-column prop="status" label="状态" width="120" />
|
||||
<el-table-column prop="deliveryTime" label="配送时间" width="180" />
|
||||
<el-table-column label="操作" width="180">
|
||||
<template #default="{ row }">
|
||||
<el-button type="danger" size="small" @click="deleteHistoryOrder(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-row>
|
||||
|
||||
</el-main>
|
||||
|
||||
<!-- 新增订单对话框 -->
|
||||
<el-dialog title="新增订单" v-model="addOrderDialogVisible" width="400px" align-center>
|
||||
<el-form :model="newOrder" ref="newOrderForm" label-width="100px">
|
||||
<el-form-item label="订单编号">
|
||||
<el-input v-model="newOrder.id" placeholder="请输入订单编号" />
|
||||
</el-form-item>
|
||||
<el-form-item label="收件人">
|
||||
<el-input v-model="newOrder.receiver" placeholder="请输入收件人" />
|
||||
</el-form-item>
|
||||
<el-form-item label="地址">
|
||||
<el-input v-model="newOrder.address" placeholder="请输入地址" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="newOrder.status" placeholder="请选择状态">
|
||||
<el-option label="待取件" value="待取件" />
|
||||
<el-option label="配送中" value="配送中" />
|
||||
<el-option label="已完成" value="已完成" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-row slot="footer" class="dialog-footer">
|
||||
<el-button @click="addOrderDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="addOrder">确定</el-button>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</el-container>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref
|
||||
} from 'vue';
|
||||
|
||||
// State
|
||||
const currentTab = ref('toDeliver');
|
||||
const addOrderDialogVisible = ref(false); // 控制新增订单对话框的显示
|
||||
const newOrder = ref({
|
||||
id: '',
|
||||
receiver: '',
|
||||
address: '',
|
||||
status: '待取件'
|
||||
});
|
||||
|
||||
const toDeliverOrders = ref([{
|
||||
id: '001',
|
||||
receiver: '李四',
|
||||
address: '北京市朝阳区',
|
||||
status: '待取件'
|
||||
},
|
||||
{
|
||||
id: '002',
|
||||
receiver: '王五',
|
||||
address: '北京市海淀区',
|
||||
status: '待取件'
|
||||
},
|
||||
{
|
||||
id: '003',
|
||||
receiver: '赵六',
|
||||
address: '北京市昌平区',
|
||||
status: '配送中'
|
||||
}
|
||||
]);
|
||||
|
||||
const historyOrders = ref([{
|
||||
id: '004',
|
||||
receiver: '孙七',
|
||||
address: '北京市东城区',
|
||||
status: '已完成',
|
||||
deliveryTime: '2024-10-10 14:00'
|
||||
},
|
||||
{
|
||||
id: '005',
|
||||
receiver: '周八',
|
||||
address: '北京市西城区',
|
||||
status: '已完成',
|
||||
deliveryTime: '2024-10-12 15:30'
|
||||
}
|
||||
]);
|
||||
|
||||
// Methods
|
||||
const updateStatus = (order, newStatus) => {
|
||||
const orderIndex = toDeliverOrders.value.findIndex(o => o.id === order.id);
|
||||
if (orderIndex !== -1) {
|
||||
toDeliverOrders.value[orderIndex].status = newStatus;
|
||||
if (newStatus === '已完成') {
|
||||
historyOrders.value.push({
|
||||
...toDeliverOrders.value[orderIndex],
|
||||
deliveryTime: new Date().toLocaleString()
|
||||
});
|
||||
toDeliverOrders.value.splice(orderIndex, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const deleteHistoryOrder = (order) => {
|
||||
const index = historyOrders.value.findIndex(o => o.id === order.id);
|
||||
if (index !== -1) {
|
||||
historyOrders.value.splice(index, 1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTabChange = (index) => {
|
||||
currentTab.value = index;
|
||||
};
|
||||
|
||||
const openAddOrderDialog = () => {
|
||||
addOrderDialogVisible.value = true;
|
||||
};
|
||||
|
||||
const addOrder = () => {
|
||||
if (newOrder.value.id && newOrder.value.receiver && newOrder.value.address) {
|
||||
toDeliverOrders.value.push({
|
||||
...newOrder.value
|
||||
});
|
||||
newOrder.value = {
|
||||
id: '',
|
||||
receiver: '',
|
||||
address: '',
|
||||
status: '待取件'
|
||||
}; // 清空表单
|
||||
addOrderDialogVisible.value = false; // 关闭对话框
|
||||
} else {
|
||||
alert('请填写完整订单信息');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.btn {
|
||||
margin-left: 1200px;
|
||||
}
|
||||
|
||||
.order-card {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.el-table th {
|
||||
background-color: #f2f3f5;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-table td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.el-menu-vertical-demo {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.el-menu-item {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.button-container {
|
||||
text-align: right;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,132 @@
|
||||
<template>
|
||||
<el-container>
|
||||
<el-header>
|
||||
<Header />
|
||||
</el-header>
|
||||
<el-container>
|
||||
<el-main>
|
||||
<div class="complaint-container">
|
||||
<h2>快递投诉</h2>
|
||||
<el-form
|
||||
:model="complaintForm"
|
||||
:rules="rules"
|
||||
ref="complaintFormRef"
|
||||
label-width="100px"
|
||||
class="complaint-form"
|
||||
>
|
||||
<el-form-item label="订单号" prop="orderNumber">
|
||||
<el-input v-model="complaintForm.orderNumber" placeholder="请输入订单号" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="投诉原因" prop="reason">
|
||||
<el-select v-model="complaintForm.reason" placeholder="请选择投诉原因">
|
||||
<el-option label="快递未按时送达" value="未按时送达" />
|
||||
<el-option label="快递损坏或丢失" value="损坏或丢失" />
|
||||
<el-option label="服务态度差" value="服务态度差" />
|
||||
<el-option label="其他问题" value="其他" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="详细描述" prop="description">
|
||||
<el-input
|
||||
type="textarea"
|
||||
v-model="complaintForm.description"
|
||||
placeholder="请详细描述您的问题"
|
||||
rows="4"
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="联系方式" prop="contact">
|
||||
<el-input v-model="complaintForm.contact" placeholder="请输入您的联系方式" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitComplaint">提交投诉</el-button>
|
||||
<el-button @click="resetForm">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-main>
|
||||
</el-container>
|
||||
<el-footer>
|
||||
<Footer />
|
||||
</el-footer>
|
||||
</el-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { complaintAPI } from '@/api';
|
||||
import type { ComplaintForm } from '@/types/api';
|
||||
|
||||
const complaintForm = ref<ComplaintForm>({
|
||||
orderNumber: '',
|
||||
reason: '',
|
||||
description: '',
|
||||
contact: '',
|
||||
});
|
||||
|
||||
const rules = {
|
||||
orderNumber: [
|
||||
{ required: true, message: '订单号不能为空', trigger: 'blur' },
|
||||
],
|
||||
reason: [
|
||||
{ required: true, message: '请选择投诉原因', trigger: 'change' },
|
||||
],
|
||||
description: [
|
||||
{ required: true, message: '请详细描述问题', trigger: 'blur' },
|
||||
{ min: 10, message: '描述至少需要10个字', trigger: 'blur' },
|
||||
],
|
||||
contact: [
|
||||
{ required: true, message: '联系方式不能为空', trigger: 'blur' },
|
||||
{
|
||||
pattern: /^1[3-9]\d{9}$/,
|
||||
message: '请输入有效的手机号码',
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const complaintFormRef = ref();
|
||||
|
||||
const submitComplaint = async () => {
|
||||
complaintFormRef.value?.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
await complaintAPI.submitComplaint(complaintForm.value);
|
||||
ElMessage.success('投诉已提交,我们将尽快处理您的问题!');
|
||||
resetForm();
|
||||
} catch (error) {
|
||||
ElMessage.error('提交失败,请稍后重试');
|
||||
}
|
||||
} else {
|
||||
ElMessage.error('请检查表单内容是否填写完整!');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
complaintFormRef.value?.resetFields();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.complaint-container {
|
||||
max-width: 600px;
|
||||
margin: 20px auto;
|
||||
padding: 20px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.complaint-form {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,280 @@
|
||||
<template>
|
||||
<el-header>
|
||||
<Header />
|
||||
</el-header>
|
||||
<div class="delivery-container">
|
||||
<el-row class="send-container">
|
||||
<el-row class="panel send-panel send-panel1">
|
||||
<el-row class="send-container">
|
||||
<el-button class="send-btn">寄</el-button>
|
||||
<el-row>
|
||||
<el-button @click="openAddressBook">地址簿</el-button>
|
||||
<el-button>智能填写</el-button>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-form ref="senderFormRef" label-width="auto" class="form" :model="form.sender" :rules="rules.sender">
|
||||
<el-form-item label="姓名" prop="senderName">
|
||||
<el-input v-model="form.sender.senderName" placeholder="请填写发件人姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话" prop="senderPhone">
|
||||
<el-input v-model="form.sender.senderPhone" placeholder="请填写发件人联系电话"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="省市区" prop="senderProvince">
|
||||
<el-cascader
|
||||
:options="options"
|
||||
v-model="form.sender.senderProvince"
|
||||
:props="{ value: 'value', label: 'label', children: 'children' }"
|
||||
placeholder="请选择省市区"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="详细地址" prop="senderAddress">
|
||||
<el-input v-model="form.sender.senderAddress" placeholder="请填写详细地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="公司名称" prop="senderCompany" class="no-asterisk">
|
||||
<el-input v-model="form.sender.senderCompany" placeholder="请填写公司名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-image src="src/assets/arrow.png"></el-image>
|
||||
<el-row class="panel send-panel send-panel1">
|
||||
<el-row class="send-container">
|
||||
<el-button class="send-btn receiver-btn">收</el-button>
|
||||
<el-row>
|
||||
<el-button @click="openAddressBook">地址簿</el-button>
|
||||
<el-button>智能填写</el-button>
|
||||
</el-row>
|
||||
</el-row>
|
||||
<el-form ref="receiverFormRef" label-width="auto" class="form" :model="form.receiver" :rules="rules.receiver">
|
||||
<el-form-item label="姓名" prop="receiverName">
|
||||
<el-input v-model="form.receiver.receiverName" placeholder="请填写收件人姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="联系电话" prop="receiverPhone">
|
||||
<el-input v-model="form.receiver.receiverPhone" placeholder="请填写收件人联系电话"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="省市区" prop="receiverProvince">
|
||||
<el-cascader
|
||||
:options="options"
|
||||
v-model="form.receiver.receiverProvince"
|
||||
:props="{ value: 'value', label: 'label', children: 'children' }"
|
||||
placeholder="请选择省市区"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="详细地址" prop="receiverAddress">
|
||||
<el-input v-model="form.receiver.receiverAddress" placeholder="请填写详细地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="公司名称" prop="receiverCompany" class="no-asterisk">
|
||||
<el-input v-model="form.receiver.receiverCompany" placeholder="请填写公司名称"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row class="panel send-panel">
|
||||
<el-text class="end-label">寄件方式</el-text>
|
||||
<el-radio-group v-model="sendType">
|
||||
<el-radio :value="0" size="large">预约上门取件</el-radio>
|
||||
<el-radio :value="1" size="large">自行联系快递员</el-radio>
|
||||
</el-radio-group>
|
||||
</el-row>
|
||||
<el-row class="panel send-panel">
|
||||
<el-button class="confirm-btn" @click="submitForm">下单</el-button>
|
||||
</el-row>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useRouter } from 'vue-router'; // 引入路由相关的函数
|
||||
import addressList from '../../assets/addressList.js';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { deliveryAPI } from '@/api';
|
||||
import type { DeliveryForm } from '@/types/api';
|
||||
|
||||
const formatCityData = (arr) => {
|
||||
return arr.map(item => ({
|
||||
value: item.name,
|
||||
label: item.name,
|
||||
children: item.sub && item.sub.length > 0 ? formatCityData(item.sub) : []
|
||||
}));
|
||||
};
|
||||
|
||||
const options = ref(formatCityData(addressList));
|
||||
|
||||
const sendType = ref(0);
|
||||
|
||||
// 创建路由实例
|
||||
const router = useRouter();
|
||||
|
||||
const form = ref<DeliveryForm>({
|
||||
sender: {
|
||||
name: '',
|
||||
phone: '',
|
||||
province: [],
|
||||
address: '',
|
||||
company: ''
|
||||
},
|
||||
receiver: {
|
||||
name: '',
|
||||
phone: '',
|
||||
province: [],
|
||||
address: '',
|
||||
company: ''
|
||||
},
|
||||
sendType: 0
|
||||
});
|
||||
|
||||
const rules = ref({
|
||||
receiver: {
|
||||
receiverName: [
|
||||
{ required: true, message: '请输入姓名', trigger: 'blur' }
|
||||
],
|
||||
receiverPhone: [
|
||||
{ required: true, message: '请输入联系电话', trigger: 'blur' }
|
||||
],
|
||||
receiverProvince: [
|
||||
{ required: true, message: '请输入省市区', trigger: 'blur' }
|
||||
],
|
||||
receiverAddress: [
|
||||
{ required: true, message: '请输入详细地址', trigger: 'blur' }
|
||||
],
|
||||
receiverCompany: [
|
||||
{ required: false, message: '请输入公司名称', trigger: 'blur' }
|
||||
],
|
||||
},
|
||||
sender: {
|
||||
senderName: [
|
||||
{ required: true, message: '请输入姓名', trigger: 'blur' }
|
||||
],
|
||||
senderPhone: [
|
||||
{ required: true, message: '请输入联系电话', trigger: 'blur' }
|
||||
],
|
||||
senderProvince: [
|
||||
{ required: true, message: '请输入省市区', trigger: 'blur' }
|
||||
],
|
||||
senderAddress: [
|
||||
{ required: true, message: '请输入详细地址', trigger: 'blur' }
|
||||
],
|
||||
senderCompany: [
|
||||
{ required: false, message: '请输入公司名称', trigger: 'blur' }
|
||||
],
|
||||
}
|
||||
});
|
||||
|
||||
const senderFormRef = ref(null);
|
||||
const receiverFormRef = ref(null);
|
||||
|
||||
// 打开地址簿
|
||||
const openAddressBook = async () => {
|
||||
try {
|
||||
const response = await deliveryAPI.getAddressBook();
|
||||
// 处理地址簿数据...
|
||||
router.push({ name: 'address' });
|
||||
} catch (error) {
|
||||
ElMessage.error('获取地址簿失败');
|
||||
}
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const submitForm = async () => {
|
||||
if (senderFormRef.value && receiverFormRef.value) {
|
||||
const validSender = await senderFormRef.value.validate();
|
||||
const validReceiver = await receiverFormRef.value.validate();
|
||||
|
||||
if (validSender && validReceiver) {
|
||||
try {
|
||||
await deliveryAPI.submitDelivery(form.value);
|
||||
ElMessage.success('下单成功!');
|
||||
} catch (error) {
|
||||
ElMessage.error('下单失败,请稍后重试');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.delivery-container {
|
||||
padding: 20px;
|
||||
margin: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||||
}
|
||||
.send-container {
|
||||
display: flex;
|
||||
width: 70%;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
margin-top: 10px;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
margin-right: auto; /* 添加这一行 */
|
||||
}
|
||||
/* 卡片容器样式 */
|
||||
.panel {
|
||||
background-color: #f9f9f9; /* 淡雅的背景颜色 */
|
||||
border-radius: 8px; /* 圆角边框 */
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); /* 添加阴影效果 */
|
||||
padding: 30px;
|
||||
margin-top: 30px;
|
||||
margin-bottom: 20px;
|
||||
width: calc(50% - 20px); /* 设置宽度为容器宽度的一半减去间距 */
|
||||
}
|
||||
|
||||
|
||||
/* 调整第二个卡片的样式 */
|
||||
.send-panel1 {
|
||||
width: calc(50% - 20px); /* 设置宽度为容器宽度的一半减去间距 */
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.send-btn {
|
||||
background-color: #333; /* 深灰色背景 */
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
padding: 10px;
|
||||
margin-right: 10px; /* 添加右边距 */
|
||||
}
|
||||
|
||||
.receiver-btn {
|
||||
background-color: #d9534f; /* 红色背景 */
|
||||
}
|
||||
|
||||
/* 表单样式 */
|
||||
.form {
|
||||
margin-top: 10px;
|
||||
width: 70%; /* 表单宽度调整为100% */
|
||||
}
|
||||
|
||||
/* 确认按钮样式 */
|
||||
.confirm-btn {
|
||||
background-color: #428bca; /* 蓝色背景 */
|
||||
color: white;
|
||||
padding: 10px 20px; /* 添加内边距 */
|
||||
border: none; /* 去除边框 */
|
||||
border-radius: 5px; /* 圆角边框 */
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
cursor: pointer; /* 鼠标悬停时显示指针 */
|
||||
}
|
||||
|
||||
/* 标签样式 */
|
||||
.el-form-item__label {
|
||||
color: #333; /* 标签文字颜色 */
|
||||
font-weight: 500; /* 字体加粗 */
|
||||
}
|
||||
.end-label {
|
||||
font-weight: 600;
|
||||
align-self: flex-start;
|
||||
margin-right: 40px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.el-form-item__label::before {
|
||||
content: '*';
|
||||
color: red;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.el-form-item.no-asterisk .el-form-item__label::before {
|
||||
content: none;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,272 @@
|
||||
<template>
|
||||
<el-header>
|
||||
<Header />
|
||||
</el-header>
|
||||
<div class="profile-list-container">
|
||||
<div class="profile-content">
|
||||
<!-- 用户资料表单 -->
|
||||
<el-card class="profile-card" shadow="hover">
|
||||
<div class="profile-header">
|
||||
<!-- 头像 -->
|
||||
<el-avatar
|
||||
style="width: 80px; height: 80px;"
|
||||
:src="avatarUrl"
|
||||
class="avatar"
|
||||
@click="changeAvatar"
|
||||
/>
|
||||
<div class="profile-info">
|
||||
<el-form ref="profileForm" :model="profileInfo" label-width="80px">
|
||||
<el-form-item label="用户名">
|
||||
<el-input v-model="profileInfo.name" placeholder="请输入用户名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="邮箱">
|
||||
<el-input v-model="profileInfo.email" placeholder="请输入邮箱"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</div>
|
||||
<el-button type="danger" @click="logout">退出登录</el-button>
|
||||
<!-- 用户详细信息表单 -->
|
||||
<div class="profile-details">
|
||||
<el-form ref="profileDetailsForm" :model="profileInfo" label-width="80px">
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="手机号">
|
||||
<el-input v-model="profileInfo.phone" placeholder="请输入手机号"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="性别">
|
||||
<el-select v-model="profileInfo.gender" placeholder="请选择性别">
|
||||
<el-option label="男" value="男"></el-option>
|
||||
<el-option label="女" value="女"></el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="出生日期">
|
||||
<el-date-picker v-model="profileInfo.birthday" type="date" placeholder="选择日期"></el-date-picker>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="地址">
|
||||
<el-input v-model="profileInfo.address" placeholder="请输入地址"></el-input>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 地址管理表单 -->
|
||||
<el-card class="address-card" shadow="hover">
|
||||
<h3>地址管理</h3>
|
||||
<el-button type="primary" @click="addAddress">添加地址</el-button>
|
||||
<!-- 地址表单 -->
|
||||
<el-form :model="addresses" label-width="80px">
|
||||
<div v-for="(address, index) in addresses" :key="address.id" class="address-item">
|
||||
<el-form-item label="收货人" :prop="'name' + index">
|
||||
<el-input v-model="address.name" placeholder="请输入收货人姓名"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="地址" :prop="'address' + index">
|
||||
<el-input v-model="address.address" placeholder="请输入收货地址"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="电话" :prop="'phone' + index">
|
||||
<el-input v-model="address.phone" placeholder="请输入联系电话"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="text" @click="editAddress(index)">保存</el-button>
|
||||
<el-button type="text" @click="deleteAddress(address.id)">删除</el-button>
|
||||
<el-button type="text" @click="copyAddress(address)">复制</el-button>
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { profileAPI } from '@/api'
|
||||
import type { UserProfile, Address } from '@/types/api'
|
||||
|
||||
const profileInfo = ref<UserProfile>({
|
||||
name: '',
|
||||
email: '',
|
||||
phone: '',
|
||||
gender: '',
|
||||
birthday: '',
|
||||
address: '',
|
||||
})
|
||||
|
||||
const addresses = ref<Address[]>([])
|
||||
|
||||
// 获取用户信息
|
||||
const getUserInfo = async () => {
|
||||
try {
|
||||
const response = await profileAPI.getUserProfile()
|
||||
profileInfo.value = response.data
|
||||
} catch (error) {
|
||||
ElMessage.error('获取用户信息失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 更新头像
|
||||
const changeAvatar = async (event: Event) => {
|
||||
const file = (event.target as HTMLInputElement).files?.[0]
|
||||
if (file) {
|
||||
const formData = new FormData()
|
||||
formData.append('avatar', file)
|
||||
try {
|
||||
await profileAPI.updateAvatar(formData)
|
||||
ElMessage.success('头像更新成功')
|
||||
} catch (error) {
|
||||
ElMessage.error('头像更新失败')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取地址列表
|
||||
const getAddresses = async () => {
|
||||
try {
|
||||
const response = await profileAPI.getAddresses()
|
||||
addresses.value = response.data
|
||||
} catch (error) {
|
||||
ElMessage.error('获取地址列表失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 添加地址
|
||||
const addAddress = async () => {
|
||||
const newAddress = { name: '', address: '', phone: '' }
|
||||
try {
|
||||
const response = await profileAPI.addAddress(newAddress)
|
||||
addresses.value.push(response.data)
|
||||
ElMessage.success('地址添加成功')
|
||||
} catch (error) {
|
||||
ElMessage.error('地址添加失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 编辑地址
|
||||
const editAddress = async (index: number) => {
|
||||
try {
|
||||
const address = addresses.value[index]
|
||||
await profileAPI.updateAddress(address.id, address)
|
||||
ElMessage.success('地址更新成功')
|
||||
} catch (error) {
|
||||
ElMessage.error('地址更新失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 删除地址
|
||||
const deleteAddress = async (id: number) => {
|
||||
try {
|
||||
await profileAPI.deleteAddress(id)
|
||||
addresses.value = addresses.value.filter(addr => addr.id !== id)
|
||||
ElMessage.success('地址删除成功')
|
||||
} catch (error) {
|
||||
ElMessage.error('地址删除失败')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getUserInfo()
|
||||
getAddresses()
|
||||
})
|
||||
|
||||
// ... 其他代码保持不变 ...
|
||||
</script>
|
||||
<style scoped>
|
||||
.profile-list-container {
|
||||
position: fixed;
|
||||
top: 60px;
|
||||
right: 0;
|
||||
width: calc(100% - 220px);
|
||||
height: calc(100vh - 60px);
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.profile-content {
|
||||
max-width: 1000px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.profile-card {
|
||||
margin-bottom: 20px;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.profile-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.profile-info {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.profile-details {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.address-card {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.address-item {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.address-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* 响应式布局 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.profile-list-container {
|
||||
width: calc(100% - 64px);
|
||||
}
|
||||
|
||||
.profile-content {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.el-form-item {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Element Plus 样式覆盖 */
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
:deep(.el-button--text) {
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
:deep(.el-form-item__label) {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
:deep(.el-input__inner) {
|
||||
border-radius: 4px;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,215 @@
|
||||
<template>
|
||||
<el-header>
|
||||
<Header />
|
||||
</el-header>
|
||||
<div class="service-list-container">
|
||||
<div class="service-content">
|
||||
<ul class="service-list">
|
||||
<li>
|
||||
<el-image src="src/assets/time.png"></el-image>
|
||||
<div>
|
||||
<p>运费时效</p>
|
||||
<p>查预估费用和预计送达时间</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<el-image src="src/assets/serviceSpot.png"></el-image>
|
||||
<div>
|
||||
<p>服务网点</p>
|
||||
<p>查各地网点、丰巢柜、合作点</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<el-image src="src/assets/require.png"></el-image>
|
||||
<div>
|
||||
<p>收寄标准</p>
|
||||
<p>查物品能不能寄</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<el-image src="src/assets/serviceRange.png"></el-image>
|
||||
<div>
|
||||
<p>服务范围</p>
|
||||
<p>查地址能不能收派</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="service-list">
|
||||
<li>
|
||||
<el-icon><DataLine /></el-icon>
|
||||
<div>
|
||||
<p>汇率查询</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<el-icon><Document /></el-icon>
|
||||
<div>
|
||||
<p>常用表格</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<el-icon><SetUp /></el-icon>
|
||||
<div>
|
||||
<p>清关服务</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<el-icon><DataBoard /></el-icon>
|
||||
<div>
|
||||
<p>无着件公示</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<el-icon><HomeFilled /></el-icon>
|
||||
<div>
|
||||
<p>特殊入仓地址查询</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<el-icon><Download /></el-icon>
|
||||
<div>
|
||||
<p>电子回单下载</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import {
|
||||
DataLine,
|
||||
Document,
|
||||
SetUp,
|
||||
DataBoard,
|
||||
HomeFilled,
|
||||
Download
|
||||
} from '@element-plus/icons-vue';
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { serviceAPI } from '@/api'
|
||||
|
||||
// 查询运费时效
|
||||
const checkDeliveryTime = async (from: string, to: string) => {
|
||||
try {
|
||||
const response = await serviceAPI.getDeliveryTime(from, to)
|
||||
// 处理响应数据...
|
||||
} catch (error) {
|
||||
ElMessage.error('查询失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 查询服务网点
|
||||
const checkServicePoints = async (location: string) => {
|
||||
try {
|
||||
const response = await serviceAPI.getServicePoints(location)
|
||||
// 处理响应数据...
|
||||
} catch (error) {
|
||||
ElMessage.error('查询失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 查询收寄标准
|
||||
const checkDeliveryStandards = async () => {
|
||||
try {
|
||||
const response = await serviceAPI.getDeliveryStandards()
|
||||
// 处理响应数据...
|
||||
} catch (error) {
|
||||
ElMessage.error('查询失败')
|
||||
}
|
||||
}
|
||||
|
||||
// 查询服务范围
|
||||
const checkServiceRange = async (address: string) => {
|
||||
try {
|
||||
const response = await serviceAPI.getServiceRange(address)
|
||||
// 处理响应数据...
|
||||
} catch (error) {
|
||||
ElMessage.error('查询失败')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.service-list-container {
|
||||
position: fixed;
|
||||
top: 60px; /* header 高度 */
|
||||
right: 0;
|
||||
width: calc(100% - 220px); /* 减去侧边栏宽度 */
|
||||
height: calc(100vh - 60px);
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.service-content {
|
||||
max-width: 1200px;
|
||||
margin: 20px auto;
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.service-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.service-list li {
|
||||
flex: 0 0 200px;
|
||||
border: 1px solid #eaeaea;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.service-list li:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.service-list img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.service-list .el-icon {
|
||||
font-size: 30px;
|
||||
margin: 10px 0;
|
||||
color: #409EFF;
|
||||
}
|
||||
|
||||
.service-list p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.service-list p:first-child {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.service-list p:last-child {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 响应式布局 */
|
||||
@media screen and (max-width: 768px) {
|
||||
.service-list-container {
|
||||
width: calc(100% - 64px); /* 折叠时的侧边栏宽度 */
|
||||
}
|
||||
|
||||
.service-list li {
|
||||
flex: 0 0 150px;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -0,0 +1,12 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import path from 'path'
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [vue()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, 'src'),
|
||||
}
|
||||
}
|
||||
})
|