diff --git a/antis-ncc-admin/src/api/extend/lqInventory.js b/antis-ncc-admin/src/api/extend/lqInventory.js new file mode 100644 index 0000000..11cce23 --- /dev/null +++ b/antis-ncc-admin/src/api/extend/lqInventory.js @@ -0,0 +1,104 @@ +import request from '@/utils/request' + +// ========== 库存管理接口 ========== + +// 创建库存 +export function createInventory(data) { + return request({ + url: '/api/Extend/LqInventory/Create', + method: 'post', + data + }) +} + +// 更新库存 +export function updateInventory(data) { + return request({ + url: '/api/Extend/LqInventory/Update', + method: 'put', + data + }) +} + +// 获取库存列表 +export function getInventoryList(params) { + return request({ + url: '/api/Extend/LqInventory/GetList', + method: 'get', + data: params + }) +} + +// 获取库存详情 +export function getInventoryInfo(id) { + return request({ + url: '/api/Extend/LqInventory/GetInfo', + method: 'get', + data: { id } + }) +} + +// ========== 库存使用记录接口 ========== + +// 添加库存使用记录 +export function createInventoryUsage(data) { + return request({ + url: '/api/Extend/LqInventoryUsage/Create', + method: 'post', + data + }) +} + +// 作废库存使用记录 +export function cancelInventoryUsage(id, remarks) { + return request({ + url: '/api/Extend/LqInventoryUsage/Cancel', + method: 'put', + data: { id, remarks } + }) +} + +// 获取使用记录列表 +export function getInventoryUsageList(params) { + return request({ + url: '/api/Extend/LqInventoryUsage/GetList', + method: 'get', + data: params + }) +} + +// 获取产品使用统计 +export function getProductUsageStatistics(data) { + return request({ + url: '/api/Extend/LqInventoryUsage/GetProductUsageStatistics', + method: 'post', + data + }) +} + +// 获取门店使用统计 +export function getStoreUsageStatistics(data) { + return request({ + url: '/api/Extend/LqInventoryUsage/GetStoreUsageStatistics', + method: 'post', + data + }) +} + +// 获取使用趋势统计 +export function getUsageTrendStatistics(data) { + return request({ + url: '/api/Extend/LqInventoryUsage/GetUsageTrendStatistics', + method: 'post', + data + }) +} + +// 获取产品使用排行榜 +export function getProductUsageRanking(data) { + return request({ + url: '/api/Extend/LqInventoryUsage/GetProductUsageRanking', + method: 'post', + data + }) +} diff --git a/antis-ncc-admin/src/api/extend/lqStudyClass.js b/antis-ncc-admin/src/api/extend/lqStudyClass.js new file mode 100644 index 0000000..97f6ecf --- /dev/null +++ b/antis-ncc-admin/src/api/extend/lqStudyClass.js @@ -0,0 +1,65 @@ +import request from '@/utils/request' + +// 创建学习班级并添加学员 +export function createClassWithStudents(data) { + return request({ + url: '/api/Extend/LqStudyClass/CreateClassWithStudents', + method: 'post', + data + }) +} + +// 向现有班级添加学员 +export function addStudentsToClass(data) { + return request({ + url: '/api/Extend/LqStudyClass/AddStudentsToClass', + method: 'post', + data + }) +} + +// 获取所有班级列表 +export function getClassList(params) { + return request({ + url: '/api/Extend/LqStudyClass/GetClassList', + method: 'get', + data: params + }) +} + +// 获取班级下所有学员信息 +export function getStudentListByClassId(params) { + return request({ + url: '/api/Extend/LqStudyClass/GetStudentListByClassId', + method: 'get', + data: params + }) +} + +// 添加学习记录 +export function addStudyRecord(data) { + return request({ + url: '/api/Extend/LqStudyClass/AddStudyRecord', + method: 'post', + data + }) +} + +// 获取学习记录列表 +export function getStudyRecordList(params) { + return request({ + url: '/api/Extend/LqStudyClass/GetStudyRecordList', + method: 'get', + data: params + }) +} + +// 作废学习记录 +export function cancelStudyRecord(id) { + return request({ + url: '/api/Extend/LqStudyClass/CancelStudyRecord', + method: 'post', + data: id + }) +} + diff --git a/antis-ncc-admin/src/router/modules/base.js b/antis-ncc-admin/src/router/modules/base.js index 50ba3da..a82bdc9 100644 --- a/antis-ncc-admin/src/router/modules/base.js +++ b/antis-ncc-admin/src/router/modules/base.js @@ -76,6 +76,17 @@ const baseRouter = [{ icon: 'icon-ym icon-ym-s-data', } }, + { + path: '/lqInventory', + component: (resolve) => require(['@/views/lqInventory'], resolve), + name: 'lqInventory', + meta: { + title: 'lqInventory', + affix: false, + zhTitle: '库存管理', + icon: 'icon-ym icon-ym-box', + } + }, { path: '/salaryCalculation', component: (resolve) => require(['@/views/salaryCalculation/index'], resolve), diff --git a/antis-ncc-admin/src/views/lqInventory/AddUsageRecordForm.vue b/antis-ncc-admin/src/views/lqInventory/AddUsageRecordForm.vue new file mode 100644 index 0000000..d65e95f --- /dev/null +++ b/antis-ncc-admin/src/views/lqInventory/AddUsageRecordForm.vue @@ -0,0 +1,259 @@ + + + + + diff --git a/antis-ncc-admin/src/views/lqInventory/InventoryForm.vue b/antis-ncc-admin/src/views/lqInventory/InventoryForm.vue new file mode 100644 index 0000000..ea29810 --- /dev/null +++ b/antis-ncc-admin/src/views/lqInventory/InventoryForm.vue @@ -0,0 +1,216 @@ + + + + + diff --git a/antis-ncc-admin/src/views/lqInventory/InventoryInfoDialog.vue b/antis-ncc-admin/src/views/lqInventory/InventoryInfoDialog.vue new file mode 100644 index 0000000..94adeef --- /dev/null +++ b/antis-ncc-admin/src/views/lqInventory/InventoryInfoDialog.vue @@ -0,0 +1,193 @@ + + + + + diff --git a/antis-ncc-admin/src/views/lqInventory/UsageRecordDialog.vue b/antis-ncc-admin/src/views/lqInventory/UsageRecordDialog.vue new file mode 100644 index 0000000..894724b --- /dev/null +++ b/antis-ncc-admin/src/views/lqInventory/UsageRecordDialog.vue @@ -0,0 +1,287 @@ + + + + + diff --git a/antis-ncc-admin/src/views/lqInventory/index.vue b/antis-ncc-admin/src/views/lqInventory/index.vue new file mode 100644 index 0000000..0e0f568 --- /dev/null +++ b/antis-ncc-admin/src/views/lqInventory/index.vue @@ -0,0 +1,295 @@ + + + + + diff --git a/antis-ncc-admin/src/views/lqStudyClass/AddStudentForm.vue b/antis-ncc-admin/src/views/lqStudyClass/AddStudentForm.vue new file mode 100644 index 0000000..8dad244 --- /dev/null +++ b/antis-ncc-admin/src/views/lqStudyClass/AddStudentForm.vue @@ -0,0 +1,166 @@ + + + + + diff --git a/antis-ncc-admin/src/views/lqStudyClass/CreateClassForm.vue b/antis-ncc-admin/src/views/lqStudyClass/CreateClassForm.vue new file mode 100644 index 0000000..a5c22c8 --- /dev/null +++ b/antis-ncc-admin/src/views/lqStudyClass/CreateClassForm.vue @@ -0,0 +1,226 @@ + + + + + diff --git a/antis-ncc-admin/src/views/lqStudyClass/StudentListDialog.vue b/antis-ncc-admin/src/views/lqStudyClass/StudentListDialog.vue new file mode 100644 index 0000000..4caac97 --- /dev/null +++ b/antis-ncc-admin/src/views/lqStudyClass/StudentListDialog.vue @@ -0,0 +1,202 @@ + + + + + diff --git a/antis-ncc-admin/src/views/lqStudyClass/StudyRecordDialog.vue b/antis-ncc-admin/src/views/lqStudyClass/StudyRecordDialog.vue new file mode 100644 index 0000000..bf3be8d --- /dev/null +++ b/antis-ncc-admin/src/views/lqStudyClass/StudyRecordDialog.vue @@ -0,0 +1,407 @@ + + + + + diff --git a/antis-ncc-admin/src/views/lqStudyClass/index.vue b/antis-ncc-admin/src/views/lqStudyClass/index.vue new file mode 100644 index 0000000..559f20d --- /dev/null +++ b/antis-ncc-admin/src/views/lqStudyClass/index.vue @@ -0,0 +1,246 @@ + + + + + diff --git a/antis-ncc-admin/src/views/lqStudyClass/test.html b/antis-ncc-admin/src/views/lqStudyClass/test.html new file mode 100644 index 0000000..6d6d4f2 --- /dev/null +++ b/antis-ncc-admin/src/views/lqStudyClass/test.html @@ -0,0 +1,236 @@ + + + + + + 学习班级管理 - 功能测试 + + + +
+
+

