2025/12/17 每日总结 核心业务模块(一):客户与员工全流程管理
核心业务模块(一):客户与员工全流程管理
承接上一篇的系统基础架构搭建,本篇聚焦MoonMIS系统的“人”管理核心——客户(老板池)与员工(打手)全流程管理。将详细拆解客户信息的增删改查、员工绩效统计、搜索筛选等核心功能,提供可直接复用的数据库交互代码和界面实现逻辑,帮大家搞定业务系统中“用户管理”的核心场景。
一、模块设计核心目标:为什么要做“人”的管理?
1. 模块定位
客户与员工是工作室业务的核心载体:老板池模块负责管理付费客户资源,记录客户偏好、消费记录等关键信息,支撑复购转化;员工管理模块负责维护服务提供方信息,跟踪工作状态与绩效,保障服务效率。两个模块共同构成“需求方-供给方”的连接桥梁,是订单流转的基础。
2. 核心功能清单
| 模块 | 核心功能 | 涉及控件/技术 |
|---|---|---|
| 老板池管理 | 客户信息增删改查、搜索筛选、标签分类、复购预警、黑名单管理 | DataGridView、TextBox、Button、MySQL CRUD、SQL聚合查询 |
| 员工管理 | 员工信息维护、状态管理(在线/忙碌/休息)、绩效统计(订单数/成功率)、搜索查询 | DataGridView、ComboBox、Label、SQL条件查询 |
3. 数据库表设计(核心表结构)
(1)客户表(Bosses)
CREATE TABLE Bosses (
BossId VARCHAR(50) PRIMARY KEY, -- 客户唯一ID(如BOS000001)
BossName VARCHAR(50) NOT NULL, -- 微信昵称/客户名称
Source VARCHAR(30), -- 来源渠道(QQ/微信/网站/推荐)
ContactInfo VARCHAR(100), -- 联系方式
AvgOrderAmount DECIMAL(10,2), -- 平均订单金额
Last30DaysSpend DECIMAL(10,2), -- 近30天消费
Tags VARCHAR(100), -- 用户标签(如高消费、稳定客户)
IsBlacklisted TINYINT(1) DEFAULT 0, -- 是否黑名单(0否1是)
ComplaintCount INT DEFAULT 0, -- 投诉次数
BanCount INT DEFAULT 0, -- 封禁次数
LastOrderDate DATETIME, -- 最后订单日期
CreatedAt DATETIME DEFAULT NOW() -- 创建时间
);
(2)员工表(Workers)
CREATE TABLE Workers (
WorkerId VARCHAR(50) PRIMARY KEY, -- 员工唯一ID(如WRK000001)
WorkerName VARCHAR(50) NOT NULL, -- 姓名
Contact VARCHAR(20), -- 联系方式
GameAccount VARCHAR(100), -- 游戏账号(业务相关账号)
Status VARCHAR(20) DEFAULT '空闲', -- 状态(在线/忙碌/休息/离线)
RegisterTime DATETIME DEFAULT NOW(), -- 注册时间
TotalOrders INT DEFAULT 0, -- 总订单数
CompletedOrders INT DEFAULT 0, -- 已完成订单数
SuccessRate DECIMAL(5,2) DEFAULT 0 -- 成功率(CompletedOrders/TotalOrders)
);
二、老板池模块开发:客户全生命周期管理
1. 界面布局设计
老板池界面核心分为三部分:
-
顶部统计区:展示总老板数、活跃老板、复购率、VIP老板等核心指标
-
功能操作区:包含搜索框、刷新、自动标签、复购预警、黑名单检查等按钮
-
数据展示区:用DataGridView展示客户列表,支持分页、选中编辑/删除
2. 核心功能实现
(1)客户列表加载:DataGridView绑定数据库数据
DataGridView是展示列表数据的核心控件,通过MySQL查询结果动态填充,实现客户信息的可视化展示:
// 加载客户列表(核心方法) private void LoadBossList() { // 清空现有数据 bossDataGridView.Rows.Clear(); // 数据库连接(使用上一篇封装的DatabaseHelper) using (var conn = DatabaseHelper.GetConnection()) { conn.Open(); // 查询客户列表(按创建时间倒序) string query = "SELECT BossId, BossName, Source, AvgOrderAmount, Last30DaysSpend, " + "Tags, IsBlacklisted, ComplaintCount, BanCount, LastOrderDate " + "FROM Bosses ORDER BY CreatedAt DESC";
using (var cmd = new MySqlCommand(query, conn))
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// 逐行添加数据到DataGridView
bossDataGridView.Rows.Add(
reader["BossId"],
reader["BossName"],
reader["Source"],
Convert.ToDecimal(reader["AvgOrderAmount"]).ToString("C2"), // 金额格式化
Convert.ToDecimal(reader["Last30DaysSpend"]).ToString("C2"),
reader["Tags"],
reader["IsBlacklisted"].ToString() == "1" ? "是" : "否", // 布尔值转文字
reader["ComplaintCount"],
reader["BanCount"],
Convert.ToDateTime(reader["LastOrderDate"]).ToString("yyyy/MM/dd HH:mm") // 日期格式化
);
}
}
}
}
#### (2)客户添加:表单录入+数据验证
通过弹出表单窗口收集客户信息,验证数据合法性后插入数据库:
```csharp
// 添加客户按钮点击事件
private void btnAddBoss_Click(object sender, EventArgs e)
{
// 弹出添加客户表单(自定义窗口AddBossForm)
AddBossForm addForm = new AddBossForm();
if (addForm.ShowDialog() == DialogResult.OK)
{
// 获取表单输入数据
string bossId = GenerateBossId(); // 生成唯一ID(如BOS000011)
string bossName = addForm.txtBossName.Text;
string source = addForm.cmbSource.SelectedItem.ToString();
string tags = addForm.txtTags.Text;
// ... 其他字段获取
// 插入数据库
using (var conn = DatabaseHelper.GetConnection())
{
conn.Open();
string insertQuery = "INSERT INTO Bosses (BossId, BossName, Source, Tags, Last30DaysSpend, AvgOrderAmount) " +
"VALUES (@BossId, @BossName, @Source, @Tags, 0, 0)";
using (var cmd = new MySqlCommand(insertQuery, conn))
{
// 参数化查询(避免SQL注入)
cmd.Parameters.AddWithValue("@BossId", bossId);
cmd.Parameters.AddWithValue("@BossName", bossName);
cmd.Parameters.AddWithValue("@Source", source);
cmd.Parameters.AddWithValue("@Tags", tags);
cmd.ExecuteNonQuery();
}
}
// 重新加载列表
LoadBossList();
MessageBox.Show("客户添加成功!");
}
}
// 生成唯一客户ID(BOS+6位数字)
private string GenerateBossId()
{
using (var conn = DatabaseHelper.GetConnection())
{
conn.Open();
string query = "SELECT MAX(BossId) FROM Bosses";
object maxId = new MySqlCommand(query, conn).ExecuteScalar();
if (maxId == DBNull.Value)
return "BOS000001";
// 截取数字部分自增
int idNum = int.Parse(maxId.ToString().Substring(3)) + 1;
return $"BOS{idNum:D6}"; // 格式化为6位数字
}
}
(3)客户搜索筛选:文本输入+条件查询
支持按客户ID、微信昵称模糊搜索,核心是动态拼接SQL查询条件:
private void btnSearchBoss_Click(object sender, EventArgs e)
{
string keyWord = txtSearchBoss.Text.Trim();
bossDataGridView.Rows.Clear();
using (var conn = DatabaseHelper.GetConnection())
{
conn.Open();
// 动态拼接查询条件(模糊匹配BossId或BossName)
string query = "SELECT BossId, BossName, Source, AvgOrderAmount, Last30DaysSpend, " +
"Tags, IsBlacklisted, ComplaintCount, BanCount, LastOrderDate " +
"FROM Bosses WHERE BossId LIKE @KeyWord OR BossName LIKE @KeyWord " +
"ORDER BY CreatedAt DESC";
using (var cmd = new MySqlCommand(query, conn))
{
// 模糊查询参数(%表示任意字符)
cmd.Parameters.AddWithValue("@KeyWord", $"%{keyWord}%");
using (var reader = cmd.ExecuteReader())
{
// 同LoadBossList逻辑,填充DataGridView
while (reader.Read())
{
// 数据添加逻辑...(与LoadBossList一致)
}
}
}
}
}
(4)复购预警功能:SQL聚合查询筛选
筛选近30天无消费但历史有订单的客户,实现复购提醒:
private void btnRepurchaseAlert_Click(object sender, EventArgs e)
{
List<string> alertBosses = new List<string>();
using (var conn = DatabaseHelper.GetConnection())
{
conn.Open();
// 查询条件:近30天消费为0 + 总订单数≥1
string query = "SELECT BossName, LastOrderDate FROM Bosses " +
"WHERE Last30DaysSpend = 0 AND " +
"EXISTS (SELECT 1 FROM Orders WHERE Orders.BossId = Bosses.BossId)";
using (var cmd = new MySqlCommand(query, conn))
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
string bossName = reader["BossName"].ToString();
string lastOrderDate = Convert.ToDateTime(reader["LastOrderDate"]).ToString("yyyy/MM/dd");
alertBosses.Add($"{bossName}(最后消费:{lastOrderDate})");
}
}
}
// 显示预警信息
if (alertBosses.Count > 0)
MessageBox.Show("复购预警客户:\n" + string.Join("\n", alertBosses), "复购提醒");
else
MessageBox.Show("暂无需要复购预警的客户");
}
3. 界面样式优化
-
DataGridView设置:启用行选中、禁止编辑(通过代码控制修改)、列宽自适应
-
标签展示:用不同颜色标注客户标签(如“高消费”标红色、“稳定客户”标绿色)
-
操作按钮:添加/编辑/删除按钮按功能分组,hover时变色,提升交互体验
三、员工管理模块开发:从信息维护到绩效统计
1. 界面布局设计
与老板池模块布局逻辑一致,保持系统界面统一性:
-
顶部统计区:展示总打手数、活跃打手、暂停打手、平均成功率
-
功能操作区:搜索框、添加/编辑/删除按钮
-
数据展示区:DataGridView展示员工列表,包含基本信息、状态、绩效数据
2. 核心功能实现
(1)员工状态管理:ComboBox下拉选择
员工状态(在线/忙碌/休息/离线)直接影响订单分配,通过ComboBox实现状态快速切换:
// 初始化员工状态下拉框(在DataGridView编辑模式中) private void bossDataGridView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e) { // 假设第5列是状态列 if (e.ColumnIndex == 5) { DataGridViewComboBoxCell comboCell = new DataGridViewComboBoxCell(); comboCell.Items.AddRange("在线", "忙碌", "休息", "离线"); bossDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex] = comboCell; // 选中当前状态 comboCell.Value = bossDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value; } } // 状态修改后同步到数据库 private void bossDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) { if (e.ColumnIndex == 5) { string workerId = bossDataGridView.Rows[e.RowIndex].Cells[0].Value.ToString(); string newStatus = bossDataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
using (var conn = DatabaseHelper.GetConnection())
{
conn.Open();
string updateQuery = "UPDATE Workers SET Status = @Status WHERE WorkerId = @WorkerId";
using (var cmd = new MySqlCommand(updateQuery, conn))
{
cmd.Parameters.AddWithValue("@Status", newStatus);
cmd.Parameters.AddWithValue("@WorkerId", workerId);
cmd.ExecuteNonQuery();
}
}
}
}
#### (2)员工绩效统计:SQL聚合查询
自动计算员工总订单数、已完成订单数、成功率,核心是通过SQL聚合函数统计数据:
```csharp
// 更新员工绩效统计(传入员工ID)
private void UpdateWorkerStats(string workerId)
{
using (var conn = DatabaseHelper.GetConnection())
{
conn.Open();
// 统计该员工的订单数据
string statsQuery = "SELECT " +
"COUNT(*) as TotalOrders, " +
"SUM(CASE WHEN Status = '已完成' THEN 1 ELSE 0 END) as CompletedOrders, " +
"IF(COUNT(*) = 0, 0, SUM(CASE WHEN Status = '已完成' THEN 1 ELSE 0 END) / COUNT(*) * 100) as SuccessRate " +
"FROM Orders WHERE WorkerId = @WorkerId";
using (var cmd = new MySqlCommand(statsQuery, conn))
{
cmd.Parameters.AddWithValue("@WorkerId", workerId);
using (var reader = cmd.ExecuteReader())
{
if (reader.Read())
{
int totalOrders = Convert.ToInt32(reader["TotalOrders"]);
int completedOrders = Convert.ToInt32(reader["CompletedOrders"]);
decimal successRate = Convert.ToDecimal(reader["SuccessRate"]);
// 更新员工表中的绩效数据
UpdateWorkerStatsToDB(workerId, totalOrders, completedOrders, successRate);
// 更新界面显示
UpdateWorkerStatsUI(workerId, totalOrders, completedOrders, successRate.ToString("F2") + "%");
}
}
}
}
}
// 将绩效数据写入员工表
private void UpdateWorkerStatsToDB(string workerId, int totalOrders, int completedOrders, decimal successRate)
{
using (var conn = DatabaseHelper.GetConnection())
{
conn.Open();
string updateQuery = "UPDATE Workers SET TotalOrders = @TotalOrders, " +
"CompletedOrders = @CompletedOrders, SuccessRate = @SuccessRate " +
"WHERE WorkerId = @WorkerId";
using (var cmd = new MySqlCommand(updateQuery, conn))
{
cmd.Parameters.AddWithValue("@TotalOrders", totalOrders);
cmd.Parameters.AddWithValue("@CompletedOrders", completedOrders);
cmd.Parameters.AddWithValue("@SuccessRate", successRate);
cmd.Parameters.AddWithValue("@WorkerId", workerId);
cmd.ExecuteNonQuery();
}
}
}
(3)员工搜索:多条件模糊匹配
支持按员工ID、姓名、联系方式搜索,逻辑与客户搜索一致,动态拼接查询条件:
private void btnSearchWorker_Click(object sender, EventArgs e)
{
string keyWord = txtSearchWorker.Text.Trim();
workerDataGridView.Rows.Clear();
using (var conn = DatabaseHelper.GetConnection())
{
conn.Open();
string query = "SELECT WorkerId, WorkerName, Contact, GameAccount, Status, TotalOrders, SuccessRate, RegisterTime " +
"FROM Workers WHERE WorkerId LIKE @KeyWord OR WorkerName LIKE @KeyWord OR Contact LIKE @KeyWord " +
"ORDER BY RegisterTime DESC";
using (var cmd = new MySqlCommand(query, conn))
{
cmd.Parameters.AddWithValue("@KeyWord", $"%{keyWord}%");
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// 填充DataGridView逻辑...
}
}
}
}
}
3. 批量操作与数据导出
支持员工信息批量导出为CSV文件,方便离线统计:
private void btnExportWorkers_Click(object sender, EventArgs e)
{
SaveFileDialog saveDialog = new SaveFileDialog();
saveDialog.Filter = "CSV文件|*.csv";
saveDialog.Title = "导出员工数据";
if (saveDialog.ShowDialog() == DialogResult.OK)
{
// 写入CSV文件
using (StreamWriter sw = new StreamWriter(saveDialog.FileName, false, Encoding.UTF8))
{
// 写入表头
sw.WriteLine("员工ID,姓名,联系方式,游戏账号,状态,总订单数,成功率,注册时间");
// 写入数据行
foreach (DataGridViewRow row in workerDataGridView.Rows)
{
if (!row.IsNewRow)
{
string line = string.Join(",",
row.Cells["WorkerId"].Value.ToString(),
row.Cells["WorkerName"].Value.ToString(),
row.Cells["Contact"].Value.ToString(),
row.Cells["GameAccount"].Value.ToString(),
row.Cells["Status"].Value.ToString(),
row.Cells["TotalOrders"].Value.ToString(),
row.Cells["SuccessRate"].Value.ToString(),
row.Cells["RegisterTime"].Value.ToString()
);
sw.WriteLine(line);
}
}
}
MessageBox.Show("导出成功!");
}
}
四、开发避坑指南:这些问题一定要注意
- 数据重复加载:每次查询前清空DataGridView的Rows,避免重复添加;使用
using语句自动释放数据库连接,防止连接泄露。 - SQL注入风险:所有用户输入(如搜索关键词、表单数据)必须使用参数化查询(
cmd.Parameters.AddWithValue),禁止直接拼接SQL字符串。 - 金额/日期格式化:从数据库读取的金额、日期需统一格式化(如金额转货币格式、日期转“yyyy/MM/dd”),保证界面显示一致性。
- 空值处理:数据库查询结果可能为DBNull,需先判断(
reader.IsDBNull(index)),再转换类型,避免空引用异常。 - 界面卡顿:数据量较大时(如百级以上客户/员工),可添加分页功能(SQL LIMIT),或在后台线程加载数据,避免界面卡死。

浙公网安备 33010602011771号