注册修改为绑定

This commit is contained in:
2025-10-21 21:51:51 +08:00
parent 5ee4e077fb
commit be2323074b
28 changed files with 729 additions and 211 deletions

View File

@@ -1,5 +1,5 @@
{
"navigationBarTitleText": "申请加入货运团队",
"navigationBarTitleText": "员工账号绑定",
"navigationBarBackgroundColor": "#1aad19",
"navigationBarTextStyle": "white",
"usingComponents": {}

View File

@@ -61,7 +61,7 @@ Page({
if (result.success) {
wx.showToast({
title: '申请提交成功',
title: '绑定成功',
icon: 'success',
duration: 2000
});
@@ -79,13 +79,27 @@ Page({
}
// 延迟返回并刷新首页
setTimeout(() => {
setTimeout(async () => {
// 获取当前页面栈
const pages = getCurrentPages();
if (pages.length >= 2) {
// 获取首页实例并调用刷新方法
const indexPage = pages[pages.length - 2];
if (indexPage && indexPage.refreshPageAfterLogin) {
// 重新获取用户状态,确保绑定成功后状态正确更新
if (indexPage.data.mainPageModule) {
const loginModule = indexPage.data.mainPageModule.getLoginModule();
const app = getApp<any>();
const userStatus = await loginModule.determineUserStatus(app.globalData.userInfo);
// 更新页面状态
indexPage.setData({
'authStatus.userStatus': userStatus
});
console.log('✅ 绑定成功后重新获取用户状态:', userStatus);
}
indexPage.refreshPageAfterLogin();
}
}
@@ -125,16 +139,6 @@ Page({
return false;
}
// 手机号验证
if (!/^1[3-9]\d{9}$/.test(phone)) {
wx.showToast({
title: '请输入正确的手机号',
icon: 'none',
duration: 2000
});
return false;
}
return true;
},
@@ -150,13 +154,13 @@ Page({
throw new Error('微信登录失败,请重试');
}
// 调用实际的注册接口
// 调用实际的绑定接口
return await userService.register({
name: data.name,
phone: data.phone
});
} catch (error) {
console.error('注册流程失败:', error);
console.error('绑定流程失败:', error);
throw error;
}
},

View File

@@ -2,16 +2,16 @@
<view class="apply-container">
<!-- 页面头部 -->
<view class="apply-header">
<text class="apply-title">加入货运团队</text>
<text class="apply-subtitle">请填写您的个人信息</text>
<text class="apply-title">员工账号绑定</text>
<text class="apply-subtitle">请填写您的员工信息</text>
</view>
<!-- 表单内容 -->
<scroll-view class="apply-content" scroll-y>
<view class="apply-form">
<!-- 姓名输入 -->
<!-- 员工姓名输入 -->
<view class="apply-form-group">
<text class="apply-form-label">姓名</text>
<text class="apply-form-label">员工姓名</text>
<input
class="apply-form-input"
type="text"
@@ -27,27 +27,33 @@
<!-- 手机号输入 -->
<!-- 员工工号输入 -->
<view class="apply-form-group">
<text class="apply-form-label">手机号</text>
<text class="apply-form-label">员工工号</text>
<input
class="apply-form-input"
type="number"
value="{{applyForm.phone}}"
data-field="phone"
bindinput="onApplyFormInput"
placeholder="请输入11位手机号码"
placeholder="请输入您的员工工号"
placeholder-class="apply-form-placeholder"
maxlength="11"
maxlength="20"
/>
<view class="apply-form-underline"></view>
</view>
</view>
</scroll-view>
<!-- 提示信息 -->
<view class="apply-tips">
<text class="tips-text">请正确输入自己的姓名和工号,忘记请联系管理员</text>
<text class="tips-warning">未分属于本公司用户请勿绑定(绑定不会保留个人信息)</text>
</view>
<!-- 底部操作按钮 -->
<view class="apply-footer">
<button class="apply-btn-cancel" bindtap="onCancel">取消</button>
<button class="apply-btn-confirm" bindtap="onSubmit" form-type="submit">提交申请</button>
<button class="apply-btn-confirm" bindtap="onSubmit" form-type="submit">绑定账号</button>
</view>
</view>

View File

@@ -84,6 +84,29 @@
opacity: 0.5;
}
/* 提示信息 */
.apply-tips {
padding: 30rpx;
background-color: #f8f9fa;
border-top: 1rpx solid #eee;
border-bottom: 1rpx solid #eee;
}
.tips-text {
display: block;
font-size: 26rpx;
color: #666;
line-height: 1.6;
margin-bottom: 10rpx;
}
.tips-warning {
display: block;
font-size: 24rpx;
color: #ff6b35;
line-height: 1.6;
}
/* 底部操作按钮 */
.apply-footer {
padding: 30rpx;

View File

@@ -126,16 +126,16 @@ Page({
if (!phone.trim()) {
this.setData({
errorMessage: '请输入手机号'
errorMessage: '请输入员工工号'
});
return false;
}
// 简单的手机号格式验证
const phoneRegex = /^1[3-9]\d{9}$/;
// 简单的号格式验证
const phoneRegex = /^\d+$/;
if (!phoneRegex.test(phone)) {
this.setData({
errorMessage: '请输入正确的手机号格式'
errorMessage: '工号只能包含数字'
});
return false;
}

View File

@@ -54,7 +54,7 @@
<view class="search-input-wrapper">
<input
class="search-input"
placeholder="搜索员工姓名、手机号或角色"
placeholder="搜索员工姓名、号或角色"
bindinput="onSearchInput"
value="{{searchKeyword}}"
/>
@@ -70,16 +70,16 @@
<text class="avatar-text">{{item.name.charAt(0)}}</text>
</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-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>
<text class="employee-phone">工号: {{item.phone}}</text>
<text class="employee-id">ID: {{item.id}}</text>
</view>
<text class="employee-phone">{{item.phone}}</text>
<text class="employee-id">ID: {{item.id}}</text>
</view>
</view>
<view class="employee-actions">
<button
@@ -119,10 +119,10 @@
</view>
<view class="form-item">
<text class="form-label">手机号码</text>
<text class="form-label">员工工号</text>
<input
class="form-input"
placeholder="请输入手机号码"
placeholder="请输入员工工号"
type="number"
value="{{addForm.phone}}"
bindinput="onFormInput"
@@ -150,7 +150,7 @@
<view class="form-hint">
<text class="hint-text">
提示:添加员工后,用户可以使用该员工的姓名和手机号进行注册
提示:添加员工后,用户可以使用该员工的姓名和号进行绑定
</text>
</view>

View File

@@ -368,7 +368,16 @@ Component<IndexPageComponent['data'], any, any, any, false>({
}
},
// 显示申请加入货运人员表单 - 跳转到独立页面
// 处理绑定按钮点击
handleRegister() {
console.log('用户点击绑定按钮');
// 跳转到绑定页面
wx.navigateTo({
url: '/pages/apply/apply'
});
},
// 显示员工账号绑定表单 - 跳转到独立页面
showApplyForm() {
wx.navigateTo({
url: '/pages/apply/apply'

View File

@@ -18,6 +18,18 @@
<view class="right-controls-container">
<!-- 签到/签退按钮 -->
<view class="auth-buttons">
<!-- 绑定按钮 - 未绑定用户 -->
<button
wx:if="{{showRegisterButton}}"
class="control-btn register-btn"
bindtap="handleRegister"
type="primary"
size="mini"
>
<text class="btn-icon">📝</text>
<text class="btn-text">绑定</text>
</button>
<!-- 签到按钮 - 已授权用户 -->
<button
wx:if="{{showSignInButton}}"
@@ -82,7 +94,7 @@
<view class="user-info">
<text class="user-name">{{userInfo.name || '未设置姓名'}}</text>
<text class="user-id">ID: {{userInfo.id || '未获取'}}</text>
<text class="user-phone">电话{{userInfo.phone || '未设置'}}</text>
<text class="user-phone">工号{{userInfo.phone || '未设置'}}</text>
<text class="user-role">角色:{{userInfo.role === 'ADMIN' ? '管理员' : '货运员'}}</text>
</view>
</view>
@@ -228,7 +240,7 @@
</view>
<view class="person-info-header">
<view class="modal-title">{{currentDeliveryPerson.name}}</view>
<view class="modal-subtitle">电话{{currentDeliveryPerson.phone}}</view>
<view class="modal-subtitle">工号{{currentDeliveryPerson.phone}}</view>
</view>
</view>
</view>
@@ -236,7 +248,7 @@
<!-- 基础信息区 - 始终可见 -->
<view class="modal-basic-info">
<view class="detail-item">
<text class="detail-label">电话</text>
<text class="detail-label">工号</text>
<text class="detail-value">{{currentDeliveryPerson.phone}}</text>
</view>
<view class="detail-item">

View File

@@ -0,0 +1,72 @@
// 管理员模块 - 专门处理管理员相关功能
import { showToast } from '../../utils/helpers';
import { DataModule } from './dataModule';
export class AdminModule {
private pageContext: any;
private dataModule: DataModule;
constructor(pageContext: any, dataModule: DataModule) {
this.pageContext = pageContext;
this.dataModule = dataModule;
}
/**
* 处理管理员标记点点击
*/
onAdminMarkerClick(admin: any, position: { x: number, y: number }): void {
console.log('管理员被点击:', admin);
// 显示管理员详情面板
this.showAdminPanel(admin, position);
}
/**
* 显示管理员详情面板
*/
private showAdminPanel(admin: any, position: { x: number, y: number }): void {
console.log('显示管理员详情面板:', admin);
// 设置当前管理员
this.dataModule.setCurrentDeliveryPerson(admin);
// 显示面板
this.dataModule.toggleDeliveryPersonModal(true, 'bottom');
}
/**
* 隐藏管理员详情面板
*/
hideAdminPanel(): void {
this.dataModule.toggleDeliveryPersonModal(false);
this.dataModule.setCurrentDeliveryPerson(null);
}
/**
* 展开管理员详情面板
*/
expandAdminPanel(): void {
this.dataModule.toggleDeliveryPersonModal(true, 'full');
}
/**
* 收起管理员详情面板
*/
collapseAdminPanel(): void {
this.dataModule.toggleDeliveryPersonModal(true, 'bottom');
}
/**
* 获取管理员信息摘要
*/
getAdminSummary(admin: any): string {
return `${admin.name || '管理员'} - ${admin.role || 'ADMIN'}`;
}
/**
* 清理资源
*/
cleanup(): void {
console.log('清理管理员模块资源');
}
}

View File

@@ -118,54 +118,6 @@ export class DataModule {
latitude,
longitude
});
// 同时更新地图上的用户标记点
this.updateUserMarkerPosition(longitude, latitude);
}
/**
* 更新用户标记点位置
*/
public updateUserMarkerPosition(longitude: number, latitude: number, userId?: number): void {
const { markers } = this.pageContext.data;
// 如果没有指定用户ID默认使用-1当前用户
const targetUserId = userId !== undefined ? userId : -1;
const markerTitle = targetUserId === -1 ? '用户位置' : `用户${targetUserId}`;
// 查找用户标记点
const userMarkerIndex = markers.findIndex((marker: any) => marker.id === targetUserId);
if (userMarkerIndex !== -1) {
// 更新用户标记点位置
const updatedMarkers = [...markers];
updatedMarkers[userMarkerIndex] = {
...updatedMarkers[userMarkerIndex],
latitude,
longitude
};
this.updateMarkers(updatedMarkers);
} else {
// 创建新的用户标记点
const userInfo = this.pageContext.data.userInfo;
const userRole = userInfo?.role || 'employee';
const iconPath = userRole === 'ADMIN' ? '/images/crown.png' : '/images/truck.png';
const newUserMarker = {
id: targetUserId,
title: markerTitle,
longitude: longitude,
latitude: latitude,
iconPath: iconPath,
width: 40,
height: 40,
zIndex: targetUserId === -1 ? 99 : 98 // 当前用户层级更高
};
const updatedMarkers = [...markers, newUserMarker];
this.updateMarkers(updatedMarkers);
}
}
/**

View File

@@ -1,12 +1,8 @@
// 员模块 - 处理所有员工(管理员和货运人员)管理、位置跟踪、交互
import employeeService from '../../../services/employeeService';
// getApp是微信小程序全局函数无需导入
import { showToast } from '../../../utils/helpers';
// 货运人员模块 - 专门处理货运人员相关功能
import { showToast } from '../../utils/helpers';
import { DataModule } from './dataModule';
export class EmployeeModule {
export class DeliveryPersonModule {
private pageContext: any;
private dataModule: DataModule;
@@ -16,31 +12,25 @@ export class EmployeeModule {
}
/**
* 加载所有员工数据(包括管理员和货运人员)
* 处理货运人员标记点点击
*/
async loadAllEmployees(): Promise<void> {
try {
// 获取所有员工数据
const allEmployees = await employeeService.getEmployees();
console.log('所有员工数据加载完成,数量:', allEmployees.length);
} catch (error) {
console.error('加载员工数据失败:', error);
showToast('加载员工数据失败');
}
onDeliveryPersonMarkerClick(deliveryPerson: any, position: { x: number, y: number }): void {
console.log('货运人员被点击:', deliveryPerson);
// 显示货运人员详情面板(包含订单列表)
this.showDeliveryPersonPanel(deliveryPerson, position);
}
/**
* 显示货运人员详情面板
*/
showDeliveryPersonPanel(person: any, position: { x: number, y: number }): void {
// 关闭其他面板
this.pageContext.hideAllPanels();
private showDeliveryPersonPanel(deliveryPerson: any, position: { x: number, y: number }): void {
console.log('显示货运人员详情面板:', deliveryPerson);
this.dataModule.setCurrentDeliveryPerson(person);
this.dataModule.setPanelPosition(position);
// 设置当前货运人员
this.dataModule.setCurrentDeliveryPerson(deliveryPerson);
// 显示面板
this.dataModule.toggleDeliveryPersonModal(true, 'bottom');
}
@@ -67,13 +57,10 @@ export class EmployeeModule {
}
/**
* 处理货运人员标记点点击
* 获取货运人员信息摘要
*/
onDeliveryPersonMarkerClick(person: any, position: { x: number, y: number }): void {
console.log('货运人员被点击:', person);
// 显示货运人员详情面板
this.showDeliveryPersonPanel(person, position);
getDeliveryPersonSummary(deliveryPerson: any): string {
return `${deliveryPerson.name || '货运人员'} - ${deliveryPerson.role || 'DRIVER'}`;
}
/**
@@ -129,4 +116,11 @@ export class EmployeeModule {
};
return statusMap[status] || status;
}
/**
* 清理资源
*/
cleanup(): void {
console.log('清理货运人员模块资源');
}
}

View File

@@ -0,0 +1,92 @@
// 员工模块 - 处理所有员工(管理员和货运人员)的通用功能
import { showToast } from '../../../utils/helpers';
import { DataModule } from './dataModule';
import employeeService from '../../../services/employeeService';
export class EmployeeModule {
private pageContext: any;
private dataModule: DataModule;
constructor(pageContext: any, dataModule: DataModule) {
this.pageContext = pageContext;
this.dataModule = dataModule;
}
/**
* 处理员工标记点点击 - 通用处理逻辑
*/
onEmployeeMarkerClick(employee: any, position: { x: number, y: number }): void {
console.log('员工被点击:', employee);
// 设置当前员工
this.dataModule.setCurrentDeliveryPerson(employee);
// 显示面板
this.dataModule.toggleDeliveryPersonModal(true, 'bottom');
}
/**
* 隐藏员工详情面板
*/
hideEmployeePanel(): void {
this.dataModule.toggleDeliveryPersonModal(false);
this.dataModule.setCurrentDeliveryPerson(null);
}
/**
* 展开员工详情面板
*/
expandEmployeePanel(): void {
this.dataModule.toggleDeliveryPersonModal(true, 'full');
}
/**
* 收起员工详情面板
*/
collapseEmployeePanel(): void {
this.dataModule.toggleDeliveryPersonModal(true, 'bottom');
}
/**
* 获取员工信息摘要
*/
getEmployeeSummary(employee: any): string {
return `${employee.name || '员工'} - ${employee.role || '未知角色'}`;
}
/**
* 获取员工状态文本
*/
getEmployeeStatusText(status: string): string {
const statusMap: Record<string, string> = {
'idle': '空闲',
'busy': '忙碌',
'offline': '离线'
};
return statusMap[status] || status;
}
/**
* 加载所有员工数据
*/
async loadAllEmployees(): Promise<void> {
try {
console.log('开始加载所有员工数据');
const employees = await employeeService.getEmployees();
console.log('员工数据加载完成:', employees);
// 这里可以添加员工数据处理逻辑比如更新到dataModule
// this.dataModule.updateEmployees(employees);
} catch (error) {
console.error('加载员工数据失败:', error);
throw error; // 重新抛出错误,让调用方处理
}
}
/**
* 清理资源
*/
cleanup(): void {
console.log('清理员工模块资源');
}
}

View File

@@ -281,7 +281,7 @@ export class LocationModule {
} else if (userRole === 'DRIVER') {
return '/images/truck.png'; // 司机图标
} else {
return '👤'; // 普通员工图标(表情符号)
return '/images/truck.png'; // 普通员工也使用货运图标
}
}
}

View File

@@ -99,7 +99,7 @@ export class LoginModule {
/**
* 执行登录流程 - 调用userService的登录方法
* 静默登录失败后,只专注于登录本身,不涉及注册、签到等复杂逻辑
* 静默登录失败后,只专注于登录本身,不涉及绑定、签到等复杂逻辑
*/
private async performLogin(): Promise<boolean> {
try {
@@ -322,6 +322,34 @@ export class LoginModule {
console.warn('启动位置追踪失败,但不影响签到:', trackingError);
}
// 加载业务数据(所有登录用户)
try {
console.log('用户签到成功,开始加载业务数据');
// 获取主页面模块并加载业务数据
const mainPageModule = this.pageContext.data.mainPageModule;
if (mainPageModule && mainPageModule.loadBusinessData) {
await mainPageModule.loadBusinessData();
console.log('业务数据加载完成');
}
} catch (businessError) {
console.warn('加载业务数据失败,但不影响签到:', businessError);
}
// 如果是管理员用户,加载员工数据
if (signInResult.employeeInfo && signInResult.employeeInfo.role === 'ADMIN') {
try {
console.log('管理员用户签到成功,开始加载员工数据');
// 获取主页面模块并加载员工数据
const mainPageModule = this.pageContext.data.mainPageModule;
if (mainPageModule && mainPageModule.loadEmployeeData) {
await mainPageModule.loadEmployeeData();
console.log('员工数据加载完成');
}
} catch (employeeError) {
console.warn('加载员工数据失败,但不影响签到:', employeeError);
}
}
return true;
} else {
console.warn('签到失败:', signInResult.message);
@@ -386,7 +414,7 @@ export class LoginModule {
const authStatus = pageData.authStatus || {};
const userInfo = pageData.userInfo;
// 显示条件已获取微信code、用户状态不是已签到、且用户不是游客注册用户)
// 显示条件已获取微信code、用户状态不是已签到、且用户不是游客绑定用户)
const result = (
authStatus.hasWxCode &&
(authStatus.userStatus === 'registered' || authStatus.userStatus === 'signed_out') &&
@@ -406,7 +434,7 @@ export class LoginModule {
const authStatus = pageData.authStatus || {};
const userInfo = pageData.userInfo;
// 显示条件已获取微信code、用户状态为未注册、且用户是游客
// 显示条件已获取微信code、用户状态为未绑定、且用户是游客
const result = (
authStatus.hasWxCode &&
authStatus.userStatus === 'unregistered' &&

View File

@@ -3,7 +3,9 @@ import { LoginModule } from './loginModule';
import { MapModule } from './mapModule';
import { OrderModule } from './orderModule';
import { WarehouseModule } from './warehouseModule';
import { EmployeeModule } from './deliveryPersonModule';
import { EmployeeModule } from './employeeModule';
import { AdminModule } from './adminModule';
import { DeliveryPersonModule } from './deliveryPersonModule';
import { LocationModule } from './locationModule';
import { DataModule } from './dataModule';
import { showToast } from '../../../utils/helpers';
@@ -29,6 +31,8 @@ export class MainPageModule {
private orderModule: OrderModule;
private warehouseModule: WarehouseModule;
private employeeModule: EmployeeModule;
private adminModule: AdminModule;
private deliveryPersonModule: DeliveryPersonModule;
private locationModule: LocationModule;
constructor(pageContext: any) {
@@ -40,7 +44,9 @@ export class MainPageModule {
this.mapModule = new MapModule(pageContext, this.dataModule);
this.orderModule = new OrderModule(pageContext, this.dataModule);
this.warehouseModule = new WarehouseModule(pageContext, this.dataModule);
this.employeeModule = new EmployeeModule(pageContext, this.dataModule);
this.employeeModule = new EmployeeModule(this.pageContext, this.dataModule);
this.adminModule = new AdminModule(this.pageContext, this.dataModule);
this.deliveryPersonModule = new DeliveryPersonModule(this.pageContext, this.dataModule);
this.locationModule = new LocationModule(pageContext, this.dataModule);
}
@@ -107,13 +113,8 @@ export class MainPageModule {
// 加载公开数据(不需要登录)
await this.loadPublicData();
// 检查是否已登录,只有已登录用户才能加载业务数据
const app = getApp<any>();
if (app.globalData.isLoggedIn) {
await this.loadBusinessData();
} else {
console.log('用户未登录,不加载业务数据');
}
// 业务数据(订单和员工数据)在用户签到后单独加载
console.log('公开数据加载完成,业务数据将在用户签到后加载');
} catch (error) {
console.error('加载数据失败:', error);
@@ -139,22 +140,44 @@ export class MainPageModule {
}
/**
* 加载业务数据
* 加载业务数据(仅在用户签到后调用)
*/
private async loadBusinessData(): Promise<void> {
public async loadBusinessData(): Promise<void> {
console.log('加载业务数据');
try {
// 并行加载各种业务数据(需要登录
await Promise.all([
this.orderModule.loadPendingOrders(),
this.employeeModule.loadAllEmployees()
]);
// 加载待处理订单(所有登录用户都可以看到
await this.orderModule.loadPendingOrders();
console.log('所有业务数据加载完成');
console.log('业务数据加载完成');
} catch (error) {
console.error('加载业务数据失败:', error);
showToast('业务数据加载失败');
throw error; // 重新抛出错误,让调用方处理
}
}
/**
* 加载员工数据(仅在管理员签到后调用)
*/
public async loadEmployeeData(): Promise<void> {
console.log('加载员工数据');
try {
// 获取用户信息
const app = getApp<any>();
const userInfo = app.globalData.userInfo;
// 只有管理员才加载员工列表
if (userInfo && userInfo.role === 'ADMIN') {
console.log('管理员用户,加载员工列表');
await this.employeeModule.loadAllEmployees();
console.log('员工数据加载完成');
} else {
console.log('非管理员用户,跳过员工列表加载');
}
} catch (error) {
console.error('加载员工数据失败:', error);
throw error; // 重新抛出错误,让调用方处理
}
}
@@ -260,9 +283,16 @@ export class MainPageModule {
case 'warehouse':
this.warehouseModule.onWarehouseMarkerClick(marker.data, e);
break;
case 'delivery_person':
this.employeeModule.onDeliveryPersonMarkerClick(marker.data, e);
break;
case 'employee':
// 员工标记点点击 - 根据角色分发到不同模块
if (marker.data.role === 'ADMIN') {
// 管理员 - 由adminModule处理
this.adminModule.onAdminMarkerClick(marker.data, e);
} else {
// 货运人员 - 由deliveryPersonModule处理包含订单列表
this.deliveryPersonModule.onDeliveryPersonMarkerClick(marker.data, e);
}
break;
default:
this.mapModule.onMarkerTap(e);
break;
@@ -304,6 +334,13 @@ export class MainPageModule {
return this.employeeModule;
}
/**
* 获取管理员模块
*/
getAdminModule(): AdminModule {
return this.adminModule;
}
/**
* 获取位置模块
*/
@@ -345,6 +382,10 @@ export class MainPageModule {
// 清理位置模块
this.locationModule.cleanup();
// 清理员工和管理员模块
this.employeeModule.cleanup();
this.adminModule.cleanup();
// 这里可以添加其他需要清理的资源
console.log('✅ 主页面模块清理完成');
}

View File

@@ -1,5 +1,6 @@
// 管理员界面 - 全屏管理面板
import { UserInfo } from '../../types';
import userService from '../../services/userService';
Page({
data: {
@@ -183,5 +184,70 @@ Page({
this.setData({
currentTime: timeString
});
},
/**
* 解绑微信处理
*/
async onUnbindWechat() {
try {
// 确认对话框
wx.showModal({
title: '确认解绑',
content: '解绑微信后,您将需要重新登录并绑定账号。确定要继续吗?',
confirmText: '确定解绑',
confirmColor: '#e74c3c',
cancelText: '取消',
success: async (res) => {
if (res.confirm) {
// 显示加载中
wx.showLoading({
title: '解绑中...',
mask: true
});
try {
// 调用解绑服务
const result = await userService.unbindWechat();
wx.hideLoading();
if (result.success) {
wx.showToast({
title: '解绑成功',
icon: 'success',
duration: 2000
});
// 延迟跳转到登录页面
setTimeout(() => {
wx.reLaunch({
url: '/pages/login/login'
});
}, 2000);
} else {
wx.showToast({
title: result.message || '解绑失败',
icon: 'none'
});
}
} catch (error) {
wx.hideLoading();
wx.showToast({
title: '解绑失败,请重试',
icon: 'none'
});
console.error('解绑微信错误:', error);
}
}
}
});
} catch (error) {
console.error('解绑微信处理错误:', error);
wx.showToast({
title: '操作失败,请重试',
icon: 'none'
});
}
}
});

View File

@@ -62,5 +62,6 @@
<view class="admin-footer">
<text class="footer-text">管理员系统 v1.0</text>
<text class="footer-time">{{currentTime}}</text>
<button class="unbind-btn" bindtap="onUnbindWechat">解绑微信</button>
</view>
</view>

View File

@@ -5,16 +5,21 @@
display: flex;
flex-direction: column;
padding: 0;
/* 安全区域适配 - 为整个容器添加顶部安全区域 */
padding-top: env(safe-area-inset-top);
box-sizing: border-box;
}
/* 顶部导航栏样式 */
.admin-header {
background: rgba(255, 255, 255, 0.95);
padding: 30rpx 40rpx;
padding: 40rpx 40rpx 30rpx 40rpx;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
/* 移除margin-top使用容器的padding-top来处理安全区域 */
min-height: 140rpx;
}
.header-left {
@@ -259,4 +264,21 @@
.footer-time {
font-size: 22rpx;
color: #999;
}
/* 解绑微信按钮样式 */
.unbind-btn {
background: #e74c3c;
color: white;
border: none;
border-radius: 8rpx;
padding: 12rpx 20rpx;
font-size: 24rpx;
cursor: pointer;
transition: all 0.3s ease;
}
.unbind-btn:active {
background: #c0392b;
transform: translateY(1rpx);
}

View File

@@ -1,5 +1,6 @@
// 员工界面 - 全屏工作面板
import { UserInfo } from '../../types';
import userService from '../../services/userService';
Page({
data: {
@@ -156,5 +157,70 @@ Page({
wx.makePhoneCall({
phoneNumber: '400-123-4567'
});
},
/**
* 解绑微信处理
*/
async onUnbindWechat() {
try {
// 确认对话框
wx.showModal({
title: '确认解绑',
content: '解绑微信后,您将需要重新登录并绑定账号。确定要继续吗?',
confirmText: '确定解绑',
confirmColor: '#e74c3c',
cancelText: '取消',
success: async (res) => {
if (res.confirm) {
// 显示加载中
wx.showLoading({
title: '解绑中...',
mask: true
});
try {
// 调用解绑服务
const result = await userService.unbindWechat();
wx.hideLoading();
if (result.success) {
wx.showToast({
title: '解绑成功',
icon: 'success',
duration: 2000
});
// 延迟跳转到登录页面
setTimeout(() => {
wx.reLaunch({
url: '/pages/login/login'
});
}, 2000);
} else {
wx.showToast({
title: result.message || '解绑失败',
icon: 'none'
});
}
} catch (error) {
wx.hideLoading();
wx.showToast({
title: '解绑失败,请重试',
icon: 'none'
});
console.error('解绑微信错误:', error);
}
}
}
});
} catch (error) {
console.error('解绑微信处理错误:', error);
wx.showToast({
title: '操作失败,请重试',
icon: 'none'
});
}
}
});

View File

@@ -81,5 +81,6 @@
<view class="employee-footer">
<text class="footer-text">员工工作系统 v1.0</text>
<text class="footer-time">{{currentTime}}</text>
<button class="unbind-btn" bindtap="onUnbindWechat">解绑微信</button>
</view>
</view>

View File

@@ -5,16 +5,21 @@
display: flex;
flex-direction: column;
padding: 0;
/* 安全区域适配 - 为整个容器添加顶部安全区域 */
padding-top: env(safe-area-inset-top);
box-sizing: border-box;
}
/* 顶部导航栏样式 */
.employee-header {
background: rgba(255, 255, 255, 0.95);
padding: 30rpx 40rpx;
padding: 40rpx 40rpx 30rpx 40rpx;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
/* 移除margin-top使用容器的padding-top来处理安全区域 */
min-height: 140rpx;
}
.header-left {
@@ -320,4 +325,21 @@
.footer-time {
font-size: 22rpx;
color: #999;
}
/* 解绑微信按钮样式 */
.unbind-btn {
background: #e74c3c;
color: white;
border: none;
border-radius: 8rpx;
padding: 12rpx 20rpx;
font-size: 24rpx;
cursor: pointer;
transition: all 0.3s ease;
}
.unbind-btn:active {
background: #c0392b;
transform: translateY(1rpx);
}

View File

@@ -148,16 +148,16 @@ Page({
if (!phone.trim()) {
this.setData({
errorMessage: '请输入手机号'
errorMessage: '请输入员工工号'
});
return false;
}
// 简单的手机号格式验证
const phoneRegex = /^1[3-9]\d{9}$/;
// 简单的号格式验证
const phoneRegex = /^\d+$/;
if (!phoneRegex.test(phone)) {
this.setData({
errorMessage: '请输入正确的手机号格式'
errorMessage: '工号只能包含数字'
});
return false;
}

View File

@@ -57,7 +57,7 @@
<view class="search-input-wrapper">
<input
class="search-input"
placeholder="搜索员工姓名、手机号或角色"
placeholder="搜索员工姓名、号或角色"
bindinput="onSearchInput"
value="{{searchKeyword}}"
/>
@@ -80,7 +80,7 @@
{{getRoleText(item.role)}}
</text>
</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>
@@ -122,10 +122,10 @@
</view>
<view class="form-item">
<text class="form-label">手机号码</text>
<text class="form-label">员工工号</text>
<input
class="form-input"
placeholder="请输入手机号码"
placeholder="请输入员工工号"
type="number"
value="{{addForm.phone}}"
bindinput="onFormInput"
@@ -152,7 +152,7 @@
<view class="form-hint">
<text class="hint-text">
提示:添加员工后,用户可以使用该员工的姓名和手机号进行注册
提示:添加员工后,用户可以使用该员工的姓名和号进行绑定
</text>
</view>

View File

@@ -95,8 +95,10 @@ class ApiService {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data);
} else {
console.error(`API Error: HTTP ${res.statusCode}: ${res.errMsg}`);
reject(new Error(`HTTP ${res.statusCode}: ${res.errMsg}`));
// 优先使用服务器返回的具体错误信息,如果没有则使用默认错误信息
const errorMessage = res.data || res.errMsg || '请求失败';
console.error(`API Error: HTTP ${res.statusCode}: ${errorMessage}`);
reject(new Error(`HTTP ${res.statusCode}: ${errorMessage}`));
}
},
fail: (err: any) => {
@@ -163,29 +165,58 @@ async ServerLogin(code: string) {
}
/**
* 注册接口
* @param userInfo 注册用户信息
* @returns 注册结果和员工信息
* 绑定接口
* @param userInfo 绑定用户信息
* @returns 绑定结果和员工信息
*/
async userRegister(userInfo: { name: string; phone: string }): Promise<{ success: boolean; employeeInfo: EmployeeInfo; message?: string }> {
console.log('API userRegister调用参数userInfo:', userInfo);
// 服务器现在返回统一的DTO格式{ success: boolean, userInfo: UserInfoResponse }
// 服务器返回直接的用户信息格式:{id, name, phone, role, openid}
const response = await this.request<any>('/user/register', {
method: 'POST',
data: userInfo,
});
return {
success: response.success,
employeeInfo: {
id: response.userInfo.id,
name: response.userInfo.name || userInfo.name, // 如果服务器返回null使用用户输入的值
phone: response.userInfo.phone || userInfo.phone, // 如果服务器返回null使用用户输入的值
role: response.userInfo.role || 'DELIVERY_PERSON'
},
message: response.message
};
// 检查响应格式,兼容不同的返回格式
if (response.id) {
// 直接返回用户信息格式
return {
success: true,
employeeInfo: {
id: response.id,
name: response.name || userInfo.name,
phone: response.phone || userInfo.phone,
role: response.role || 'DELIVERY_PERSON'
},
message: '绑定成功'
};
} else if (response.userInfo && response.userInfo.id) {
// 包装格式:{success, userInfo, message}
return {
success: response.success !== false,
employeeInfo: {
id: response.userInfo.id,
name: response.userInfo.name || userInfo.name,
phone: response.userInfo.phone || userInfo.phone,
role: response.userInfo.role || 'DELIVERY_PERSON'
},
message: response.message
};
} else {
// 未知格式,返回错误
console.error('未知的绑定响应格式:', response);
return {
success: false,
employeeInfo: {
id: 0,
name: userInfo.name,
phone: userInfo.phone,
role: 'DELIVERY_PERSON'
},
message: '绑定响应格式错误'
};
}
}
@@ -197,6 +228,25 @@ async ServerLogin(code: string) {
return await this.request('/user/logout', { method: 'POST' });
}
/**
* 解绑微信接口
* 清除当前用户的openid绑定允许重新注册其他账号
* @returns 解绑结果
*/
async unbindWechat(): Promise<{ success: boolean; message?: string }> {
console.log('API unbindWechat调用');
const response = await this.request<any>('/user/unbind', {
method: 'POST',
data: {}
});
return {
success: response.success,
message: response.message
};
}
/**
* 签退接口
* @param userId 用户ID

View File

@@ -77,8 +77,8 @@ class EmployeeService {
}
/**
* 根据手机号查找员工
* @param phone 手机
* 根据号查找员工
* @param phone
* @returns 员工信息或null
*/
async findEmployeeByPhone(phone: string): Promise<EmployeeInfo | null> {
@@ -87,9 +87,9 @@ class EmployeeService {
}
/**
* 验证员工信息(用于注册时检查)
* @param name 姓名
* @param phone 手机
* 验证员工信息(用于绑定时检查)
* @param name 姓名
* @param phone
* @returns 验证结果
*/
async validateEmployee(name: string, phone: string): Promise<{ success: boolean; message?: string; employee?: EmployeeInfo }> {

View File

@@ -423,17 +423,40 @@ class LocationTrackingService {
const formattedUsers = message.users.map((user: any) => {
// 支持多种数据格式locationData字段或直接字段
const locationData = user.locationData || user;
return {
// 验证必需字段是否存在
if (!user.userId && !locationData.userId) {
console.error('❌ 用户数据缺少userId字段:', user);
return null;
}
if (locationData.latitude === undefined || locationData.longitude === undefined) {
console.error('❌ 用户数据缺少位置信息:', user);
return null;
}
// 对于位置更新消息允许缺少name和role字段从本地缓存中获取
const existingUser = this.onlineUsers.get(user.userId || locationData.userId);
const formattedUser = {
userId: user.userId || locationData.userId,
name: user.name || user.userName || `用户${user.userId || locationData.userId}`,
role: user.role || 'employee',
name: user.name || user.userName || (existingUser ? existingUser.name : `用户${user.userId || locationData.userId}`),
role: user.role || (existingUser ? existingUser.role : 'DRIVER'),
userStatus: user.userStatus !== false, // 转换为布尔值
lastUpdateTime: user.lastUpdateTime || locationData.timestamp || Date.now(),
latitude: locationData.latitude,
longitude: locationData.longitude,
timestamp: locationData.timestamp || user.timestamp || Date.now()
};
});
// 验证必需字段
if (!formattedUser.userId) {
console.error('❌ 用户数据缺少userId字段:', formattedUser);
return null;
}
return formattedUser;
}).filter(user => user !== null); // 过滤掉无效数据
console.log('📊 转换后的用户位置数据:', formattedUsers);
@@ -500,12 +523,15 @@ class LocationTrackingService {
const longitude = user.longitude;
const timestamp = user.timestamp || user.lastUpdateTime || Date.now();
// 对于位置更新消息允许缺少name和role字段从本地缓存中获取
const existingUser = this.onlineUsers.get(user.userId);
// 更新或添加用户信息
this.onlineUsers.set(user.userId, {
userId: user.userId,
name: user.name || user.userName || `用户${user.userId}`,
name: user.name || user.userName || (existingUser ? existingUser.name : `用户${user.userId}`),
avatarUrl: '/images/user-avatar.png',
role: user.role || 'employee',
role: user.role || (existingUser ? existingUser.role : 'DRIVER'),
lastLocation: {
userId: user.userId,
longitude: longitude,

View File

@@ -64,26 +64,12 @@ class MapService {
clearTimeout(timeout);
console.error('高德地图SDK定位失败:', err);
// 如果高德SDK失败,尝试使用微信原生API
console.log('尝试使用微信原生getLocation API...');
wx.getLocation({
type: 'gcj02',
success: (wxRes) => {
console.log('微信原生API定位成功:', wxRes);
resolve({
longitude: wxRes.longitude,
latitude: wxRes.latitude
});
},
fail: (wxErr) => {
console.error('微信原生API定位失败:', wxErr);
// 所有方法都失败,使用模拟位置
console.log('所有定位方法失败,使用模拟位置');
resolve({
longitude: 102.7123,
latitude: 25.0409
});
}
// 注释:高德SDK失败后,直接使用模拟位置,不调用微信原生API
// 原因:微信小程序可能没有位置权限,避免权限错误
console.log('高德地图SDK定位失败使用模拟位置');
resolve({
longitude: 102.7123,
latitude: 25.0409
});
}
}, (locationString: string) => {

View File

@@ -113,7 +113,7 @@ class UserService {
}
/**
* 执行静默登录流程:微信登录->个人服务器登录->进入基础界面->签到/注册
* 执行静默登录流程:微信登录->个人服务器登录->进入基础界面->签到/绑定
* @returns 登录结果
*/
async wxLogin(): Promise<{
@@ -293,14 +293,59 @@ class UserService {
}
/**
* 用户注册
* @param registerInfo 注册信息
* @returns 注册结果和员工信息
* 用户绑定
* @param registerInfo 绑定信息
* @returns 绑定结果和员工信息
*/
async register(registerInfo: { name: string; phone: string }): Promise<{ success: boolean; employeeInfo: EmployeeInfo; message?: string }> {
return apiService.userRegister(registerInfo);
}
/**
* 解绑微信
* 清除当前用户的openid绑定允许重新注册其他账号
* @returns 解绑结果
*/
async unbindWechat(): Promise<{ success: boolean; message?: string }> {
try {
console.log('开始解绑微信流程');
// 调用API解绑
const result = await apiService.unbindWechat();
if (result.success) {
console.log('微信解绑成功');
// 清除本地存储的登录信息
wx.removeStorageSync('userInfo');
wx.removeStorageSync('token');
wx.removeStorageSync('openid');
wx.removeStorageSync('session_key');
// 清除全局数据
const app = getApp<any>();
app.globalData.userInfo = null;
app.globalData.token = null;
app.globalData.openid = null;
app.globalData.isLoggedIn = false;
console.log('本地登录信息已清除');
// 解绑成功后跳转到主界面
setTimeout(() => {
wx.reLaunch({
url: '/pages/index/index'
});
}, 500);
}
return result;
} catch (error) {
console.error('解绑微信失败:', error);
return { success: false, message: '解绑微信失败,请重试' };
}
}
/**
* 获取用户权限列表
* @returns 权限列表