地址路径修改

This commit is contained in:
2025-10-26 13:15:04 +08:00
parent be2323074b
commit 271b88232c
77 changed files with 13254 additions and 228 deletions

View File

@@ -1,6 +1,9 @@
// 管理员界面 - 全屏管理面板
import { UserInfo } from '../../types';
import { Role } from '../../utils/roleUtils';
import userService from '../../services/userService';
import statisticsService from '../../services/statisticsService';
import { API_BASE_URL } from '../../services/apiService';
Page({
data: {
@@ -60,7 +63,7 @@ Page({
currentTime: ''
},
onLoad() {
onLoad: function() {
this.getUserInfo();
this.loadStatistics();
this.updateCurrentTime();
@@ -70,49 +73,143 @@ Page({
}, 1000);
},
onShow() {
onShow: function() {
this.loadStatistics();
this.updateCurrentTime();
},
/**
* 获取完整的头像URL
* @param avatarPath 头像相对路径
* @returns 完整的头像URL
*/
getFullAvatarUrl: function(avatarPath: string | undefined): string {
if (!avatarPath) {
return '/images/user-avatar.png';
}
// 如果已经是完整URL直接返回
if (avatarPath.startsWith('http')) {
return avatarPath;
}
// 将相对路径转换为完整URL
return `${API_BASE_URL}${avatarPath}`;
},
/**
* 处理用户信息预先准备好完整的头像URL
* @param userInfo 原始用户信息
* @returns 处理后的用户信息
*/
processUserInfo: function(userInfo: any): any {
if (!userInfo) {
return {
id: 0,
role: Role.ADMIN,
name: '管理员',
fullAvatarUrl: '/images/user-avatar.png'
};
}
// 预先准备好完整的头像URL
const processedUserInfo = { ...userInfo };
if (userInfo.avatarPath) {
processedUserInfo.fullAvatarUrl = this.getFullAvatarUrl(userInfo.avatarPath);
} else {
processedUserInfo.fullAvatarUrl = '/images/user-avatar.png';
}
return processedUserInfo;
},
/**
* 获取用户信息
*/
getUserInfo() {
const app = getApp<any>();
if (app.globalData.userInfo) {
const userInfo = app.globalData.userInfo;
this.setData({ userInfo });
getUserInfo: async function() {
try {
const app = getApp<any>();
// 验证是否为管理员
if (userInfo.role !== 'ADMIN') {
wx.showToast({
title: '无权限访问',
icon: 'none'
});
wx.navigateBack();
// 如果全局数据中没有用户信息,尝试从用户服务获取
if (!app.globalData.userInfo) {
const userInfo = await userService.getUserInfo();
if (userInfo) {
app.globalData.userInfo = userInfo;
}
}
if (app.globalData.userInfo) {
const userInfo = this.processUserInfo(app.globalData.userInfo);
this.setData({ userInfo });
// 验证是否为管理员
if (userInfo.role !== Role.ADMIN) {
wx.showToast({
title: '无权限访问',
icon: 'none'
});
wx.navigateBack();
}
} else {
// 如果仍然没有用户信息,显示默认信息
this.setData({
userInfo: this.processUserInfo(null)
});
}
} catch (error) {
console.error('获取用户信息失败:', error);
// 出错时显示默认信息
this.setData({
userInfo: this.processUserInfo(null)
});
}
},
/**
* 加载统计数据
*/
loadStatistics() {
// 模拟加载统计数据
this.setData({
stats: {
employeeCount: 25,
orderCount: 156,
warehouseCount: 8
}
});
loadStatistics: async function() {
try {
wx.showLoading({
title: '加载数据中...'
});
// 使用统计服务获取真实数据
const stats = await statisticsService.getSystemStats();
this.setData({
stats: {
employeeCount: stats.employeeCount,
orderCount: stats.orderCount,
warehouseCount: stats.warehouseCount
}
});
wx.hideLoading();
} catch (error) {
console.error('加载统计数据失败:', error);
wx.hideLoading();
// 出错时使用默认值
this.setData({
stats: {
employeeCount: 0,
orderCount: 0,
warehouseCount: 0
}
});
wx.showToast({
title: '数据加载失败',
icon: 'none'
});
}
},
/**
* 菜单项点击事件
*/
onMenuItemTap(e: any) {
onMenuItemTap: function(e: any) {
const itemId = e.currentTarget.dataset.id;
switch (itemId) {
@@ -152,14 +249,14 @@ Page({
/**
* 返回首页
*/
goBack() {
goBack: function() {
wx.navigateBack();
},
/**
* 刷新数据
*/
onRefresh() {
onRefresh: function() {
this.loadStatistics();
this.updateCurrentTime();
wx.showToast({
@@ -171,7 +268,7 @@ Page({
/**
* 更新当前时间
*/
updateCurrentTime() {
updateCurrentTime: function() {
const now = new Date();
const timeString = now.toLocaleString('zh-CN', {
year: 'numeric',
@@ -189,7 +286,7 @@ Page({
/**
* 解绑微信处理
*/
async onUnbindWechat() {
onUnbindWechat: async function() {
try {
// 确认对话框
wx.showModal({

View File

@@ -7,10 +7,14 @@
<view class="back-icon" bindtap="goBack">
<text class="back-arrow"></text>
</view>
<view class="admin-avatar">👑</view>
<!-- 用户头像 -->
<view class="admin-avatar">
<image wx:if="{{userInfo && userInfo.fullAvatarUrl}}" src="{{userInfo.fullAvatarUrl}}" class="avatar-image" mode="aspectFill"></image>
<text wx:else class="avatar-placeholder">{{userInfo && userInfo.name ? userInfo.name.charAt(0) : '管'}}</text>
</view>
<view class="admin-info">
<text class="admin-name">{{userInfo.name || '管理员'}}</text>
<text class="admin-role">系统管理员</text>
<text class="admin-name">{{userInfo && userInfo.name ? userInfo.name : '管理员'}}</text>
<text class="admin-role">{{userInfo && userInfo.role ? (userInfo.role === 'ADMIN' ? '系统管理员' : userInfo.role === 'MANAGER' ? '经理' : '员工') : '系统管理员'}}</text>
</view>
</view>
<view class="header-right">

View File

@@ -58,6 +58,23 @@
border-radius: 50%;
margin-right: 20rpx;
border: 3rpx solid #667eea;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
background: #f0f0f0;
}
.avatar-image {
width: 100%;
height: 100%;
border-radius: 50%;
}
.avatar-placeholder {
font-size: 32rpx;
font-weight: bold;
color: #667eea;
}
.admin-info {

View File

@@ -2,6 +2,8 @@
import { EmployeeInfo } from '../../types';
import employeeService from '../../services/employeeService';
import { Role, getRoleOptions } from '../../utils/roleUtils';
import { avatarCache } from '../../utils/avatarCache';
import { API_BASE_URL } from '../../services/apiService';
Page({
data: {
@@ -10,7 +12,7 @@ Page({
filteredEmployees: [] as EmployeeInfo[],
// 页面状态
currentTab: 'list', // list: 列表页, add: 添加页
currentTab: 'list', // list: 列表页, add: 添加页, edit: 编辑页
loading: false,
// 添加员工表单数据
@@ -20,6 +22,15 @@ Page({
role: Role.DELIVERY_PERSON
},
// 编辑员工表单数据
editForm: {
id: 0,
name: '',
phone: '',
role: Role.DELIVERY_PERSON,
avatarUrl: ''
},
// 错误信息
errorMessage: '',
successMessage: '',
@@ -31,7 +42,10 @@ Page({
roleOptions: getRoleOptions(),
// 用户信息
userInfo: null as any
userInfo: null as any,
// 临时头像路径(用于头像上传)
tempAvatarPath: ''
},
onLoad() {
@@ -40,7 +54,10 @@ Page({
},
onShow() {
this.loadEmployees();
// 只在页面显示时检查是否需要刷新数据,避免频繁请求
if (this.data.employees.length === 0) {
this.loadEmployees();
}
},
/**
@@ -63,6 +80,45 @@ Page({
}
},
/**
* 获取完整的头像URL
* @param avatarPath 头像相对路径
* @returns 完整的头像URL
*/
getFullAvatarUrl(avatarPath: string | undefined): string {
if (!avatarPath) {
return '/images/user-avatar.png';
}
// 如果已经是完整URL直接返回
if (avatarPath.startsWith('http')) {
return avatarPath;
}
// 将相对路径转换为完整URL
return `${API_BASE_URL}${avatarPath}`;
},
/**
* 获取本地缓存的头像路径
*/
async getLocalAvatarPath(avatarPath: string | undefined): Promise<string> {
if (!avatarPath) {
return '/images/user-avatar.png';
}
try {
// 使用头像缓存获取本地文件路径
const fullAvatarUrl = this.getFullAvatarUrl(avatarPath);
const localAvatarPath = await avatarCache.getAvatarPath(fullAvatarUrl);
return localAvatarPath;
} catch (error) {
console.error('获取头像缓存失败:', error);
// 如果缓存失败回退到远程URL
return this.getFullAvatarUrl(avatarPath);
}
},
/**
* 加载员工列表
*/
@@ -75,11 +131,24 @@ Page({
try {
const employees = await employeeService.getEmployees();
// 为每个员工获取本地缓存的头像路径
const employeesWithAvatars = await Promise.all(
employees.map(async (employee) => {
const localAvatarPath = await this.getLocalAvatarPath(employee.avatarPath);
return {
...employee,
fullAvatarUrl: localAvatarPath
};
})
);
// 获取过滤后的员工列表
const filteredEmployees = this.getFilteredEmployees(employees);
const filteredEmployees = this.getFilteredEmployees(employeesWithAvatars);
this.setData({
employees,
employees: employeesWithAvatars,
filteredEmployees,
loading: false
});
@@ -103,7 +172,8 @@ Page({
successMessage: ''
});
if (tab === 'list') {
// 只在切换到列表页且没有数据时才加载,避免频繁请求
if (tab === 'list' && this.data.employees.length === 0) {
this.loadEmployees();
}
},
@@ -215,6 +285,220 @@ Page({
}
},
/**
* 编辑员工
*/
editEmployee(e: any) {
const employeeId = e.currentTarget.dataset.id;
const employee = this.data.employees.find(emp => emp.id === employeeId);
if (employee) {
this.setData({
editForm: {
id: employee.id || 0,
name: employee.name || '',
phone: employee.phone || '',
role: employee.role || Role.DELIVERY_PERSON,
avatarUrl: ''
},
currentTab: 'edit'
});
}
},
/**
* 提交编辑员工表单
*/
async submitEditForm() {
if (!this.validateEditForm()) {
return;
}
this.setData({
loading: true,
errorMessage: '',
successMessage: ''
});
try {
// 调用更新员工的API方法
await employeeService.updateEmployee(this.data.editForm.id, {
name: this.data.editForm.name,
phone: this.data.editForm.phone,
role: this.data.editForm.role
});
// 如果有新头像,上传头像
if (this.data.tempAvatarPath) {
try {
const result = await employeeService.uploadAvatar(this.data.editForm.id, this.data.tempAvatarPath);
if (result.success && result.avatarUrl) {
// 更新头像URL
this.setData({
'editForm.avatarUrl': result.avatarUrl
});
}
} catch (avatarError) {
console.error('上传头像失败:', avatarError);
wx.showToast({
title: '头像上传失败',
icon: 'error'
});
}
}
this.setData({
loading: false,
successMessage: '员工更新成功',
currentTab: 'list',
tempAvatarPath: ''
});
// 重新加载员工列表
this.loadEmployees();
} catch (error) {
console.error('更新员工失败:', error);
this.setData({
loading: false,
errorMessage: '更新员工失败,请重试'
});
}
},
/**
* 选择头像
*/
chooseAvatar() {
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['album'],
maxDuration: 30,
camera: 'back',
success: (res) => {
if (res.tempFiles && res.tempFiles.length > 0) {
const tempFilePath = res.tempFiles[0].tempFilePath;
this.setData({
'editForm.avatarUrl': tempFilePath,
tempAvatarPath: tempFilePath
});
}
},
fail: (err) => {
console.error('选择头像失败:', err);
wx.showToast({
title: '选择头像失败',
icon: 'error'
});
}
});
},
/**
* 拍照
*/
takePhoto() {
wx.chooseMedia({
count: 1,
mediaType: ['image'],
sourceType: ['camera'],
maxDuration: 30,
camera: 'back',
success: (res) => {
if (res.tempFiles && res.tempFiles.length > 0) {
const tempFilePath = res.tempFiles[0].tempFilePath;
this.setData({
'editForm.avatarUrl': tempFilePath,
tempAvatarPath: tempFilePath
});
}
},
fail: (err) => {
console.error('拍照失败:', err);
wx.showToast({
title: '拍照失败',
icon: 'error'
});
}
});
},
/**
* 验证编辑表单
*/
validateEditForm(): boolean {
const { name, phone, role } = this.data.editForm;
if (!name.trim()) {
this.setData({
errorMessage: '请输入员工姓名'
});
return false;
}
if (!phone.trim()) {
this.setData({
errorMessage: '请输入员工工号'
});
return false;
}
// 简单的工号格式验证
const phoneRegex = /^\d+$/;
if (!phoneRegex.test(phone)) {
this.setData({
errorMessage: '工号只能包含数字'
});
return false;
}
if (!role) {
this.setData({
errorMessage: '请选择员工角色'
});
return false;
}
return true;
},
/**
* 取消编辑
*/
cancelEdit() {
this.setData({
currentTab: 'list',
errorMessage: '',
successMessage: ''
});
},
/**
* 编辑表单输入处理
*/
onEditFormInput(e: any) {
const { field } = e.currentTarget.dataset;
const value = e.detail.value;
this.setData({
[`editForm.${field}`]: value,
errorMessage: '',
successMessage: ''
});
},
/**
* 处理编辑角色选择
*/
onEditRoleChange(e: any) {
const index = e.detail.value;
const selectedRole = this.data.roleOptions[index].value;
this.setData({
'editForm.role': selectedRole
});
},
/**
* 删除员工
*/
@@ -304,19 +588,8 @@ Page({
return [];
}
// 获取当前登录用户信息
const app = getApp();
const currentUser = app.globalData.userInfo;
// 过滤掉当前登录用户
let filteredEmployees = employees.filter(emp => {
// 如果没有当前用户信息,显示所有员工
if (!currentUser || !currentUser.id) {
return true;
}
// 过滤掉当前用户
return emp.id !== currentUser.id;
});
// 显示所有员工,包括当前用户
let filteredEmployees = employees;
// 更严格的搜索关键词检查
if (!searchKeyword || typeof searchKeyword !== 'string' || !searchKeyword.trim()) {

View File

@@ -30,6 +30,13 @@
>
<text class="tab-text">添加员工</text>
</view>
<view
class="tab-item {{currentTab === 'edit' ? 'active' : ''}}"
bindtap="switchTab"
data-tab="edit"
>
<text class="tab-text">编辑员工</text>
</view>
</view>
<!-- 消息提示 -->
@@ -70,21 +77,32 @@
<view wx:for="{{filteredEmployees}}" wx:key="id" class="employee-item">
<view class="employee-info">
<view class="employee-avatar">
<text class="avatar-text">{{item.name.charAt(0)}}</text>
<image wx:if="{{item.fullAvatarUrl}}" class="avatar-image" src="{{item.fullAvatarUrl}}" mode="aspectFill"></image>
<view wx:else class="avatar-placeholder">
<text class="avatar-text">{{item.name.charAt(0)}}</text>
</view>
</view>
<view class="employee-details">
<view class="employee-name-row">
<text class="employee-name">{{item.name}}</text>
<text class="employee-role {{item.role === 'ADMIN' ? 'admin-role' : ''}}">
<text class="role-icon">{{item.role === 'ADMIN' ? '👑' : '🚚'}}</text>
{{getRoleText(item.role)}}
</text>
<view class="employee-role {{item.role === 'ADMIN' ? 'admin-role' : ''}}">
<text class="role-icon">👤</text>
<text>{{item.role === 'ADMIN' ? '管理员' : '配送员'}}</text>
</view>
</view>
<text class="employee-phone">工号: {{item.phone}}</text>
<text class="employee-phone">{{item.phone}}</text>
<text class="employee-id">ID: {{item.id}}</text>
</view>
</view>
<view class="employee-actions">
<button
class="edit-btn"
bindtap="editEmployee"
data-id="{{item.id}}"
size="mini"
>
编辑
</button>
<button
class="delete-btn"
bindtap="deleteEmployee"
@@ -165,4 +183,92 @@
</button>
</view>
</view>
<!-- 编辑员工页面 -->
<view wx:if="{{currentTab === 'edit'}}" class="edit-container">
<view class="form-container">
<view class="form-header">
<text class="form-title">编辑员工信息</text>
</view>
<!-- 头像上传区域 -->
<view class="form-item">
<text class="form-label">员工头像</text>
<view class="avatar-upload-container">
<view class="avatar-preview">
<image wx:if="{{editForm.avatarUrl}}" class="avatar-image" src="{{editForm.avatarUrl}}" mode="aspectFill"></image>
<view wx:else class="avatar-placeholder">
<text class="avatar-text">{{editForm.name ? editForm.name.charAt(0) : '?'}}</text>
</view>
</view>
<view class="avatar-actions">
<button class="avatar-btn" bindtap="chooseAvatar" size="mini">选择头像</button>
<button class="avatar-btn" bindtap="takePhoto" size="mini">拍照</button>
</view>
</view>
</view>
<view class="form-item">
<text class="form-label">员工姓名</text>
<input
class="form-input"
placeholder="请输入员工姓名"
value="{{editForm.name}}"
bindinput="onEditFormInput"
data-field="name"
/>
</view>
<view class="form-item">
<text class="form-label">员工工号</text>
<input
class="form-input"
placeholder="请输入员工工号"
type="number"
value="{{editForm.phone}}"
bindinput="onEditFormInput"
data-field="phone"
/>
</view>
<view class="form-item">
<text class="form-label">员工角色</text>
<picker
class="form-picker"
bindchange="onEditRoleChange"
range="{{roleOptions}}"
range-key="label"
>
<view class="picker-display">
<text class="picker-text">
{{editForm.role === 'ADMIN' ? '管理员' : editForm.role === 'DELIVERY_PERSON' ? '配送员' : '请选择角色'}}
</text>
<text class="picker-arrow">▼</text>
</view>
</picker>
</view>
<view class="form-hint">
<text class="hint-text">
提示:修改员工信息后,用户可以使用新的信息进行绑定
</text>
</view>
<view class="form-actions">
<button
class="submit-btn"
bindtap="submitEditForm"
disabled="{{loading}}"
>
{{loading ? '更新中...' : '更新员工'}}
</button>
<button
class="cancel-btn"
bindtap="cancelEdit"
>
取消
</button>
</view>
</view>
</view>
</view>

View File

@@ -189,19 +189,22 @@
/* 员工列表样式 */
.employee-list {
flex: 1;
padding: 0 40rpx;
padding: 0 30rpx;
box-sizing: border-box;
}
.employee-item {
background: white;
padding: 30rpx;
margin: 20rpx 0;
padding: 25rpx;
margin: 15rpx 0;
border-radius: 12rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
display: flex;
justify-content: space-between;
align-items: center;
transition: transform 0.3s ease;
box-sizing: border-box;
max-width: 100%;
overflow: hidden;
}
.employee-item:active {
@@ -212,45 +215,77 @@
display: flex;
align-items: center;
flex: 1;
min-width: 0;
}
.employee-avatar {
width: 80rpx;
height: 80rpx;
width: 70rpx;
height: 70rpx;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
margin-right: 25rpx;
margin-right: 20rpx;
color: white;
font-size: 32rpx;
font-size: 28rpx;
font-weight: bold;
flex-shrink: 0;
overflow: hidden;
position: relative;
}
.employee-avatar .avatar-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.employee-avatar .avatar-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.employee-avatar .avatar-text {
font-size: 28rpx;
font-weight: bold;
color: white;
}
.employee-details {
flex: 1;
min-width: 0;
}
.employee-name-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
margin-bottom: 8rpx;
gap: 15rpx;
}
.employee-name {
font-size: 30rpx;
font-size: 28rpx;
font-weight: bold;
color: #333;
flex-shrink: 0;
max-width: 200rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.employee-role {
font-size: 24rpx;
font-size: 22rpx;
background: #f0f0f0;
padding: 8rpx 16rpx;
border-radius: 20rpx;
padding: 6rpx 12rpx;
border-radius: 16rpx;
color: #666;
flex-shrink: 0;
}
.employee-role.admin-role {
@@ -259,23 +294,30 @@
}
.role-icon {
margin-right: 5rpx;
margin-right: 4rpx;
}
.employee-phone {
display: block;
font-size: 26rpx;
font-size: 24rpx;
color: #666;
margin-bottom: 5rpx;
margin-bottom: 4rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.employee-id {
font-size: 22rpx;
font-size: 20rpx;
color: #999;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.employee-actions {
margin-left: 20rpx;
margin-left: 15rpx;
flex-shrink: 0;
}
.delete-btn {
@@ -392,4 +434,80 @@
.submit-btn:disabled {
opacity: 0.6;
}
/* 头像上传样式 */
.avatar-upload-container {
display: flex;
align-items: center;
gap: 30rpx;
}
.avatar-preview {
width: 120rpx;
height: 120rpx;
border-radius: 50%;
overflow: hidden;
background: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
border: 2rpx solid #ddd;
}
.avatar-image {
width: 100%;
height: 100%;
}
.avatar-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.avatar-text {
font-size: 48rpx;
font-weight: bold;
color: white;
}
.avatar-actions {
display: flex;
flex-direction: column;
gap: 15rpx;
}
.avatar-btn {
background: #f8f9fa;
border: 1rpx solid #ddd;
color: #333;
padding: 15rpx 20rpx;
border-radius: 8rpx;
font-size: 24rpx;
}
.avatar-btn:active {
background: #e9ecef;
}
/* 编辑页面样式 */
.edit-container {
flex: 1;
padding: 40rpx;
background: white;
}
.cancel-btn {
width: 100%;
background: #f8f9fa;
color: #666;
border: 1rpx solid #ddd;
padding: 30rpx;
border-radius: 12rpx;
font-size: 28rpx;
margin-top: 20rpx;
}

View File

@@ -0,0 +1,7 @@
{
"usingComponents": {},
"navigationBarTitleText": "个人信息",
"navigationStyle": "custom",
"enablePullDownRefresh": true,
"backgroundColor": "#f5f5f5"
}

View File

@@ -0,0 +1,218 @@
// 个人信息页面
import { UserInfo } from '../../types';
import userService from '../../services/userService';
import statisticsService from '../../services/statisticsService';
Page({
data: {
userInfo: null as UserInfo | null,
// 个人统计数据
personalStats: {
totalOrders: 0, // 总订单数
completedOrders: 0, // 已完成订单数
pendingOrders: 0, // 待处理订单数
deliveryRate: 0, // 配送成功率
averageTime: 0 // 平均配送时间
},
// 系统统计数据
systemStats: {
employeeCount: 0, // 员工总数
orderCount: 0, // 订单总数
warehouseCount: 0 // 仓库总数
},
loading: true
},
onLoad() {
this.loadUserInfo();
this.loadStatistics();
},
onShow() {
// 页面显示时重新加载数据
this.loadUserInfo();
this.loadStatistics();
},
/**
* 加载用户信息
*/
async loadUserInfo() {
try {
const app = getApp<any>();
if (app.globalData.userInfo) {
this.setData({
userInfo: app.globalData.userInfo
});
} else {
// 如果没有全局用户信息尝试从API获取
const userInfo = await userService.getUserInfo();
this.setData({ userInfo });
}
} catch (error) {
console.error('加载用户信息失败:', error);
wx.showToast({
title: '加载用户信息失败',
icon: 'none'
});
}
},
/**
* 加载统计数据
*/
async loadStatistics() {
this.setData({ loading: true });
try {
wx.showLoading({
title: '加载统计数据...'
});
// 强制刷新统计数据,不使用缓存
const systemStats = await statisticsService.getSystemStats(true);
// 获取个人统计数据这里需要根据用户ID获取个人统计数据
const personalStats = await this.getPersonalStats();
this.setData({
systemStats: {
employeeCount: systemStats.employeeCount,
orderCount: systemStats.orderCount,
warehouseCount: systemStats.warehouseCount
},
personalStats,
loading: false
});
wx.hideLoading();
} catch (error) {
console.error('加载统计数据失败:', error);
this.setData({ loading: false });
wx.hideLoading();
wx.showToast({
title: '加载统计数据失败',
icon: 'none'
});
}
},
/**
* 获取个人统计数据
*/
async getPersonalStats() {
try {
// 这里应该调用个人统计API
// 暂时使用模拟数据
return {
totalOrders: 156,
completedOrders: 142,
pendingOrders: 14,
deliveryRate: 91.0,
averageTime: 45
};
} catch (error) {
console.error('获取个人统计数据失败:', error);
// 返回默认值
return {
totalOrders: 0,
completedOrders: 0,
pendingOrders: 0,
deliveryRate: 0,
averageTime: 0
};
}
},
/**
* 刷新数据
*/
onRefresh() {
this.loadStatistics();
},
/**
* 返回上一页
*/
goBack() {
wx.navigateBack();
},
/**
* 编辑个人信息
*/
onEditProfile() {
wx.showToast({
title: '编辑功能开发中',
icon: 'none'
});
},
/**
* 查看历史订单
*/
onViewHistory() {
wx.navigateTo({
url: '/pages/staff/order-management'
});
},
/**
* 联系客服
*/
onContactSupport() {
wx.makePhoneCall({
phoneNumber: '400-123-4567'
});
},
/**
* 退出登录
*/
onLogout() {
wx.showModal({
title: '确认退出',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
this.performLogout();
}
}
});
},
/**
* 执行退出登录操作
*/
async performLogout() {
try {
wx.showLoading({
title: '退出中...'
});
// 调用用户服务的退出登录方法
const userService = require('../../services/userService').default;
await userService.logout();
// 清除全局用户信息
const app = getApp<any>();
app.globalData.userInfo = null;
wx.hideLoading();
// 跳转到首页
wx.reLaunch({
url: '/pages/index/index'
});
} catch (error) {
console.error('退出登录失败:', error);
wx.hideLoading();
wx.showToast({
title: '退出登录失败',
icon: 'none'
});
}
}
});

View File

@@ -0,0 +1,120 @@
<!-- 个人信息页面 -->
<view class="profile-container">
<!-- 顶部导航栏 -->
<view class="profile-header">
<view class="header-left">
<!-- 微信风格返回按钮 -->
<view class="back-icon" bindtap="goBack">
<text class="back-arrow"></text>
</view>
<view class="profile-avatar">👤</view>
<view class="profile-info">
<text class="profile-name">{{userInfo.name || '用户'}}</text>
<text class="profile-role">{{userInfo.role === 'ADMIN' ? '管理员' : '员工'}}</text>
</view>
</view>
<view class="header-right">
<button class="refresh-btn" bindtap="onRefresh">刷新</button>
</view>
</view>
<!-- 加载状态 -->
<view wx:if="{{loading}}" class="loading-container">
<view class="loading-spinner"></view>
<text class="loading-text">正在加载数据...</text>
</view>
<!-- 主内容区域 -->
<view wx:else class="profile-content">
<!-- 个人信息卡片 -->
<view class="info-card">
<view class="card-header">
<text class="card-title">个人信息</text>
<button class="edit-btn" bindtap="onEditProfile">编辑</button>
</view>
<view class="info-grid">
<view class="info-item">
<text class="info-label">姓名</text>
<text class="info-value">{{userInfo.name || '未设置'}}</text>
</view>
<view class="info-item">
<text class="info-label">手机号</text>
<text class="info-value">{{userInfo.phone || '未设置'}}</text>
</view>
<view class="info-item">
<text class="info-label">角色</text>
<text class="info-value">{{userInfo.role === 'ADMIN' ? '管理员' : '员工'}}</text>
</view>
<view class="info-item">
<text class="info-label">用户ID</text>
<text class="info-value">{{userInfo.id || '未知'}}</text>
</view>
</view>
</view>
<!-- 个人统计卡片 -->
<view class="stats-card">
<view class="card-header">
<text class="card-title">个人工作统计</text>
<button class="history-btn" bindtap="onViewHistory">查看历史</button>
</view>
<view class="stats-grid">
<view class="stat-item">
<view class="stat-icon">📦</view>
<text class="stat-value">{{personalStats.totalOrders}}</text>
<text class="stat-label">总订单数</text>
</view>
<view class="stat-item">
<view class="stat-icon">✅</view>
<text class="stat-value">{{personalStats.completedOrders}}</text>
<text class="stat-label">已完成</text>
</view>
<view class="stat-item">
<view class="stat-icon">⏳</view>
<text class="stat-value">{{personalStats.pendingOrders}}</text>
<text class="stat-label">待处理</text>
</view>
<view class="stat-item">
<view class="stat-icon">📊</view>
<text class="stat-value">{{personalStats.deliveryRate}}%</text>
<text class="stat-label">成功率</text>
</view>
<view class="stat-item">
<view class="stat-icon">⏱️</view>
<text class="stat-value">{{personalStats.averageTime}}分钟</text>
<text class="stat-label">平均时间</text>
</view>
</view>
</view>
<!-- 系统统计卡片 -->
<view class="stats-card">
<view class="card-header">
<text class="card-title">系统概览</text>
</view>
<view class="stats-grid">
<view class="stat-item">
<view class="stat-icon employee-icon">👥</view>
<text class="stat-value">{{systemStats.employeeCount}}</text>
<text class="stat-label">员工总数</text>
</view>
<view class="stat-item">
<view class="stat-icon order-icon">📦</view>
<text class="stat-value">{{systemStats.orderCount}}</text>
<text class="stat-label">订单总数</text>
</view>
<view class="stat-item">
<view class="stat-icon warehouse-icon">🏭</view>
<text class="stat-value">{{systemStats.warehouseCount}}</text>
<text class="stat-label">仓库数量</text>
</view>
</view>
</view>
<!-- 功能按钮区域 -->
<view class="action-buttons">
<button class="action-btn contact-btn" bindtap="onContactSupport">联系客服</button>
<button class="action-btn logout-btn" bindtap="onLogout">退出登录</button>
</view>
</view>
</view>

View File

@@ -0,0 +1,288 @@
/* 个人信息页面样式 */
.profile-container {
min-height: 100vh;
background: #f5f5f5;
}
/* 顶部导航栏样式 */
.profile-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 40rpx 30rpx;
background: white;
border-bottom: 1rpx solid #e0e0e0;
}
.header-left {
display: flex;
align-items: center;
gap: 20rpx;
}
.back-icon {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
background: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
font-size: 36rpx;
color: #333;
}
.back-arrow {
font-weight: bold;
}
.profile-avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
background: #3498db;
display: flex;
align-items: center;
justify-content: center;
font-size: 40rpx;
color: white;
}
.profile-info {
display: flex;
flex-direction: column;
}
.profile-name {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 5rpx;
}
.profile-role {
font-size: 24rpx;
color: #666;
background: #f0f0f0;
padding: 4rpx 12rpx;
border-radius: 12rpx;
align-self: flex-start;
}
.header-right {
display: flex;
gap: 20rpx;
}
.refresh-btn {
padding: 15rpx 25rpx;
border: none;
border-radius: 8rpx;
font-size: 26rpx;
background: #3498db;
color: white;
cursor: pointer;
transition: all 0.3s ease;
}
.refresh-btn:active {
transform: translateY(1rpx);
}
/* 加载状态样式 */
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
}
.loading-spinner {
width: 60rpx;
height: 60rpx;
border: 4rpx solid #f3f3f3;
border-top: 4rpx solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20rpx;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loading-text {
font-size: 28rpx;
color: #666;
}
/* 主内容区域样式 */
.profile-content {
padding: 30rpx;
}
/* 卡片通用样式 */
.info-card, .stats-card {
background: white;
border-radius: 15rpx;
padding: 30rpx;
margin-bottom: 30rpx;
box-shadow: 0 4rpx 15rpx rgba(0, 0, 0, 0.1);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.card-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.edit-btn, .history-btn {
padding: 10rpx 20rpx;
border: 1rpx solid #3498db;
border-radius: 6rpx;
font-size: 24rpx;
background: transparent;
color: #3498db;
cursor: pointer;
}
.edit-btn:active, .history-btn:active {
background: #3498db;
color: white;
}
/* 信息网格样式 */
.info-grid {
display: grid;
grid-template-columns: 1fr;
gap: 20rpx;
}
.info-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.info-item:last-child {
border-bottom: none;
}
.info-label {
font-size: 28rpx;
color: #666;
}
.info-value {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
/* 统计网格样式 */
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20rpx;
}
.stat-item {
background: #f8f9fa;
padding: 25rpx;
border-radius: 10rpx;
text-align: center;
transition: transform 0.3s ease;
}
.stat-item:active {
transform: translateY(-2rpx);
}
.stat-icon {
font-size: 40rpx;
margin-bottom: 10rpx;
}
.employee-icon {
color: #3498db;
}
.order-icon {
color: #e74c3c;
}
.warehouse-icon {
color: #f39c12;
}
.stat-value {
display: block;
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 5rpx;
}
.stat-label {
font-size: 24rpx;
color: #666;
}
/* 功能按钮区域样式 */
.action-buttons {
display: flex;
flex-direction: column;
gap: 20rpx;
margin-top: 40rpx;
}
.action-btn {
padding: 25rpx;
border: none;
border-radius: 10rpx;
font-size: 30rpx;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
}
.contact-btn {
background: #27ae60;
color: white;
}
.logout-btn {
background: #e74c3c;
color: white;
}
.action-btn:active {
transform: translateY(1rpx);
opacity: 0.9;
}
/* 响应式调整 */
@media (max-width: 750rpx) {
.stats-grid {
grid-template-columns: repeat(2, 1fr);
}
.profile-header {
padding: 30rpx 20rpx;
}
.profile-content {
padding: 20rpx;
}
}

View File

@@ -10,7 +10,7 @@ Page({
filteredWarehouses: [] as WarehouseInfo[],
// 页面状态
currentTab: 'list', // list: 列表页, add: 添加页
currentTab: 'list', // list: 列表页, add: 添加页, edit: 编辑页
loading: false,
// 添加仓库表单数据
@@ -25,6 +25,20 @@ Page({
latitude: 24.880095
},
// 编辑仓库表单数据
editForm: {
id: 0,
name: '',
address: '',
contact: '',
phone: '',
description: '',
capacity: 500,
longitude: 102.833722,
latitude: 24.880095,
status: 'open' as 'open' | 'closed' | 'maintenance'
},
// 错误信息
errorMessage: '',
successMessage: '',
@@ -41,8 +55,10 @@ Page({
},
onShow() {
// 页面显示时刷新数据
this.loadWarehouses();
// 只在页面显示时检查是否需要刷新数据,避免频繁请求
if (this.data.warehouses.length === 0) {
this.loadWarehouses();
}
},
// 加载仓库列表
@@ -145,6 +161,51 @@ Page({
});
},
// 经度输入处理
onLongitudeInput(e: any) {
const value = parseFloat(e.detail.value) || 0;
this.setData({
'addForm.longitude': value
});
},
// 纬度输入处理
onLatitudeInput(e: any) {
const value = parseFloat(e.detail.value) || 0;
this.setData({
'addForm.latitude': value
});
},
// 地图选点功能
pickLocationFromMap() {
console.log('开始地图选点...');
wx.chooseLocation({
success: (res) => {
console.log('地图选点成功:', res);
if (res.longitude && res.latitude) {
console.log('更新表单数据 - 经度:', res.longitude, '纬度:', res.latitude);
this.setData({
'addForm.longitude': res.longitude,
'addForm.latitude': res.latitude
});
console.log('表单数据更新后:', this.data.addForm);
wx.showToast({
title: '位置已选择',
icon: 'success'
});
}
},
fail: (error) => {
console.error('地图选点失败:', error);
wx.showToast({
title: '选点失败,请重试',
icon: 'none'
});
}
});
},
// 验证表单
validateForm(): boolean {
const { name, address, contact, phone } = this.data.addForm;
@@ -237,6 +298,168 @@ Page({
});
},
// 取消编辑
cancelEdit() {
this.setData({
currentTab: 'list',
errorMessage: '',
successMessage: ''
});
},
// 编辑表单输入处理
onEditNameInput(e: any) {
this.setData({
'editForm.name': e.detail.value
});
},
onEditAddressInput(e: any) {
this.setData({
'editForm.address': e.detail.value
});
},
onEditContactInput(e: any) {
this.setData({
'editForm.contact': e.detail.value
});
},
onEditPhoneInput(e: any) {
this.setData({
'editForm.phone': e.detail.value
});
},
onEditDescriptionInput(e: any) {
this.setData({
'editForm.description': e.detail.value
});
},
onEditCapacityInput(e: any) {
this.setData({
'editForm.capacity': parseInt(e.detail.value) || 500
});
},
onEditLongitudeInput(e: any) {
this.setData({
'editForm.longitude': parseFloat(e.detail.value) || 102.833722
});
},
onEditLatitudeInput(e: any) {
this.setData({
'editForm.latitude': parseFloat(e.detail.value) || 24.880095
});
},
onEditStatusChange(e: any) {
this.setData({
'editForm.status': e.detail.value
});
},
// 编辑仓库
editWarehouse(e: any) {
const warehouseId = e.currentTarget.dataset.id;
const warehouse = this.data.warehouses.find(w => w.id === warehouseId);
if (warehouse) {
this.setData({
editForm: {
id: warehouse.id || 0,
name: warehouse.name || '',
address: warehouse.address || '',
contact: warehouse.contact || '',
phone: warehouse.phone || '',
description: warehouse.description || '',
capacity: warehouse.capacity || 500,
longitude: warehouse.longitude || 102.833722,
latitude: warehouse.latitude || 24.880095,
status: warehouse.status || 'open'
},
currentTab: 'edit'
});
}
},
// 提交编辑仓库表单
async submitEditForm() {
this.setData({
errorMessage: '',
successMessage: ''
});
if (!this.validateEditForm()) {
return;
}
this.setData({
loading: true
});
try {
// 使用updateWarehouse更新仓库信息
await warehouseService.updateWarehouse(this.data.editForm.id, this.data.editForm);
this.setData({
loading: false,
successMessage: '仓库更新成功',
currentTab: 'list'
});
// 重新加载仓库列表
this.loadWarehouses();
showToast('仓库更新成功');
} catch (error) {
console.error('更新仓库失败:', error);
this.setData({
loading: false,
errorMessage: '更新仓库失败,请重试'
});
}
},
// 验证编辑表单
validateEditForm(): boolean {
const { name, address, contact, phone } = this.data.editForm;
if (!name.trim()) {
this.setData({
errorMessage: '请输入仓库名称'
});
return false;
}
if (!address.trim()) {
this.setData({
errorMessage: '请输入仓库地址'
});
return false;
}
if (!contact?.trim()) {
this.setData({
errorMessage: '请输入联系人'
});
return false;
}
if (!phone?.trim()) {
this.setData({
errorMessage: '请输入联系电话'
});
return false;
}
return true;
},
// 删除仓库
async deleteWarehouse(e: any) {
const warehouseId = e.currentTarget.dataset.id;

View File

@@ -49,6 +49,13 @@
>
<text>添加仓库</text>
</view>
<view
class="tab-item {{currentTab === 'edit' ? 'active' : ''}}"
data-tab="edit"
bindtap="switchTab"
>
<text>编辑仓库</text>
</view>
</view>
<!-- 仓库列表页面 -->
@@ -86,11 +93,18 @@
</view>
</view>
<view class="warehouse-actions">
<button
class="edit-btn"
data-id="{{item.id}}"
bindtap="editWarehouse"
size="mini"
>编辑</button>
<button
class="delete-btn"
data-id="{{item.id}}"
data-name="{{item.name}}"
bindtap="deleteWarehouse"
size="mini"
>删除</button>
</view>
</view>
@@ -192,6 +206,33 @@
type="number"
/>
</view>
<view class="form-group">
<text class="form-label">坐标位置</text>
<view class="coordinate-inputs">
<view class="coordinate-row">
<text class="coordinate-label">经度:</text>
<input
class="coordinate-input"
placeholder="请输入经度"
bindinput="onLongitudeInput"
value="{{addForm.longitude}}"
type="digit"
/>
</view>
<view class="coordinate-row">
<text class="coordinate-label">纬度:</text>
<input
class="coordinate-input"
placeholder="请输入纬度"
bindinput="onLatitudeInput"
value="{{addForm.latitude}}"
type="digit"
/>
</view>
</view>
<button class="map-pick-btn" bindtap="pickLocationFromMap">地图选点</button>
</view>
</view>
<view class="form-section">
@@ -216,4 +257,127 @@
</view>
</scroll-view>
</view>
<!-- 编辑仓库页面 -->
<view wx:if="{{currentTab === 'edit'}}" class="edit-page">
<scroll-view class="form-container" scroll-y>
<view class="form-section">
<text class="section-title">编辑仓库信息</text>
<view class="form-group">
<text class="form-label">仓库名称 *</text>
<input
class="form-input"
placeholder="请输入仓库名称"
bindinput="onEditNameInput"
value="{{editForm.name}}"
/>
</view>
<view class="form-group">
<text class="form-label">仓库地址 *</text>
<input
class="form-input"
placeholder="请输入仓库地址"
bindinput="onEditAddressInput"
value="{{editForm.address}}"
/>
</view>
<view class="form-group">
<text class="form-label">联系人 *</text>
<input
class="form-input"
placeholder="请输入联系人姓名"
bindinput="onEditContactInput"
value="{{editForm.contact}}"
/>
</view>
<view class="form-group">
<text class="form-label">联系电话 *</text>
<input
class="form-input"
placeholder="请输入联系电话"
bindinput="onEditPhoneInput"
value="{{editForm.phone}}"
type="number"
/>
</view>
<view class="form-group">
<text class="form-label">仓库容量</text>
<input
class="form-input"
placeholder="请输入仓库容量(件数)"
bindinput="onEditCapacityInput"
value="{{editForm.capacity}}"
type="number"
/>
</view>
<view class="form-group">
<text class="form-label">坐标位置</text>
<view class="coordinate-inputs">
<view class="coordinate-row">
<text class="coordinate-label">经度:</text>
<input
class="coordinate-input"
placeholder="请输入经度"
bindinput="onEditLongitudeInput"
value="{{editForm.longitude}}"
type="digit"
/>
</view>
<view class="coordinate-row">
<text class="coordinate-label">纬度:</text>
<input
class="coordinate-input"
placeholder="请输入纬度"
bindinput="onEditLatitudeInput"
value="{{editForm.latitude}}"
type="digit"
/>
</view>
</view>
<button class="map-pick-btn" bindtap="pickLocationFromMap">地图选点</button>
</view>
<view class="form-group">
<text class="form-label">仓库状态</text>
<picker
class="form-picker"
range="{{['营业中', '已关闭', '维护中']}}"
value="{{editForm.status === 'open' ? 0 : editForm.status === 'closed' ? 1 : 2}}"
bindchange="onEditStatusChange"
>
<view class="picker-value">
{{editForm.status === 'open' ? '营业中' : editForm.status === 'closed' ? '已关闭' : '维护中'}}
</view>
</picker>
</view>
</view>
<view class="form-section">
<text class="section-title">其他信息</text>
<view class="form-group">
<text class="form-label">仓库描述</text>
<textarea
class="form-textarea"
placeholder="请输入仓库描述信息(可选)"
bindinput="onEditDescriptionInput"
value="{{editForm.description}}"
maxlength="200"
/>
<text class="textarea-counter">{{editForm.description ? editForm.description.length : 0}}/200</text>
</view>
</view>
<view class="form-actions">
<button class="submit-btn" bindtap="submitEditForm">更新仓库</button>
<button class="cancel-btn" bindtap="cancelEdit">取消</button>
</view>
</scroll-view>
</view>
</view>

View File

@@ -148,39 +148,45 @@
/* 列表页面样式 */
.list-page {
padding: 30rpx;
flex: 1;
display: flex;
flex-direction: column;
}
/* 搜索框 */
.search-container {
margin-bottom: 30rpx;
padding: 30rpx 40rpx;
background: white;
border-bottom: 1rpx solid #eee;
}
.search-input-wrapper {
position: relative;
background: white;
border-radius: 12rpx;
padding: 20rpx 60rpx 20rpx 30rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
}
.search-input {
flex: 1;
padding: 25rpx 60rpx 25rpx 30rpx;
border: 1rpx solid #ddd;
border-radius: 12rpx;
font-size: 28rpx;
color: #333;
background: #f8f9fa;
}
.search-icon {
position: absolute;
right: 30rpx;
top: 50%;
transform: translateY(-50%);
font-size: 28rpx;
color: #999;
}
/* 仓库列表 */
.warehouse-list {
max-height: calc(100vh - 400rpx);
flex: 1;
padding: 0 30rpx;
box-sizing: border-box;
}
.empty-state {
@@ -198,46 +204,99 @@
}
.empty-text {
/* 空文本样式占位 */
}
/* 坐标输入样式 */
.coordinate-inputs {
margin-bottom: 20rpx;
}
.coordinate-row {
display: flex;
align-items: center;
margin-bottom: 15rpx;
}
.coordinate-label {
width: 120rpx;
font-size: 28rpx;
color: #333;
}
.coordinate-input {
flex: 1;
border: 1rpx solid #e8e8e8;
border-radius: 8rpx;
padding: 20rpx;
font-size: 28rpx;
background: white;
}
.map-pick-btn {
background: #667eea;
color: white;
border: none;
border-radius: 8rpx;
padding: 20rpx;
font-size: 28rpx;
text-align: center;
width: 100%;
}
.map-pick-btn:active {
background: #5a6fd8;
}
.map-pick-btn {
font-size: 28rpx;
}
.warehouse-item {
background: white;
padding: 25rpx;
margin: 15rpx 0;
border-radius: 12rpx;
padding: 30rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
box-sizing: border-box;
max-width: 100%;
overflow: hidden;
}
.warehouse-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 20rpx;
margin-bottom: 15rpx;
}
.warehouse-info {
flex: 1;
min-width: 0;
}
.warehouse-name {
font-size: 32rpx;
font-size: 28rpx;
font-weight: 600;
color: #333;
margin-bottom: 10rpx;
margin-bottom: 8rpx;
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.warehouse-status {
display: flex;
gap: 10rpx;
gap: 8rpx;
}
.status-badge {
padding: 6rpx 16rpx;
border-radius: 20rpx;
font-size: 22rpx;
padding: 6rpx 12rpx;
border-radius: 16rpx;
font-size: 20rpx;
font-weight: 500;
flex-shrink: 0;
}
.status-badge.open {
@@ -260,38 +319,43 @@
.warehouse-actions {
display: flex;
gap: 10rpx;
gap: 8rpx;
flex-shrink: 0;
}
.delete-btn {
background: #ff4757;
color: white;
border: none;
padding: 12rpx 20rpx;
border-radius: 8rpx;
font-size: 24rpx;
font-size: 22rpx;
}
/* 仓库详情 */
.warehouse-details {
border-top: 1rpx solid #f0f0f0;
padding-top: 20rpx;
padding-top: 15rpx;
}
.detail-row {
display: flex;
margin-bottom: 12rpx;
font-size: 26rpx;
margin-bottom: 10rpx;
font-size: 24rpx;
}
.detail-label {
color: #666;
min-width: 120rpx;
min-width: 100rpx;
flex-shrink: 0;
}
.detail-value {
color: #333;
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.inventory-status {