🎓 学习班级管理系统

+

基于Vue 2.6 + Element UI + ASP.NET Core开发的学习班级管理功能

+
+ +
+

📋 已实现功能

+ +
+ +
+

🔧 API接口配置

+
+

接口地址:/api/Extend/LqStudyClass

+

请求方法:GET, POST

+

主要接口:

+
+POST /api/Extend/LqStudyClass/CreateClassWithStudents +GET /api/Extend/LqStudyClass/GetClassList +POST /api/Extend/LqStudyClass/AddStudentsToClass +GET /api/Extend/LqStudyClass/GetStudentListByClassId +POST /api/Extend/LqStudyClass/AddStudyRecord +GET /api/Extend/LqStudyClass/GetStudyRecordList +POST /api/Extend/LqStudyClass/CancelStudyRecord +
+
+
+ +
+

📁 文件结构

+
+lqStudyClass/ +├── index.vue # 主页面组件 +├── CreateClassForm.vue # 创建班级表单组件 +├── AddStudentForm.vue # 添加学员表单组件 +├── StudentListDialog.vue # 学员列表弹窗组件 +└── StudyRecordDialog.vue # 学习记录管理弹窗组件 + +api/extend/ +└── lqStudyClass.js # API接口定义 +
+
+ +
+

🎯 核心功能说明

