Files
WXProgram/miniprogram/pages/staff/employee-management.ts
2025-10-26 13:15:04 +08:00

635 lines
14 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 员工管理页面 - 集成到管理员界面
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: {
// 员工列表
employees: [] as EmployeeInfo[],
filteredEmployees: [] as EmployeeInfo[],
// 页面状态
currentTab: 'list', // list: 列表页, add: 添加页, edit: 编辑页
loading: false,
// 添加员工表单数据
addForm: {
name: '',
phone: '',
role: Role.DELIVERY_PERSON
},
// 编辑员工表单数据
editForm: {
id: 0,
name: '',
phone: '',
role: Role.DELIVERY_PERSON,
avatarUrl: ''
},
// 错误信息
errorMessage: '',
successMessage: '',
// 搜索关键词
searchKeyword: '',
// 角色选项
roleOptions: getRoleOptions(),
// 用户信息
userInfo: null as any,
// 临时头像路径(用于头像上传)
tempAvatarPath: ''
},
onLoad() {
this.getUserInfo();
this.loadEmployees();
},
onShow() {
// 只在页面显示时检查是否需要刷新数据,避免频繁请求
if (this.data.employees.length === 0) {
this.loadEmployees();
}
},
/**
* 获取用户信息
*/
getUserInfo() {
const app = getApp<any>();
if (app.globalData.userInfo) {
const userInfo = app.globalData.userInfo;
this.setData({ userInfo });
// 验证是否为管理员
if (userInfo.role !== 'ADMIN') {
wx.showToast({
title: '无权限访问',
icon: 'none'
});
wx.navigateBack();
}
}
},
/**
* 获取完整的头像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);
}
},
/**
* 加载员工列表
*/
async loadEmployees() {
this.setData({
loading: true,
errorMessage: '',
successMessage: ''
});
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(employeesWithAvatars);
this.setData({
employees: employeesWithAvatars,
filteredEmployees,
loading: false
});
} catch (error) {
console.error('加载员工列表失败:', error);
this.setData({
loading: false,
errorMessage: '加载员工列表失败,请稍后重试'
});
}
},
/**
* 切换页面标签
*/
switchTab(e: any) {
const tab = e.currentTarget.dataset.tab;
this.setData({
currentTab: tab,
errorMessage: '',
successMessage: ''
});
// 只在切换到列表页且没有数据时才加载,避免频繁请求
if (tab === 'list' && this.data.employees.length === 0) {
this.loadEmployees();
}
},
/**
* 处理添加员工表单输入
*/
onFormInput(e: any) {
const { field } = e.currentTarget.dataset;
const value = e.detail.value;
this.setData({
[`addForm.${field}`]: value,
errorMessage: '',
successMessage: ''
});
},
/**
* 处理角色选择
*/
onRoleChange(e: any) {
const index = e.detail.value;
const selectedRole = this.data.roleOptions[index].value;
this.setData({
'addForm.role': selectedRole
});
},
/**
* 验证表单数据
*/
validateForm(): boolean {
const { name, phone, role } = this.data.addForm;
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;
},
/**
* 提交添加员工表单
*/
async submitAddForm() {
if (!this.validateForm()) {
return;
}
this.setData({
loading: true,
errorMessage: '',
successMessage: ''
});
try {
await employeeService.addEmployee(this.data.addForm);
this.setData({
loading: false,
successMessage: '员工添加成功',
addForm: {
name: '',
phone: '',
role: Role.DELIVERY_PERSON
}
});
// 添加成功后自动切换到列表页
setTimeout(() => {
this.setData({
currentTab: 'list'
});
this.loadEmployees();
}, 1500);
} catch (error) {
console.error('添加员工失败:', error);
this.setData({
loading: false,
errorMessage: (error as Error).message || '添加员工失败,请稍后重试'
});
}
},
/**
* 编辑员工
*/
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
});
},
/**
* 删除员工
*/
async deleteEmployee(e: any) {
const employeeId = e.currentTarget.dataset.id;
const employee = this.data.employees.find(emp => emp.id === employeeId);
if (!employee) {
return;
}
wx.showModal({
title: '确认删除',
content: `确定要删除员工 ${employee.name} (${employee.phone}) 吗?此操作不可恢复。`,
confirmText: '删除',
confirmColor: '#ff4d4f',
cancelText: '取消',
success: async (res) => {
if (res.confirm) {
this.setData({
loading: true,
errorMessage: '',
successMessage: ''
});
try {
const result = await employeeService.deleteEmployee(employeeId);
if (result.success) {
this.setData({
loading: false,
successMessage: result.message || '员工删除成功'
});
// 重新加载员工列表
this.loadEmployees();
} else {
this.setData({
loading: false,
errorMessage: result.message || '删除员工失败'
});
}
} catch (error) {
console.error('删除员工失败:', error);
this.setData({
loading: false,
errorMessage: '删除员工失败,请稍后重试'
});
}
}
}
});
},
/**
* 搜索员工
*/
onSearchInput(e: any) {
const keyword = e.detail.value;
this.setData({
searchKeyword: keyword
});
// 更新过滤后的员工列表
this.updateFilteredEmployees();
},
/**
* 更新过滤后的员工列表
*/
updateFilteredEmployees() {
const { employees } = this.data;
const filteredEmployees = this.getFilteredEmployees(employees);
this.setData({
filteredEmployees
});
},
/**
* 获取过滤后的员工列表
*/
getFilteredEmployees(employees?: EmployeeInfo[]): EmployeeInfo[] {
const { searchKeyword } = this.data;
// 如果employees为空返回空数组
if (!employees || !Array.isArray(employees)) {
return [];
}
// 显示所有员工,包括当前用户
let filteredEmployees = employees;
// 更严格的搜索关键词检查
if (!searchKeyword || typeof searchKeyword !== 'string' || !searchKeyword.trim()) {
return filteredEmployees;
}
const keyword = searchKeyword.toLowerCase();
return filteredEmployees.filter(emp =>
emp.name.toLowerCase().includes(keyword) ||
emp.phone.includes(keyword) ||
(emp.role || '').toLowerCase().includes(keyword)
);
},
/**
* 获取角色显示文本
*/
getRoleText(role: string): string {
const roleMap: Record<string, string> = {
'ADMIN': '管理员',
'DELIVERY_PERSON': '配送员',
'EMPLOYEE': '员工'
};
return roleMap[role] || role;
},
/**
* 清空消息
*/
clearMessages() {
this.setData({
errorMessage: '',
successMessage: ''
});
},
/**
* 返回上一页
*/
goBack() {
wx.navigateBack();
}
});