+
+

1. 创建学习班级并添加学员

+

支持一次性创建班级并批量添加学员,包含班级基本信息(名称、老师、时间、备注)和学员详细信息(姓名、手机、员工ID、入学时间、HR归属)。

+ +

2. 班级列表管理

+

提供班级列表展示,支持按班级名称、授课老师、开始时间等条件搜索,支持分页显示。

+ +

3. 学员管理

+

可以查看指定班级下的所有学员信息,支持学员信息搜索和筛选,支持向现有班级添加新学员。

+ +

4. 学习记录管理

+

记录学员的学习情况,包括学习类型、交通费、学习日期、日常状态、是否下店协助等信息,支持记录的添加、查看和作废操作。

+
+
+ +
+

🚀 技术特点

+ +
+ +
+

📊 数据流程

+
+

创建班级流程:

+
    +
  1. 填写班级基本信息(名称、老师、时间等)
  2. +
  3. 添加学员信息(可批量添加)
  4. +
  5. 提交表单,后端创建班级和学员记录
  6. +
  7. 返回创建结果,刷新列表
  8. +
+ +

学员管理流程:

+
    +
  1. 从班级列表选择班级
  2. +
  3. 查看班级学员列表
  4. +
  5. 支持搜索和筛选学员
  6. +
  7. 可添加新学员到班级
  8. +
+ +

学习记录流程:

+
    +
  1. 选择班级查看学习记录
  2. +
  3. 添加新的学习记录
  4. +
  5. 支持记录搜索和筛选
  6. +
  7. 可作废无效记录
  8. +
+
+
+ +
+

✅ 开发状态

+

+ 前端页面:已完成 + API接口:已对接 + 路由配置:已配置 + 功能测试:待测试 +

+
+
+ + + diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryService.cs index 6344fa0..1aa2892 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryService.cs @@ -171,20 +171,40 @@ namespace NCC.Extend quantity = x.Quantity, productCategory = x.ProductCategory, departmentId = x.DepartmentId, - departmentName = SqlFunc.Subqueryable().Where(u => u.Id == x.DepartmentId).Select(u => u.RealName), + departmentName = "", standardUnit = x.StandardUnit, totalValue = x.Price * x.Quantity, createUser = x.CreateUser, - createUserName = SqlFunc.Subqueryable().Where(u => u.Id == x.CreateUser).Select(u => u.RealName), + createUserName = "", createTime = x.CreateTime, updateUser = x.UpdateUser, - updateUserName = SqlFunc.Subqueryable().Where(u => u.Id == x.UpdateUser).Select(u => u.RealName), + updateUserName = "", updateTime = x.UpdateTime, isEffective = x.IsEffective }) .MergeTable() .OrderBy(sidx + " " + input.sort) .ToPagedListAsync(input.currentPage, input.pageSize); + + // 补充用户名称信息 + foreach (var item in data.list) + { + if (!string.IsNullOrEmpty(item.departmentId)) + { + var deptUser = await _db.Queryable().Where(u => u.Id == item.departmentId).FirstAsync(); + item.departmentName = deptUser?.RealName ?? ""; + } + if (!string.IsNullOrEmpty(item.createUser)) + { + var createUser = await _db.Queryable().Where(u => u.Id == item.createUser).FirstAsync(); + item.createUserName = createUser?.RealName ?? ""; + } + if (!string.IsNullOrEmpty(item.updateUser)) + { + var updateUser = await _db.Queryable().Where(u => u.Id == item.updateUser).FirstAsync(); + item.updateUserName = updateUser?.RealName ?? ""; + } + } return PageResult.SqlSugarPageResult(data); } catch (Exception ex) @@ -210,12 +230,14 @@ namespace NCC.Extend { throw NCCException.Oh("库存ID不能为空"); } + // 查询库存信息 var inventory = await _db.Queryable().Where(x => x.Id == id).FirstAsync(); if (inventory == null) { throw NCCException.Oh("库存记录不存在"); } + var result = new LqInventoryInfoOutput { id = inventory.Id, @@ -224,18 +246,35 @@ namespace NCC.Extend quantity = inventory.Quantity, productCategory = inventory.ProductCategory, departmentId = inventory.DepartmentId, - departmentName = SqlFunc.Subqueryable().Where(u => u.Id == inventory.DepartmentId).Select(u => u.RealName), + departmentName = "", standardUnit = inventory.StandardUnit, totalValue = inventory.Price * inventory.Quantity, createUser = inventory.CreateUser, - createUserName = SqlFunc.Subqueryable().Where(u => u.Id == inventory.CreateUser).Select(u => u.RealName), + createUserName = "", createTime = inventory.CreateTime, updateUser = inventory.UpdateUser, - updateUserName = SqlFunc.Subqueryable().Where(u => u.Id == inventory.UpdateUser).Select(u => u.RealName), + updateUserName = "", updateTime = inventory.UpdateTime, isEffective = inventory.IsEffective }; + // 补充用户名称信息 + if (!string.IsNullOrEmpty(result.departmentId)) + { + var deptUser = await _db.Queryable().Where(u => u.Id == result.departmentId).FirstAsync(); + result.departmentName = deptUser?.RealName ?? ""; + } + if (!string.IsNullOrEmpty(result.createUser)) + { + var createUser = await _db.Queryable().Where(u => u.Id == result.createUser).FirstAsync(); + result.createUserName = createUser?.RealName ?? ""; + } + if (!string.IsNullOrEmpty(result.updateUser)) + { + var updateUser = await _db.Queryable().Where(u => u.Id == result.updateUser).FirstAsync(); + result.updateUserName = updateUser?.RealName ?? ""; + } + return result; } catch (Exception ex) diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs index dcf331e..f4a181f 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqInventoryUsageService.cs @@ -186,28 +186,70 @@ namespace NCC.Extend { Id = x.Id, ProductId = x.ProductId, - ProductName = SqlFunc.Subqueryable().Where(p => p.Id == x.ProductId).Select(p => p.ProductName), - ProductCategory = SqlFunc.Subqueryable().Where(p => p.Id == x.ProductId).Select(p => p.ProductCategory), - ProductPrice = SqlFunc.Subqueryable().Where(p => p.Id == x.ProductId).Select(p => p.Price), + ProductName = "", + ProductCategory = "", + ProductPrice = 0, StoreId = x.StoreId, - StoreName = SqlFunc.Subqueryable().Where(u => u.Id == x.StoreId).Select(u => u.RealName), + StoreName = "", UsageTime = x.UsageTime, UsageQuantity = x.UsageQuantity, RelatedConsumeId = x.RelatedConsumeId, CreateUser = x.CreateUser, - CreateUserName = SqlFunc.Subqueryable().Where(u => u.Id == x.CreateUser).Select(u => u.RealName), + CreateUserName = "", CreateTime = x.CreateTime, UpdateUser = x.UpdateUser, - UpdateUserName = SqlFunc.Subqueryable().Where(u => u.Id == x.UpdateUser).Select(u => u.RealName), + UpdateUserName = "", UpdateTime = x.UpdateTime, IsEffective = x.IsEffective }) .MergeTable() - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductName), x => x.ProductName.Contains(input.ProductName)) - .WhereIF(!string.IsNullOrWhiteSpace(input.ProductCategory), x => x.ProductCategory.Contains(input.ProductCategory)) - .WhereIF(!string.IsNullOrWhiteSpace(input.StoreName), x => x.StoreName.Contains(input.StoreName)) .OrderBy(sidx + " " + input.sort) .ToPagedListAsync(input.currentPage, input.pageSize); + + // 补充产品信息和用户信息 + foreach (var item in data.list) + { + if (!string.IsNullOrEmpty(item.ProductId)) + { + var product = await _db.Queryable().Where(p => p.Id == item.ProductId).FirstAsync(); + if (product != null) + { + item.ProductName = product.ProductName; + item.ProductCategory = product.ProductCategory; + item.ProductPrice = product.Price; + } + } + if (!string.IsNullOrEmpty(item.StoreId)) + { + var store = await _db.Queryable().Where(u => u.Id == item.StoreId).FirstAsync(); + item.StoreName = store?.RealName ?? ""; + } + if (!string.IsNullOrEmpty(item.CreateUser)) + { + var createUser = await _db.Queryable().Where(u => u.Id == item.CreateUser).FirstAsync(); + item.CreateUserName = createUser?.RealName ?? ""; + } + if (!string.IsNullOrEmpty(item.UpdateUser)) + { + var updateUser = await _db.Queryable().Where(u => u.Id == item.UpdateUser).FirstAsync(); + item.UpdateUserName = updateUser?.RealName ?? ""; + } + } + + // 应用产品名称和分类的过滤条件 + if (!string.IsNullOrWhiteSpace(input.ProductName) || !string.IsNullOrWhiteSpace(input.ProductCategory)) + { + data.list = data.list.Where(x => + (string.IsNullOrWhiteSpace(input.ProductName) || x.ProductName.Contains(input.ProductName)) && + (string.IsNullOrWhiteSpace(input.ProductCategory) || x.ProductCategory.Contains(input.ProductCategory)) + ).ToList(); + } + + // 应用门店名称的过滤条件 + if (!string.IsNullOrWhiteSpace(input.StoreName)) + { + data.list = data.list.Where(x => x.StoreName.Contains(input.StoreName)).ToList(); + } return PageResult.SqlSugarPageResult(data); } catch (Exception ex)