Commit bdf9e89151890af2bc168f6b74498d7a8169c5eb

Authored by “wangming”
1 parent 96009bc9

更新.gitignore以包含.zip文件和Cursor IDE文件,添加WeChatBotService和LqKdKdjlbStringGenerator的依…

…赖注入,改进LqKdKdjlbService以生成并发送开单记录字符串到企业微信群,更新package.json以支持legacy模式。
Showing 75 changed files with 1436 additions and 2 deletions
.DS_Store
No preview for this file type
.gitignore
... ... @@ -272,4 +272,7 @@ __pycache__/
272 272 .config/
273 273 admin-web
274 274 *.rar
275   -*.zip
276 275 \ No newline at end of file
  276 +*.zip
  277 +
  278 +# Cursor IDE files
  279 +.cursor/
277 280 \ No newline at end of file
... ...
README.md 0 → 100644
  1 +# 绿纤ERP管理系统
  2 +
  3 +## 项目简介
  4 +
  5 +绿纤ERP管理系统是一个基于现代化技术栈开发的企业资源规划系统,专为绿纤行业量身定制。系统采用前后端分离架构,提供完整的生产、销售、库存、财务等业务管理功能。
  6 +
  7 +## 技术栈
  8 +
  9 +### 后端技术
  10 +- **.NET Core 3.1/5.0** - 跨平台Web框架
  11 +- **SqlSugar** - 轻量级ORM框架
  12 +- **MySQL** - 关系型数据库
  13 +- **JWT** - 身份认证
  14 +- **Serilog** - 结构化日志
  15 +- **Swagger** - API文档
  16 +
  17 +### 前端技术
  18 +- **Vue 2.6** - 渐进式JavaScript框架
  19 +- **Element UI** - 企业级UI组件库
  20 +- **Vuex** - 状态管理
  21 +- **Vue Router** - 路由管理
  22 +- **Axios** - HTTP客户端
  23 +- **SCSS** - CSS预处理器
  24 +
  25 +## 项目结构
  26 +
  27 +```
  28 +lvqianmeiye_ERP/
  29 +├── netcore/ # 后端.NET Core项目
  30 +│ └── src/
  31 +│ ├── Application/ # 应用层
  32 +│ ├── Infrastructure/ # 基础设施层
  33 +│ └── Modularity/ # 业务模块层
  34 +│ ├── System/ # 系统管理模块
  35 +│ ├── Extend/ # 🎯 核心业务模块(绿纤ERP业务逻辑)
  36 +│ │ ├── NCC.Extend/ # 业务服务层
  37 +│ │ ├── NCC.Extend.Entitys/ # 实体模型层
  38 +│ │ └── NCC.Extend.Interfaces/ # 接口定义层
  39 +│ ├── OAuth/ # 身份认证模块
  40 +│ ├── Message/ # 消息中心模块
  41 +│ ├── Order/ # 订单管理模块
  42 +│ ├── VisualDev/ # 可视化开发模块
  43 +│ └── Tenant/ # 多租户支持模块
  44 +├── antis-ncc-admin/ # 前端Vue项目
  45 +│ ├── src/
  46 +│ │ ├── api/ # API接口
  47 +│ │ ├── components/ # 公共组件
  48 +│ │ ├── views/ # 页面视图
  49 +│ │ │ ├── lqBmzb/ # 部门管理页面
  50 +│ │ │ ├── lqCpxx/ # 产品信息页面
  51 +│ │ │ ├── lqHygl/ # 会员管理页面
  52 +│ │ │ └── ... # 其他业务页面
  53 +│ │ ├── router/ # 路由配置
  54 +│ │ └── store/ # 状态管理
  55 +│ ├── package.json # 前端依赖配置
  56 +│ └── vue.config.js # Vue构建配置
  57 +└── html/ # 静态资源
  58 +```
  59 +
  60 +## 🎯 核心业务模块说明
  61 +
  62 +**Extend模块**是系统的核心业务模块,包含绿纤ERP的所有业务逻辑。该模块采用三层架构设计:
  63 +
  64 +### NCC.Extend(业务服务层)
  65 +包含所有业务服务的具体实现,按功能分类:
  66 +
  67 +#### 📋 基础管理类
  68 +- `LqBmzbService` - 部门管理服务
  69 +- `LqCpxxService` - 产品信息管理服务
  70 +- `LqHyglService` - 会员管理服务
  71 +- `LqKhxxService` - 客户信息管理服务
  72 +- `LqRyzlService` - 人员资料管理服务
  73 +
  74 +#### 🏭 生产管理类
  75 +- `LqJsfaService` - 工艺方案管理服务
  76 +- `LqSbtjbService` - 设备统计管理服务
  77 +- `LqYcsdJsjService` - 技术数据管理服务
  78 +- `LqYcsdJjlftjsService` - 技术方案管理服务
  79 +- `LqYcsdMdlbjhsxxService` - 模具管理服务
  80 +
  81 +#### 💰 销售管理类
  82 +- `LqXhHyhkService` - 销售回款管理服务
  83 +- `LqXhmxbService` - 销售明细管理服务
  84 +- `LqTkXscService` - 提成管理服务
  85 +- `LqTkjlbService` - 提成记录管理服务
  86 +
  87 +#### 📦 库存管理类
  88 +- `LqKqhzbService` - 库存汇总管理服务
  89 +- `LqLssjService` - 历史数据管理服务
  90 +- `LqYjmxbService` - 原料明细管理服务
  91 +
  92 +#### 📊 财务管理类
  93 +- `LqSkzhService` - 收款账户管理服务
  94 +- `LqHzfService` - 汇总费用管理服务
  95 +- `LqJdqdService` - 季度清单管理服务
  96 +
  97 +#### 🔧 系统工具类
  98 +- `EmailService` - 邮件服务
  99 +- `DocumentService` - 文档管理服务
  100 +- `BigDataService` - 大数据分析服务
  101 +- `WorkLogService` - 工作日志服务
  102 +
  103 +### NCC.Extend.Entitys(实体模型层)
  104 +- **Entity/** - 数据库实体模型(66个实体)
  105 +- **Dto/** - 数据传输对象(304个DTO)
  106 +- **Mapper/** - 对象映射配置(50个映射器)
  107 +- **Model/** - 业务模型类
  108 +
  109 +### NCC.Extend.Interfaces(接口定义层)
  110 +- 定义所有业务服务的接口契约
  111 +- 支持依赖注入和单元测试
  112 +- 提供清晰的业务边界
  113 +
  114 +## 环境要求
  115 +
  116 +### 开发环境
  117 +- **Node.js**: 16.20.2 (必须使用此版本)
  118 +- **.NET Core SDK**: 3.1 或 5.0
  119 +- **MySQL**: 5.7 或 8.0
  120 +- **Visual Studio 2019/2022** 或 **VS Code**
  121 +
  122 +### 浏览器支持
  123 +- Chrome 70+
  124 +- Firefox 65+
  125 +- Safari 12+
  126 +- Edge 79+
  127 +
  128 +## 快速开始
  129 +
  130 +### 1. 克隆项目
  131 +```bash
  132 +git clone [项目地址]
  133 +cd lvqianmeiye_ERP
  134 +```
  135 +
  136 +### 2. 后端启动
  137 +
  138 +#### 方式一:Visual Studio
  139 +1. 打开 `netcore/smart.agriculture.platform.NET.sln`
  140 +2. 设置 `NCC.API` 为启动项目
  141 +3. 按 F5 运行
  142 +
  143 +#### 方式二:命令行
  144 +```bash
  145 +cd netcore/src/Application/NCC.API
  146 +dotnet restore
  147 +dotnet run
  148 +```
  149 +
  150 +### 3. 前端启动
  151 +
  152 +```bash
  153 +cd antis-ncc-admin
  154 +
  155 +# 安装依赖
  156 +npm install
  157 +
  158 +# 启动开发服务器
  159 +npm run dev
  160 +```
  161 +
  162 +### 4. 访问系统
  163 +- 前端地址:http://localhost:3000
  164 +- 后端API:http://localhost:5000
  165 +- API文档:http://localhost:5000/antis.doc
  166 +
  167 +## 默认账号
  168 +
  169 +- **管理员账号**:admin
  170 +- **默认密码**:123456
  171 +
  172 +## 主要功能模块
  173 +
  174 +> 💡 **说明**:所有业务功能的核心代码都位于 `netcore/src/Modularity/Extend/` 模块中
  175 +
  176 +### 📋 基础管理模块
  177 +- **部门管理** (`LqBmzbService`) - 组织架构管理,部门分类维护
  178 +- **产品信息** (`LqCpxxService`) - 产品档案管理,产品分类维护
  179 +- **会员管理** (`LqHyglService`) - 客户信息管理,会员等级维护
  180 +- **客户信息** (`LqKhxxService`) - 客户档案管理,客户关系维护
  181 +- **人员资料** (`LqRyzlService`) - 员工信息管理,人员档案维护
  182 +
  183 +### 🏭 生产管理模块
  184 +- **工艺方案** (`LqJsfaService`) - 生产工艺配置,工艺流程管理
  185 +- **设备统计** (`LqSbtjbService`) - 设备使用情况统计,设备维护管理
  186 +- **技术数据** (`LqYcsdJsjService`) - 技术参数管理,工艺数据维护
  187 +- **技术方案** (`LqYcsdJjlftjsService`) - 技术方案管理,工艺优化
  188 +- **模具管理** (`LqYcsdMdlbjhsxxService`) - 模具档案管理,模具维护
  189 +
  190 +### 💰 销售管理模块
  191 +- **销售回款** (`LqXhHyhkService`) - 销售回款管理,资金回笼跟踪
  192 +- **销售明细** (`LqXhmxbService`) - 销售明细管理,销售数据分析
  193 +- **提成管理** (`LqTkXscService`) - 销售提成计算,提成规则维护
  194 +- **提成记录** (`LqTkjlbService`) - 提成记录管理,提成发放跟踪
  195 +
  196 +### 📦 库存管理模块
  197 +- **库存汇总** (`LqKqhzbService`) - 库存数据分析,库存统计报表
  198 +- **历史数据** (`LqLssjService`) - 历史数据管理,数据归档
  199 +- **原料明细** (`LqYjmxbService`) - 原料库存管理,原料使用跟踪
  200 +
  201 +### 📊 财务管理模块
  202 +- **收款账户** (`LqSkzhService`) - 收款账户管理,资金账户维护
  203 +- **汇总费用** (`LqHzfService`) - 费用汇总管理,成本分析
  204 +- **季度清单** (`LqJdqdService`) - 季度财务清单,财务报告
  205 +
  206 +### 🔧 系统工具模块
  207 +- **邮件服务** (`EmailService`) - 邮件发送,通知提醒
  208 +- **文档管理** (`DocumentService`) - 文档存储,文件管理
  209 +- **大数据分析** (`BigDataService`) - 数据分析,报表生成
  210 +- **工作日志** (`WorkLogService`) - 工作日志记录,操作跟踪
  211 +
  212 +### ⚙️ 系统管理模块(位于System模块)
  213 +- **用户管理** - 系统用户维护,用户权限管理
  214 +- **角色权限** - 权限分配管理,角色权限配置
  215 +- **系统配置** - 系统参数设置,基础配置维护
  216 +- **日志管理** - 操作日志查看,系统日志分析
  217 +
  218 +## 开发指南
  219 +
  220 +### 🎯 核心业务开发(Extend模块)
  221 +
  222 +#### 添加新的业务服务
  223 +1. **创建实体模型** (`NCC.Extend.Entitys/Entity/`)
  224 + ```csharp
  225 + [SugarTable("lq_新表名")]
  226 + [Tenant(ClaimConst.TENANT_ID)]
  227 + public class Lq新实体Entity
  228 + {
  229 + [SugarColumn(ColumnName = "F_Id", IsPrimaryKey = true)]
  230 + public string Id { get; set; }
  231 + // 其他字段...
  232 + }
  233 + ```
  234 +
  235 +2. **创建DTO对象** (`NCC.Extend.Entitys/Dto/`)
  236 + - `Lq新实体ListQueryInput` - 列表查询输入
  237 + - `Lq新实体CrInput` - 创建输入
  238 + - `Lq新实体UpInput` - 更新输入
  239 + - `Lq新实体InfoOutput` - 详情输出
  240 + - `Lq新实体ListOutput` - 列表输出
  241 +
  242 +3. **创建接口定义** (`NCC.Extend.Interfaces/`)
  243 + ```csharp
  244 + public interface ILq新实体Service : ITransient
  245 + {
  246 + Task<dynamic> GetInfo(string id);
  247 + Task<dynamic> GetList(Lq新实体ListQueryInput input);
  248 + Task Create(Lq新实体CrInput input);
  249 + Task Update(string id, Lq新实体UpInput input);
  250 + Task Delete(string id);
  251 + }
  252 + ```
  253 +
  254 +4. **实现业务服务** (`NCC.Extend/`)
  255 + ```csharp
  256 + [ApiDescriptionSettings(Tag = "Extend", Name = "Lq新实体", Order = 200)]
  257 + [Route("api/Extend/[controller]")]
  258 + public class Lq新实体Service : ILq新实体Service, IDynamicApiController, ITransient
  259 + {
  260 + // 服务实现...
  261 + }
  262 + ```
  263 +
  264 +#### 前端页面开发
  265 +1. **创建页面组件** (`antis-ncc-admin/src/views/lq新模块/`)
  266 + - `index.vue` - 列表页面
  267 + - `Form.vue` - 表单页面
  268 + - `ExportBox.vue` - 导出组件
  269 +
  270 +2. **添加API接口** (`antis-ncc-admin/src/api/extend/`)
  271 + ```javascript
  272 + export function getLq新实体List(data) {
  273 + return request({
  274 + url: '/api/Extend/Lq新实体',
  275 + method: 'GET',
  276 + data
  277 + })
  278 + }
  279 + ```
  280 +
  281 +### 前端开发
  282 +```bash
  283 +# 开发模式
  284 +npm run dev
  285 +
  286 +# 构建生产版本
  287 +npm run build
  288 +
  289 +# 代码检查
  290 +npm run lint
  291 +```
  292 +
  293 +### 后端开发
  294 +```bash
  295 +# 还原包
  296 +dotnet restore
  297 +
  298 +# 编译项目
  299 +dotnet build
  300 +
  301 +# 运行项目
  302 +dotnet run
  303 +
  304 +# 发布项目
  305 +dotnet publish -c Release
  306 +```
  307 +
  308 +## 配置说明
  309 +
  310 +### 数据库配置
  311 +修改 `netcore/src/Application/NCC.API/appsettings.json` 中的连接字符串:
  312 +
  313 +```json
  314 +{
  315 + "ConnectionStrings": {
  316 + "DefaultConnection": "Database=lqerp;Data Source=localhost;Port=3306;User Id=root;Password=yourpassword;Charset=utf8;"
  317 + }
  318 +}
  319 +```
  320 +
  321 +### 前端代理配置
  322 +修改 `antis-ncc-admin/vue.config.js` 中的代理地址:
  323 +
  324 +```javascript
  325 +proxy: {
  326 + '/dev': {
  327 + target: 'http://localhost:5000', // 后端API地址
  328 + changeOrigin: true,
  329 + pathRewrite: {
  330 + '^/dev': ''
  331 + }
  332 + }
  333 +}
  334 +```
  335 +
  336 +## 部署说明
  337 +
  338 +### 后端部署
  339 +1. 发布项目:`dotnet publish -c Release`
  340 +2. 配置数据库连接字符串
  341 +3. 部署到IIS或Linux服务器
  342 +
  343 +### 前端部署
  344 +1. 构建项目:`npm run build`
  345 +2. 将 `dist` 目录部署到Web服务器
  346 +3. 配置Nginx或IIS反向代理
  347 +
  348 +## 常见问题
  349 +
  350 +### Q: 前端启动失败
  351 +A: 确保使用Node.js 16.20.2版本,其他版本可能不兼容
  352 +
  353 +### Q: 后端连接数据库失败
  354 +A: 检查数据库连接字符串和MySQL服务状态
  355 +
  356 +### Q: 权限验证失败
  357 +A: 检查JWT配置和Token有效期设置
  358 +
  359 +### Q: 页面显示异常
  360 +A: 检查浏览器控制台错误信息和网络请求状态
  361 +
  362 +## 技术支持
  363 +
  364 +如有技术问题,请联系开发团队或查看项目文档。
  365 +
  366 +## 版本信息
  367 +
  368 +- **当前版本**:v1.0.0
  369 +- **最后更新**:2024年
  370 +- **维护状态**:活跃开发中
  371 +
  372 +---
  373 +
  374 +**注意**:本项目仅供学习和内部使用,请勿用于商业用途。
... ...
analyze_excel.py 0 → 100644
  1 +#!/usr/bin/env python3
  2 +# -*- coding: utf-8 -*-
  3 +"""
  4 +Excel工资核算文件分析工具
  5 +分析工资核算相关的Excel文件,提取字段信息和引用关系
  6 +"""
  7 +
  8 +import pandas as pd
  9 +import os
  10 +import re
  11 +from pathlib import Path
  12 +
  13 +def analyze_excel_file(file_path, sheet_name=None):
  14 + """分析单个Excel文件"""
  15 + try:
  16 + # 获取所有工作表名称
  17 + excel_file = pd.ExcelFile(file_path)
  18 + sheets = excel_file.sheet_names
  19 +
  20 + print(f"\n=== 分析文件: {os.path.basename(file_path)} ===")
  21 + print(f"工作表数量: {len(sheets)}")
  22 + print(f"工作表名称: {sheets}")
  23 +
  24 + analysis_result = {
  25 + 'file_name': os.path.basename(file_path),
  26 + 'sheets': {},
  27 + 'all_columns': set(),
  28 + 'formulas': [],
  29 + 'references': []
  30 + }
  31 +
  32 + # 分析每个工作表
  33 + for sheet in sheets:
  34 + if sheet_name and sheet != sheet_name:
  35 + continue
  36 +
  37 + try:
  38 + df = pd.read_excel(file_path, sheet_name=sheet, header=0)
  39 + print(f"\n--- 工作表: {sheet} ---")
  40 + print(f"行数: {len(df)}")
  41 + print(f"列数: {len(df.columns)}")
  42 + print(f"列名: {list(df.columns)}")
  43 +
  44 + # 收集列名
  45 + analysis_result['all_columns'].update(df.columns)
  46 + analysis_result['sheets'][sheet] = {
  47 + 'rows': len(df),
  48 + 'columns': len(df.columns),
  49 + 'column_names': list(df.columns),
  50 + 'sample_data': df.head(3).to_dict('records') if len(df) > 0 else []
  51 + }
  52 +
  53 + # 查找公式和引用
  54 + for col in df.columns:
  55 + for idx, value in df[col].items():
  56 + if pd.notna(value) and isinstance(value, str):
  57 + # 查找Excel公式模式
  58 + formula_patterns = [
  59 + r'=([A-Z]+[0-9]+)', # 单元格引用
  60 + r'=([A-Z]+[0-9]+:[A-Z]+[0-9]+)', # 范围引用
  61 + r'=([A-Z]+[0-9]+\[[^\]]+\])', # 数组引用
  62 + r'=([A-Z]+[0-9]+\$[0-9]+)', # 绝对引用
  63 + r'=([A-Z]+[0-9]+:[A-Z]+[0-9]+\$[0-9]+)', # 绝对范围引用
  64 + ]
  65 +
  66 + for pattern in formula_patterns:
  67 + matches = re.findall(pattern, str(value))
  68 + if matches:
  69 + analysis_result['formulas'].append({
  70 + 'sheet': sheet,
  71 + 'cell': f"{col}{idx+1}",
  72 + 'formula': str(value),
  73 + 'references': matches
  74 + })
  75 + analysis_result['references'].extend(matches)
  76 +
  77 + except Exception as e:
  78 + print(f"分析工作表 {sheet} 时出错: {e}")
  79 + analysis_result['sheets'][sheet] = {'error': str(e)}
  80 +
  81 + return analysis_result
  82 +
  83 + except Exception as e:
  84 + print(f"分析文件 {file_path} 时出错: {e}")
  85 + return None
  86 +
  87 +def main():
  88 + """主函数"""
  89 + base_path = "/Users/mr.wang/代码库/绿纤/lvqianmeiye_ERP/参考资料/工资核算 -7月"
  90 +
  91 + # 要分析的文件列表
  92 + files_to_analyze = [
  93 + "工资(全字段).xlsx",
  94 + "①B-a-26考勤汇总表.xlsx",
  95 + "②B-a-17每日早报.xlsx",
  96 + "③B-a-③呈现-消耗明细表.xlsx",
  97 + "④B-a-25社保统计表.xlsx",
  98 + "⑤B-a-12奖励统计表.xlsx",
  99 + "B-b-③健康师底薪.xlsx",
  100 + "B-b-④健康师提成-金三角顾问.xlsx",
  101 + "B-b-⑤其他岗位工资.xlsx",
  102 + "B-b-⑤当月数据及门店毛利.xlsx"
  103 + ]
  104 +
  105 + all_results = {}
  106 +
  107 + print("开始分析工资核算Excel文件...")
  108 + print("=" * 60)
  109 +
  110 + for filename in files_to_analyze:
  111 + file_path = os.path.join(base_path, filename)
  112 + if os.path.exists(file_path):
  113 + result = analyze_excel_file(file_path)
  114 + if result:
  115 + all_results[filename] = result
  116 + else:
  117 + print(f"文件不存在: {filename}")
  118 +
  119 + # 生成分析报告
  120 + generate_report(all_results)
  121 +
  122 +def generate_report(all_results):
  123 + """生成分析报告"""
  124 + report_path = "/Users/mr.wang/代码库/绿纤/lvqianmeiye_ERP/工资核算Excel分析报告.md"
  125 +
  126 + with open(report_path, 'w', encoding='utf-8') as f:
  127 + f.write("# 工资核算Excel文件分析报告\n\n")
  128 + f.write("## 概述\n\n")
  129 + f.write("本报告分析了工资核算相关的Excel文件,提取了字段信息、公式引用关系等关键数据。\n\n")
  130 +
  131 + # 文件概览
  132 + f.write("## 文件概览\n\n")
  133 + f.write("| 文件名 | 工作表数量 | 总列数 | 状态 |\n")
  134 + f.write("|--------|------------|--------|------|\n")
  135 +
  136 + for filename, result in all_results.items():
  137 + if result:
  138 + sheet_count = len(result['sheets'])
  139 + total_columns = len(result['all_columns'])
  140 + f.write(f"| {filename} | {sheet_count} | {total_columns} | ✅ |\n")
  141 + else:
  142 + f.write(f"| {filename} | - | - | ❌ |\n")
  143 +
  144 + # 详细分析
  145 + f.write("\n## 详细分析\n\n")
  146 +
  147 + for filename, result in all_results.items():
  148 + if not result:
  149 + continue
  150 +
  151 + f.write(f"### {filename}\n\n")
  152 +
  153 + # 工作表信息
  154 + f.write("#### 工作表信息\n\n")
  155 + for sheet_name, sheet_info in result['sheets'].items():
  156 + if 'error' in sheet_info:
  157 + f.write(f"- **{sheet_name}**: 分析出错 - {sheet_info['error']}\n")
  158 + else:
  159 + f.write(f"- **{sheet_name}**: {sheet_info['rows']}行 x {sheet_info['columns']}列\n")
  160 + f.write(f" - 列名: {', '.join([str(col) for col in sheet_info['column_names']])}\n")
  161 +
  162 + # 字段统计
  163 + f.write(f"\n#### 字段统计\n\n")
  164 + f.write(f"总字段数: {len(result['all_columns'])}\n\n")
  165 + f.write("所有字段列表:\n")
  166 + for col in sorted(result['all_columns'], key=str):
  167 + f.write(f"- {col}\n")
  168 +
  169 + # 公式引用
  170 + if result['formulas']:
  171 + f.write(f"\n#### 公式引用\n\n")
  172 + f.write(f"发现 {len(result['formulas'])} 个公式引用:\n\n")
  173 + for formula in result['formulas'][:10]: # 只显示前10个
  174 + f.write(f"- **{formula['cell']}** ({formula['sheet']}): {formula['formula']}\n")
  175 + f.write(f" - 引用: {', '.join(formula['references'])}\n")
  176 +
  177 + if len(result['formulas']) > 10:
  178 + f.write(f"\n... 还有 {len(result['formulas']) - 10} 个公式\n")
  179 +
  180 + f.write("\n---\n\n")
  181 +
  182 + # 字段汇总
  183 + f.write("## 字段汇总\n\n")
  184 + all_columns = set()
  185 + for result in all_results.values():
  186 + if result:
  187 + all_columns.update(result['all_columns'])
  188 +
  189 + f.write(f"所有文件共发现 {len(all_columns)} 个唯一字段:\n\n")
  190 + for col in sorted(all_columns, key=str):
  191 + f.write(f"- {col}\n")
  192 +
  193 + # 引用关系汇总
  194 + f.write("\n## 引用关系汇总\n\n")
  195 + all_references = set()
  196 + for result in all_results.values():
  197 + if result:
  198 + all_references.update(result['references'])
  199 +
  200 + f.write(f"发现 {len(all_references)} 个唯一引用:\n\n")
  201 + for ref in sorted(all_references, key=str):
  202 + f.write(f"- {ref}\n")
  203 +
  204 + print(f"\n分析报告已生成: {report_path}")
  205 +
  206 +if __name__ == "__main__":
  207 + main()
... ...
analyze_formulas.py 0 → 100644
  1 +#!/usr/bin/env python3
  2 +# -*- coding: utf-8 -*-
  3 +"""
  4 +Excel公式分析工具
  5 +分析工资核算Excel文件中的公式和引用关系
  6 +"""
  7 +
  8 +import pandas as pd
  9 +import openpyxl
  10 +import os
  11 +import re
  12 +from pathlib import Path
  13 +
  14 +def extract_formulas_from_excel(file_path):
  15 + """从Excel文件中提取所有公式"""
  16 + try:
  17 + # 使用openpyxl读取Excel文件以获取公式
  18 + workbook = openpyxl.load_workbook(file_path, data_only=False)
  19 +
  20 + formulas = []
  21 + references = []
  22 +
  23 + for sheet_name in workbook.sheetnames:
  24 + worksheet = workbook[sheet_name]
  25 +
  26 + for row in worksheet.iter_rows():
  27 + for cell in row:
  28 + if cell.data_type == 'f': # 公式类型
  29 + formula = str(cell.value)
  30 + cell_ref = f"{sheet_name}!{cell.coordinate}"
  31 +
  32 + # 提取公式中的引用
  33 + refs = extract_references_from_formula(formula)
  34 +
  35 + formulas.append({
  36 + 'file': os.path.basename(file_path),
  37 + 'sheet': sheet_name,
  38 + 'cell': cell.coordinate,
  39 + 'formula': formula,
  40 + 'references': refs
  41 + })
  42 +
  43 + references.extend(refs)
  44 +
  45 + return formulas, references
  46 +
  47 + except Exception as e:
  48 + print(f"分析文件 {file_path} 时出错: {e}")
  49 + return [], []
  50 +
  51 +def extract_references_from_formula(formula):
  52 + """从公式中提取引用关系"""
  53 + references = []
  54 +
  55 + # 匹配各种引用模式
  56 + patterns = [
  57 + # XLOOKUP引用模式
  58 + r"XLOOKUP\([^,]+,\s*'([^']+)'!([^,]+),\s*'([^']+)'!([^,]+)",
  59 + # VLOOKUP引用模式
  60 + r"VLOOKUP\([^,]+,\s*'([^']+)'!([^,]+)",
  61 + # 直接工作表引用
  62 + r"'([^']+)'!([A-Z]+\d+)",
  63 + # 工作表范围引用
  64 + r"'([^']+)'!([A-Z]+\d+:[A-Z]+\d+)",
  65 + # 简单单元格引用
  66 + r"([A-Z]+\d+)",
  67 + # 范围引用
  68 + r"([A-Z]+\d+:[A-Z]+\d+)",
  69 + ]
  70 +
  71 + for pattern in patterns:
  72 + matches = re.findall(pattern, formula)
  73 + for match in matches:
  74 + if isinstance(match, tuple):
  75 + if len(match) == 2:
  76 + references.append({
  77 + 'type': 'worksheet_reference',
  78 + 'file': match[0] if match[0] else None,
  79 + 'range': match[1]
  80 + })
  81 + elif len(match) == 4:
  82 + references.append({
  83 + 'type': 'xlookup_reference',
  84 + 'file': match[0],
  85 + 'lookup_range': match[1],
  86 + 'file2': match[2],
  87 + 'return_range': match[3]
  88 + })
  89 + else:
  90 + references.append({
  91 + 'type': 'cell_reference',
  92 + 'range': match
  93 + })
  94 +
  95 + return references
  96 +
  97 +def analyze_formula_dependencies(formulas):
  98 + """分析公式依赖关系"""
  99 + dependencies = {}
  100 +
  101 + for formula in formulas:
  102 + cell_key = f"{formula['file']}!{formula['sheet']}!{formula['cell']}"
  103 + dependencies[cell_key] = {
  104 + 'formula': formula['formula'],
  105 + 'dependencies': formula['references']
  106 + }
  107 +
  108 + return dependencies
  109 +
  110 +def generate_formula_report(formulas, references, dependencies):
  111 + """生成公式分析报告"""
  112 + report_path = "/Users/mr.wang/代码库/绿纤/lvqianmeiye_ERP/Excel公式分析报告.md"
  113 +
  114 + with open(report_path, 'w', encoding='utf-8') as f:
  115 + f.write("# Excel公式分析报告\n\n")
  116 + f.write("## 概述\n\n")
  117 + f.write("本报告分析了工资核算Excel文件中的公式和引用关系,帮助理解数据计算逻辑。\n\n")
  118 +
  119 + # 统计信息
  120 + f.write("## 统计信息\n\n")
  121 + f.write(f"- 总公式数量: {len(formulas)}\n")
  122 + f.write(f"- 总引用数量: {len(references)}\n")
  123 + f.write(f"- 涉及文件数量: {len(set(f['file'] for f in formulas))}\n\n")
  124 +
  125 + # 按文件分组分析
  126 + files = {}
  127 + for formula in formulas:
  128 + file_name = formula['file']
  129 + if file_name not in files:
  130 + files[file_name] = []
  131 + files[file_name].append(formula)
  132 +
  133 + f.write("## 文件公式分析\n\n")
  134 +
  135 + for file_name, file_formulas in files.items():
  136 + f.write(f"### {file_name}\n\n")
  137 + f.write(f"公式数量: {len(file_formulas)}\n\n")
  138 +
  139 + # 按工作表分组
  140 + sheets = {}
  141 + for formula in file_formulas:
  142 + sheet_name = formula['sheet']
  143 + if sheet_name not in sheets:
  144 + sheets[sheet_name] = []
  145 + sheets[sheet_name].append(formula)
  146 +
  147 + for sheet_name, sheet_formulas in sheets.items():
  148 + f.write(f"#### 工作表: {sheet_name}\n\n")
  149 + f.write(f"公式数量: {len(sheet_formulas)}\n\n")
  150 +
  151 + # 显示前10个公式
  152 + for i, formula in enumerate(sheet_formulas[:10]):
  153 + f.write(f"**{formula['cell']}**:\n")
  154 + f.write(f"```\n{formula['formula']}\n```\n")
  155 +
  156 + if formula['references']:
  157 + f.write("引用关系:\n")
  158 + for ref in formula['references']:
  159 + if ref['type'] == 'xlookup_reference':
  160 + f.write(f"- XLOOKUP: {ref['file']}!{ref['lookup_range']} -> {ref['file2']}!{ref['return_range']}\n")
  161 + elif ref['type'] == 'worksheet_reference':
  162 + f.write(f"- 工作表引用: {ref['file']}!{ref['range']}\n")
  163 + elif ref['type'] == 'cell_reference':
  164 + f.write(f"- 单元格引用: {ref['range']}\n")
  165 + f.write("\n")
  166 + else:
  167 + f.write("无外部引用\n\n")
  168 +
  169 + if len(sheet_formulas) > 10:
  170 + f.write(f"... 还有 {len(sheet_formulas) - 10} 个公式\n\n")
  171 +
  172 + f.write("---\n\n")
  173 +
  174 + # 引用关系汇总
  175 + f.write("## 引用关系汇总\n\n")
  176 +
  177 + # 统计引用类型
  178 + ref_types = {}
  179 + for ref in references:
  180 + ref_type = ref['type']
  181 + if ref_type not in ref_types:
  182 + ref_types[ref_type] = 0
  183 + ref_types[ref_type] += 1
  184 +
  185 + f.write("### 引用类型统计\n\n")
  186 + for ref_type, count in ref_types.items():
  187 + f.write(f"- {ref_type}: {count} 个\n")
  188 + f.write("\n")
  189 +
  190 + # 外部文件引用
  191 + external_refs = {}
  192 + for ref in references:
  193 + if ref['type'] == 'xlookup_reference' and ref['file']:
  194 + file_name = ref['file']
  195 + if file_name not in external_refs:
  196 + external_refs[file_name] = []
  197 + external_refs[file_name].append(ref)
  198 +
  199 + if external_refs:
  200 + f.write("### 外部文件引用\n\n")
  201 + for file_name, refs in external_refs.items():
  202 + f.write(f"**{file_name}**: {len(refs)} 个引用\n")
  203 + for ref in refs[:5]: # 只显示前5个
  204 + f.write(f"- {ref['file']}!{ref['lookup_range']} -> {ref['file2']}!{ref['return_range']}\n")
  205 + if len(refs) > 5:
  206 + f.write(f"... 还有 {len(refs) - 5} 个引用\n")
  207 + f.write("\n")
  208 +
  209 + # 公式依赖关系图
  210 + f.write("## 公式依赖关系\n\n")
  211 + f.write("### 关键公式分析\n\n")
  212 +
  213 + # 找出包含XLOOKUP的公式
  214 + xlookup_formulas = [f for f in formulas if 'XLOOKUP' in f['formula']]
  215 +
  216 + if xlookup_formulas:
  217 + f.write("#### XLOOKUP公式分析\n\n")
  218 + for formula in xlookup_formulas[:10]:
  219 + f.write(f"**{formula['file']}!{formula['sheet']}!{formula['cell']}**:\n")
  220 + f.write(f"```\n{formula['formula']}\n```\n")
  221 +
  222 + # 解析XLOOKUP参数
  223 + xlookup_match = re.search(r"XLOOKUP\(([^,]+),\s*'([^']+)'!([^,]+),\s*'([^']+)'!([^,]+)", formula['formula'])
  224 + if xlookup_match:
  225 + lookup_value = xlookup_match.group(1).strip()
  226 + lookup_file = xlookup_match.group(2)
  227 + lookup_range = xlookup_match.group(3)
  228 + return_file = xlookup_match.group(4)
  229 + return_range = xlookup_match.group(5)
  230 +
  231 + f.write("参数解析:\n")
  232 + f.write(f"- 查找值: {lookup_value}\n")
  233 + f.write(f"- 查找范围: {lookup_file}!{lookup_range}\n")
  234 + f.write(f"- 返回范围: {return_file}!{return_range}\n")
  235 + f.write("\n")
  236 +
  237 + # 数据流分析
  238 + f.write("### 数据流向分析\n\n")
  239 + f.write("基于公式分析,数据流向如下:\n\n")
  240 +
  241 + # 分析数据源文件
  242 + data_sources = set()
  243 + for ref in references:
  244 + if ref['type'] == 'xlookup_reference' and ref['file']:
  245 + data_sources.add(ref['file'])
  246 +
  247 + f.write("**数据源文件**:\n")
  248 + for source in sorted(data_sources):
  249 + f.write(f"- {source}\n")
  250 + f.write("\n")
  251 +
  252 + f.write("**数据流向**:\n")
  253 + f.write("1. 基础数据从各数据源文件获取\n")
  254 + f.write("2. 通过XLOOKUP/VLOOKUP函数进行数据匹配\n")
  255 + f.write("3. 在工资核算表中进行汇总计算\n")
  256 + f.write("4. 生成最终的工资计算结果\n\n")
  257 +
  258 + return report_path
  259 +
  260 +def main():
  261 + """主函数"""
  262 + base_path = "/Users/mr.wang/代码库/绿纤/lvqianmeiye_ERP/参考资料/工资核算 -7月"
  263 +
  264 + # 要分析的文件列表
  265 + files_to_analyze = [
  266 + "工资(全字段).xlsx",
  267 + "①B-a-26考勤汇总表.xlsx",
  268 + "②B-a-17每日早报.xlsx",
  269 + "③B-a-③呈现-消耗明细表.xlsx",
  270 + "④B-a-25社保统计表.xlsx",
  271 + "⑤B-a-12奖励统计表.xlsx",
  272 + "B-b-③健康师底薪.xlsx",
  273 + "B-b-④健康师提成-金三角顾问.xlsx",
  274 + "B-b-⑤其他岗位工资.xlsx",
  275 + "B-b-⑤当月数据及门店毛利.xlsx"
  276 + ]
  277 +
  278 + all_formulas = []
  279 + all_references = []
  280 +
  281 + print("开始分析Excel公式...")
  282 + print("=" * 60)
  283 +
  284 + for filename in files_to_analyze:
  285 + file_path = os.path.join(base_path, filename)
  286 + if os.path.exists(file_path):
  287 + print(f"正在分析: {filename}")
  288 + formulas, references = extract_formulas_from_excel(file_path)
  289 + all_formulas.extend(formulas)
  290 + all_references.extend(references)
  291 + print(f" 发现 {len(formulas)} 个公式")
  292 + else:
  293 + print(f"文件不存在: {filename}")
  294 +
  295 + # 分析依赖关系
  296 + dependencies = analyze_formula_dependencies(all_formulas)
  297 +
  298 + # 生成报告
  299 + report_path = generate_formula_report(all_formulas, all_references, dependencies)
  300 +
  301 + print(f"\n公式分析完成!")
  302 + print(f"总公式数量: {len(all_formulas)}")
  303 + print(f"总引用数量: {len(all_references)}")
  304 + print(f"分析报告: {report_path}")
  305 +
  306 +if __name__ == "__main__":
  307 + main()
... ...
antis-ncc-admin/.DS_Store
No preview for this file type
antis-ncc-admin/.nvmrc 0 → 100644
  1 +16.20.2
  2 +
... ...
antis-ncc-admin/package-lock.json
... ... @@ -13634,6 +13634,14 @@
13634 13634 "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
13635 13635 "dev": true
13636 13636 },
  13637 + "node_modules/nan": {
  13638 + "version": "2.23.0",
  13639 + "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.0.tgz",
  13640 + "integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==",
  13641 + "dev": true,
  13642 + "license": "MIT",
  13643 + "optional": true
  13644 + },
13637 13645 "node_modules/nanomatch": {
13638 13646 "version": "1.2.13",
13639 13647 "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
... ... @@ -27809,6 +27817,7 @@
27809 27817 },
27810 27818 "eve": {
27811 27819 "version": "git+ssh://git@github.com/adobe-webplatform/eve.git#eef80ed8d188423c2272746fb8ae5cc8dad84cb1",
  27820 + "integrity": "sha512-VrMCMjRWGSuyiV/1SP58K4lIui3jlfD3uBapV8jahx9/RsqZad/FL7Tq5NRTHWFI8yd1dVLgUrEDPrA70gnOTw==",
27812 27821 "from": "eve@git://github.com/adobe-webplatform/eve.git#eef80ed"
27813 27822 },
27814 27823 "event-pubsub": {
... ... @@ -32943,6 +32952,13 @@
32943 32952 "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=",
32944 32953 "dev": true
32945 32954 },
  32955 + "nan": {
  32956 + "version": "2.23.0",
  32957 + "resolved": "https://registry.npmjs.org/nan/-/nan-2.23.0.tgz",
  32958 + "integrity": "sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==",
  32959 + "dev": true,
  32960 + "optional": true
  32961 + },
32946 32962 "nanomatch": {
32947 32963 "version": "1.2.13",
32948 32964 "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
... ... @@ -36827,6 +36843,7 @@
36827 36843 },
36828 36844 "squire-rte": {
36829 36845 "version": "git+ssh://git@github.com/sohee-lee7/Squire.git#b1e0e1031fa18912d233c204cbe7c7fae4a42621",
  36846 + "integrity": "sha512-/1Wi323QPO3AmcGOXjliEp2Kqzse6/BbCyCj/lw0R0M/zS+7IFm1LnBlgMlfa1yLXRjNcc5PcmE2vnwA4Zlhkg==",
36830 36847 "from": "squire-rte@github:sohee-lee7/Squire#b1e0e1031fa18912d233c204cbe7c7fae4a42621"
36831 36848 },
36832 36849 "sshpk": {
... ...
antis-ncc-admin/package.json
... ... @@ -6,6 +6,7 @@
6 6 "license": "MIT",
7 7 "scripts": {
8 8 "dev": "vue-cli-service serve --open",
  9 + "dev:legacy": "NODE_OPTIONS=\"--openssl-legacy-provider\" vue-cli-service serve --open",
9 10 "build": "cross-env NODE_ENV=production vue-cli-service build",
10 11 "build:staging": "cross-env NODE_ENV=production vue-cli-service build --mode staging",
11 12 "build:javaBootDev": "cross-env NODE_ENV=production vue-cli-service build --mode javaBootDev",
... ...
antis-ncc-admin/start-dev.sh 0 → 100755
  1 +#!/bin/bash
  2 +
  3 +# 绿纤ERP前端启动脚本
  4 +echo "🚀 启动绿纤ERP前端项目..."
  5 +
  6 +# 检查nvm是否安装
  7 +if ! command -v nvm &> /dev/null; then
  8 + echo "❌ nvm未安装,请先安装nvm"
  9 + exit 1
  10 +fi
  11 +
  12 +# 切换到项目目录
  13 +cd "$(dirname "$0")"
  14 +
  15 +# 使用nvm切换到指定Node.js版本
  16 +echo "📦 切换到Node.js 16.20.2..."
  17 +nvm use
  18 +
  19 +# 检查Node.js版本
  20 +echo "✅ 当前Node.js版本: $(node --version)"
  21 +
  22 +# 安装依赖(如果需要)
  23 +if [ ! -d "node_modules" ]; then
  24 + echo "📥 安装项目依赖..."
  25 + npm install
  26 +fi
  27 +
  28 +# 启动开发服务器
  29 +echo "🌐 启动前端开发服务器..."
  30 +echo "📍 访问地址: http://localhost:3000"
  31 +echo "🛑 按 Ctrl+C 停止服务"
  32 +echo ""
  33 +
  34 +npm run dev
  35 +
... ...
netcore/.DS_Store
No preview for this file type
netcore/src/.DS_Store
No preview for this file type
netcore/src/Application/.DS_Store
No preview for this file type
netcore/src/Application/NCC.API.Core/Startup.cs
... ... @@ -30,6 +30,7 @@ using Antis.Pay.Core.Interface;
30 30 using Antis.Pay.Core;
31 31 using Microsoft.AspNetCore.Http;
32 32 using Microsoft.AspNetCore.Http.Features;
  33 +using NCC.Extend.Utils;
33 34  
34 35 namespace NCC.API.Core
35 36 {
... ... @@ -58,6 +59,12 @@ namespace NCC.API.Core
58 59 services.AddConfigurableOptions<CacheOptions>();
59 60 //使用微信支付实现
60 61 services.AddScoped<IWePay, WePay>();
  62 +
  63 + // 注册企业微信机器人服务
  64 + services.AddHttpClient<WeChatBotService>();
  65 +
  66 + // 注册开单记录字符串生成器
  67 + services.AddScoped<LqKdKdjlbStringGenerator>();
61 68  
62 69 services.AddControllersWithViews()
63 70 .AddMvcFilter<RequestActionFilter>()
... ...
netcore/src/Modularity/Extend/NCC.Extend/LqKdKdjlbService.cs
... ... @@ -22,6 +22,8 @@ using NCC.Common.Model.NPOI;
22 22 using NCC.Common.Configuration;
23 23 using NCC.DataEncryption;
24 24 using NCC.ClayObject;
  25 +using NCC.Extend.Utils;
  26 +using System.Net.Http;
25 27  
26 28 namespace NCC.Extend.LqKdKdjlb
27 29 {
... ... @@ -38,6 +40,8 @@ namespace NCC.Extend.LqKdKdjlb
38 40 private readonly ISqlSugarRepository<LqKdPxmxEntity> _lqKdPxmxRepository;
39 41 private readonly SqlSugarScope _db;
40 42 private readonly IUserManager _userManager;
  43 + private readonly WeChatBotService _weChatBotService;
  44 + private readonly LqKdKdjlbStringGenerator _stringGenerator;
41 45  
42 46 /// <summary>
43 47 /// 初始化一个<see cref="LqKdKdjlbService"/>类型的新实例
... ... @@ -47,7 +51,9 @@ namespace NCC.Extend.LqKdKdjlb
47 51 ISqlSugarRepository<LqKdJksyjEntity> lqKdJksyjRepository,
48 52 ISqlSugarRepository<LqKdKjbsyjEntity> lqKdKjbsyjRepository,
49 53 ISqlSugarRepository<LqKdPxmxEntity> lqKdPxmxRepository,
50   - IUserManager userManager)
  54 + IUserManager userManager,
  55 + WeChatBotService weChatBotService,
  56 + LqKdKdjlbStringGenerator stringGenerator)
51 57 {
52 58 _lqKdKdjlbRepository = lqKdKdjlbRepository;
53 59 _db = _lqKdKdjlbRepository.Context;
... ... @@ -55,6 +61,8 @@ namespace NCC.Extend.LqKdKdjlb
55 61 _lqKdKjbsyjRepository = lqKdKjbsyjRepository;
56 62 _lqKdPxmxRepository = lqKdPxmxRepository;
57 63 _userManager = userManager;
  64 + _weChatBotService = weChatBotService;
  65 + _stringGenerator = stringGenerator;
58 66 }
59 67  
60 68 /// <summary>
... ... @@ -203,6 +211,41 @@ namespace NCC.Extend.LqKdKdjlb
203 211  
204 212 //关闭事务
205 213 _db.CommitTran();
  214 +
  215 + // 生成开单记录字符串并发送到企业微信
  216 + try
  217 + {
  218 + var entityInfo = await GetInfo(newEntity.Id);
  219 + if (entityInfo != null)
  220 + {
  221 + var orderRecordString = _stringGenerator.GenerateOrderRecordString(entityInfo);
  222 + Console.WriteLine("开单记录字符串生成成功:");
  223 + Console.WriteLine(orderRecordString);
  224 +
  225 + // 发送到企业微信群
  226 + try
  227 + {
  228 + var sendResult = await _weChatBotService.SendOrderRecordMessage(orderRecordString);
  229 + if (sendResult)
  230 + {
  231 + Console.WriteLine("开单记录已成功发送到企业微信群");
  232 + }
  233 + else
  234 + {
  235 + Console.WriteLine("开单记录发送到企业微信群失败");
  236 + }
  237 + }
  238 + catch (Exception wechatEx)
  239 + {
  240 + Console.WriteLine($"发送企业微信消息异常: {wechatEx.Message}");
  241 + }
  242 + }
  243 + }
  244 + catch (Exception ex)
  245 + {
  246 + // 字符串生成失败不影响主流程,只记录日志
  247 + Console.WriteLine($"生成开单记录字符串失败: {ex.Message}");
  248 + }
206 249 }
207 250 catch (Exception)
208 251 {
... ... @@ -473,5 +516,6 @@ namespace NCC.Extend.LqKdKdjlb
473 516 throw NCCException.Oh(ErrorCode.COM1002);
474 517 }
475 518 }
  519 +
476 520 }
477 521 }
... ...
netcore/src/Modularity/Extend/NCC.Extend/Utils/LqKdKdjlbStringGenerator.cs 0 → 100644
  1 +using System;
  2 +using System.Collections.Generic;
  3 +using System.Linq;
  4 +using System.Text;
  5 +using NCC.Extend.Entitys.Dto.LqKdKdjlb;
  6 +using NCC.Extend.Entitys;
  7 +using NCC.System.Entitys.Permission;
  8 +using SqlSugar;
  9 +
  10 +namespace NCC.Extend.Utils
  11 +{
  12 + /// <summary>
  13 + /// 开单记录字符串生成器
  14 + /// </summary>
  15 + public class LqKdKdjlbStringGenerator
  16 + {
  17 + private readonly ISqlSugarClient _db;
  18 +
  19 + public LqKdKdjlbStringGenerator(ISqlSugarClient db)
  20 + {
  21 + _db = db;
  22 + }
  23 +
  24 + /// <summary>
  25 + /// 生成开单记录字符串
  26 + /// </summary>
  27 + /// <param name="entity">开单记录实体</param>
  28 + /// <returns>格式化的字符串</returns>
  29 + public string GenerateOrderRecordString(LqKdKdjlbInfoOutput entity)
  30 + {
  31 + if (entity == null)
  32 + {
  33 + return string.Empty;
  34 + }
  35 + var sb = new StringBuilder();
  36 + // 店名:龙城国际店 - 获取显示名称
  37 + var storeName = GetStoreDisplayName(entity.djmd);
  38 + sb.AppendLine($"⏩店名:{storeName}");
  39 + // 金三角:ko队 - 获取部门显示名称
  40 + var departmentName = GetDepartmentDisplayName(entity.jsj);
  41 + sb.AppendLine($"⏩金三角:{departmentName}");
  42 + // 顾客姓名:高华 - 通过客户ID查询客户名称
  43 + var customerName = GetCustomerName(entity.kdhy);
  44 + sb.AppendLine($"⏩顾客姓名:{customerName}");
  45 + // 健康师:王维
  46 + var healthTeachers = GetHealthTeachers(entity.lqKdJksyjList);
  47 + sb.AppendLine($"⏩健康师:{healthTeachers}");
  48 +
  49 + // 活动方案:532工程
  50 + sb.AppendLine($"⏩活动方案:{entity.pxxx ?? "无"}");
  51 +
  52 + // 跟单配合:王经理 竹主任 陈思思老师
  53 + var techTeachers = GetTechTeachers(entity.lqKdKjbsyjList);
  54 + sb.AppendLine($"⏩跟单配合:{techTeachers}");
  55 +
  56 + // 业绩:4800
  57 + sb.AppendLine($"⏩业绩:{entity.zdyj}");
  58 +
  59 + // 实付:4800
  60 + sb.AppendLine($"⏩实付:{entity.sfyj}");
  61 +
  62 + // 欠款:
  63 + sb.AppendLine($"⏩欠款: {entity.qk}");
  64 +
  65 + // 抵扣:
  66 + sb.AppendLine($"⏩抵扣:{entity.ckmx ?? "无"}");
  67 +
  68 + // 来源:售后
  69 + sb.AppendLine($"⏩来源:{entity.khly ?? "无"}");
  70 +
  71 + // 是否属于升单:
  72 + sb.AppendLine($"⏩是否属于升单:{entity.sfskdd ?? "无"}");
  73 +
  74 + // 简介:高姐是我们的老客,今天邀约到犀浦店做532,维维全程陪同,陈思思老师在操作过程中给姐姐分享企业文化,找到顾客需求、邀请王经理 竹主任 给到顾客福利、顾客爽快成交,私密档案已了解到70%,感谢顾客的信任与支持 ,王经理 竹主任 陈老师辛苦了[玫瑰]维维真棒[强]龙城国际店加油!我们还在努力中!家人们给我们打气加油👏👏👏👏等待我们的捷报👍👍
  75 + sb.AppendLine($"⏩简介:{entity.jj ?? "无"}");
  76 +
  77 + return sb.ToString();
  78 + }
  79 +
  80 + /// <summary>
  81 + /// 获取门店显示名称
  82 + /// </summary>
  83 + /// <param name="storeCode">门店编码</param>
  84 + /// <returns>门店显示名称</returns>
  85 + private string GetStoreDisplayName(string storeCode)
  86 + {
  87 + if (string.IsNullOrEmpty(storeCode))
  88 + {
  89 + return "无";
  90 + }
  91 +
  92 + try
  93 + {
  94 + var store = _db.Queryable<LqMdxxEntity>()
  95 + .Where(x => x.Mdbm == storeCode)
  96 + .First();
  97 +
  98 + return store?.Dm ?? storeCode;
  99 + }
  100 + catch
  101 + {
  102 + return storeCode;
  103 + }
  104 + }
  105 +
  106 + /// <summary>
  107 + /// 获取部门显示名称
  108 + /// </summary>
  109 + /// <param name="departmentCode">部门编码</param>
  110 + /// <returns>部门显示名称</returns>
  111 + private string GetDepartmentDisplayName(string departmentCode)
  112 + {
  113 + if (string.IsNullOrEmpty(departmentCode))
  114 + {
  115 + return "无";
  116 + }
  117 +
  118 + try
  119 + {
  120 + var department = _db.Queryable<LqYcsdJsjEntity>()
  121 + .Where(x => x.Id == departmentCode)
  122 + .First();
  123 +
  124 + return department?.Jsj ?? departmentCode;
  125 + }
  126 + catch
  127 + {
  128 + return departmentCode;
  129 + }
  130 + }
  131 +
  132 + /// <summary>
  133 + /// 获取健康师信息
  134 + /// </summary>
  135 + /// <param name="healthTeacherList">健康师列表</param>
  136 + /// <returns>健康师姓名字符串</returns>
  137 + private string GetHealthTeachers(List<LqKdJksyjInfoOutput> healthTeacherList)
  138 + {
  139 + if (healthTeacherList == null || !healthTeacherList.Any())
  140 + {
  141 + return "无";
  142 + }
  143 +
  144 + var names = new List<string>();
  145 + foreach (var teacher in healthTeacherList)
  146 + {
  147 + if (!string.IsNullOrEmpty(teacher.jks))
  148 + {
  149 + // 通过账号查询用户真实姓名
  150 + var realName = GetUserRealNameByAccount(teacher.jks);
  151 + if (!string.IsNullOrEmpty(realName))
  152 + {
  153 + names.Add(realName);
  154 + }
  155 + }
  156 + else if (!string.IsNullOrEmpty(teacher.jksxm))
  157 + {
  158 + // 如果没有账号,使用原有的姓名字段
  159 + names.Add(teacher.jksxm);
  160 + }
  161 + }
  162 +
  163 + return names.Distinct().Any() ? string.Join(" ", names.Distinct()) : "无";
  164 + }
  165 +
  166 + /// <summary>
  167 + /// 获取科技部老师信息
  168 + /// </summary>
  169 + /// <param name="techTeacherList">科技部老师列表</param>
  170 + /// <returns>科技部老师姓名字符串</returns>
  171 + private string GetTechTeachers(List<LqKdKjbsyjInfoOutput> techTeacherList)
  172 + {
  173 + if (techTeacherList == null || !techTeacherList.Any())
  174 + {
  175 + return "无";
  176 + }
  177 +
  178 + var names = new List<string>();
  179 + foreach (var teacher in techTeacherList)
  180 + {
  181 + if (!string.IsNullOrEmpty(teacher.kjbls))
  182 + {
  183 + // 通过账号查询用户真实姓名
  184 + var realName = GetUserRealNameByAccount(teacher.kjbls);
  185 + if (!string.IsNullOrEmpty(realName))
  186 + {
  187 + names.Add(realName);
  188 + }
  189 + }
  190 + else if (!string.IsNullOrEmpty(teacher.kjblsxm))
  191 + {
  192 + // 如果没有账号,使用原有的姓名字段
  193 + names.Add(teacher.kjblsxm);
  194 + }
  195 + }
  196 +
  197 + return names.Distinct().Any() ? string.Join(" ", names.Distinct()) : "无";
  198 + }
  199 +
  200 + /// <summary>
  201 + /// 获取客户名称
  202 + /// </summary>
  203 + /// <param name="customerId">客户ID</param>
  204 + /// <returns>客户名称</returns>
  205 + private string GetCustomerName(string customerId)
  206 + {
  207 + if (string.IsNullOrEmpty(customerId))
  208 + {
  209 + return "无";
  210 + }
  211 +
  212 + try
  213 + {
  214 + var customer = _db.Queryable<LqKhxxEntity>()
  215 + .Where(x => x.Id == customerId)
  216 + .First();
  217 +
  218 + return customer?.Khmc ?? "无";
  219 + }
  220 + catch
  221 + {
  222 + return "无";
  223 + }
  224 + }
  225 +
  226 + /// <summary>
  227 + /// 通过账号查询用户真实姓名
  228 + /// </summary>
  229 + /// <param name="account">用户账号</param>
  230 + /// <returns>用户真实姓名</returns>
  231 + private string GetUserRealNameByAccount(string account)
  232 + {
  233 + if (string.IsNullOrEmpty(account))
  234 + {
  235 + return string.Empty;
  236 + }
  237 +
  238 + try
  239 + {
  240 + var user = _db.Queryable<UserEntity>()
  241 + .Where(x => x.Account == account && x.DeleteMark == null)
  242 + .First();
  243 +
  244 + return user?.RealName ?? string.Empty;
  245 + }
  246 + catch
  247 + {
  248 + return string.Empty;
  249 + }
  250 + }
  251 +
  252 + }
  253 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotService.cs 0 → 100644
  1 +using System;
  2 +using System.Net.Http;
  3 +using System.Text;
  4 +using System.Threading.Tasks;
  5 +using Newtonsoft.Json;
  6 +
  7 +namespace NCC.Extend.Utils
  8 +{
  9 + /// <summary>
  10 + /// 企业微信机器人服务
  11 + /// </summary>
  12 + public class WeChatBotService
  13 + {
  14 + private readonly HttpClient _httpClient;
  15 + private const string BOT_API_URL = "http://wx.lvqianmeiye.com/api/Bot/send-text";
  16 + private const string WEBHOOK_URL = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=6f8686ec-5011-4c1d-bae9-d82a2a2f4d83";
  17 +
  18 + public WeChatBotService(HttpClient httpClient)
  19 + {
  20 + _httpClient = httpClient;
  21 + }
  22 +
  23 + /// <summary>
  24 + /// 发送文本消息到企业微信群
  25 + /// </summary>
  26 + /// <param name="content">消息内容</param>
  27 + /// <returns>发送结果</returns>
  28 + public async Task<bool> SendTextMessage(string content)
  29 + {
  30 + try
  31 + {
  32 + var requestData = new
  33 + {
  34 + webhookUrl = WEBHOOK_URL,
  35 + content = content,
  36 + mentionedList = (string)null,
  37 + mentionedMobileList = (string)null
  38 + };
  39 +
  40 + var json = JsonConvert.SerializeObject(requestData);
  41 + var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
  42 +
  43 + var response = await _httpClient.PostAsync(BOT_API_URL, httpContent);
  44 +
  45 + if (response.IsSuccessStatusCode)
  46 + {
  47 + var responseContent = await response.Content.ReadAsStringAsync();
  48 + Console.WriteLine($"企业微信消息发送成功: {responseContent}");
  49 + return true;
  50 + }
  51 + else
  52 + {
  53 + var errorContent = await response.Content.ReadAsStringAsync();
  54 + Console.WriteLine($"企业微信消息发送失败: {response.StatusCode} - {errorContent}");
  55 + return false;
  56 + }
  57 + }
  58 + catch (Exception ex)
  59 + {
  60 + Console.WriteLine($"企业微信消息发送异常: {ex.Message}");
  61 + return false;
  62 + }
  63 + }
  64 +
  65 + /// <summary>
  66 + /// 发送开单记录消息
  67 + /// </summary>
  68 + /// <param name="orderRecordString">开单记录字符串</param>
  69 + /// <returns>发送结果</returns>
  70 + public async Task<bool> SendOrderRecordMessage(string orderRecordString)
  71 + {
  72 + if (string.IsNullOrEmpty(orderRecordString))
  73 + {
  74 + Console.WriteLine("开单记录字符串为空,跳过发送");
  75 + return false;
  76 + }
  77 +
  78 + // 添加标题和格式化
  79 + var messageContent = $"🎉 新开单记录\n\n{orderRecordString}";
  80 +
  81 + return await SendTextMessage(messageContent);
  82 + }
  83 + }
  84 +}
... ...
netcore/src/Modularity/Extend/NCC.Extend/Utils/WeChatBotTestController.cs 0 → 100644
  1 +using Microsoft.AspNetCore.Mvc;
  2 +using NCC.DynamicApiController;
  3 +using NCC.Dependency;
  4 +using System.Threading.Tasks;
  5 +using System.Collections.Generic;
  6 +using NCC.Extend.Entitys.Dto.LqKdKdjlb;
  7 +
  8 +namespace NCC.Extend.Utils
  9 +{
  10 + /// <summary>
  11 + /// 企业微信机器人测试控制器
  12 + /// </summary>
  13 + [ApiDescriptionSettings(Tag = "Extend", Name = "WeChatBotTest", Order = 200)]
  14 + [Route("api/Extend/[controller]")]
  15 + public class WeChatBotTestController : IDynamicApiController, ITransient
  16 + {
  17 + private readonly WeChatBotService _weChatBotService;
  18 + private readonly LqKdKdjlbStringGenerator _stringGenerator;
  19 +
  20 + public WeChatBotTestController(WeChatBotService weChatBotService, LqKdKdjlbStringGenerator stringGenerator)
  21 + {
  22 + _weChatBotService = weChatBotService;
  23 + _stringGenerator = stringGenerator;
  24 + }
  25 +
  26 + /// <summary>
  27 + /// 测试发送文本消息
  28 + /// </summary>
  29 + /// <param name="content">消息内容</param>
  30 + /// <returns>发送结果</returns>
  31 + [HttpPost("SendText")]
  32 + public async Task<bool> SendTextMessage(string content = "这是一条测试消息")
  33 + {
  34 + return await _weChatBotService.SendTextMessage(content);
  35 + }
  36 +
  37 + /// <summary>
  38 + /// 测试发送开单记录消息
  39 + /// </summary>
  40 + /// <returns>发送结果</returns>
  41 + [HttpPost("SendOrderRecord")]
  42 + public async Task<bool> SendOrderRecordMessage()
  43 + {
  44 + var testOrderRecord = @"----------------
  45 +⏩店名:测试门店
  46 +⏩金三角:测试团队
  47 +⏩顾客姓名:测试客户
  48 +⏩健康师:测试健康师
  49 +⏩活动方案:测试方案
  50 +⏩跟单配合:测试配合
  51 +⏩业绩:1000
  52 +⏩实付:1000
  53 +⏩欠款: 0
  54 +⏩抵扣:无
  55 +⏩来源:测试来源
  56 +⏩是否属于升单:无
  57 +⏩简介:这是一条测试开单记录";
  58 +
  59 + return await _weChatBotService.SendOrderRecordMessage(testOrderRecord);
  60 + }
  61 +
  62 + /// <summary>
  63 + /// 测试字符串生成器(验证显示名称功能)
  64 + /// </summary>
  65 + /// <returns>生成的字符串</returns>
  66 + [HttpPost("TestStringGenerator")]
  67 + public string TestStringGenerator()
  68 + {
  69 + // 创建测试数据
  70 + var testEntity = new LqKdKdjlbInfoOutput
  71 + {
  72 + id = "test001",
  73 + djmd = "TEST001", // 门店编码
  74 + jsj = "DEPT001", // 部门编码
  75 + kdhy = "CUSTOMER001", // 客户ID
  76 + kdhyc = "测试客户",
  77 + pxxx = "测试方案",
  78 + zdyj = 1000,
  79 + sfyj = 1000,
  80 + qk = 0,
  81 + ckmx = "无",
  82 + khly = "测试来源",
  83 + sfskdd = "无",
  84 + jj = "这是一条测试开单记录",
  85 + lqKdJksyjList = new List<LqKdJksyjInfoOutput>
  86 + {
  87 + new LqKdJksyjInfoOutput { jks = "test_health_1", jksxm = "测试健康师1" },
  88 + new LqKdJksyjInfoOutput { jks = "test_health_2", jksxm = "测试健康师2" }
  89 + },
  90 + lqKdKjbsyjList = new List<LqKdKjbsyjInfoOutput>
  91 + {
  92 + new LqKdKjbsyjInfoOutput { kjbls = "test_tech_1", kjblsxm = "测试科技部1" },
  93 + new LqKdKjbsyjInfoOutput { kjbls = "test_tech_2", kjblsxm = "测试科技部2" }
  94 + }
  95 + };
  96 +
  97 + return _stringGenerator.GenerateOrderRecordString(testEntity);
  98 + }
  99 + }
  100 +}
... ...
参考资料/.DS_Store 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/.DS_Store 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/B-b-③健康师底薪.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/B-b-④健康师提成-金三角顾问.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/B-b-⑤其他岗位工资.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/B-b-⑤当月数据及门店毛利.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/①B-a-26考勤汇总表.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/②B-a-17每日早报.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/③B-a-③呈现-消耗明细表.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/④B-a-25社保统计表.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/⑤B-a-12奖励统计表.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/外部表单/2025年7月工资(2)(3)(2) 的副本-郭主管8-14.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/外部表单/2025年7月工资表 的副本-张总裁.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/外部表单/7月-考勤.xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/工资(全字段).xlsx 0 → 100644
No preview for this file type
参考资料/工资核算 -7月/流程-工资核算的相关表格及sop流程.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/.DS_Store 0 → 100644
No preview for this file type
参考资料/整体-8.15/2025嘉宾挑战V4.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-a前置信息/A-a-①前置信息-门店资料(确定版)-8.5更新.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-a前置信息/A-a-②前置信息-人员资料-8.10更新.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-a前置信息/A-a-③前置信息-项目资料(7-24更新).xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-a前置信息/A-a-④前置信息-客户资料-8.5更新.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-a前置信息/A-a-⑤前置信息-历史数据2024.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-a前置信息/A-a-⑥前置信息-信息字典-8.5更新.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-a前置信息/A-a-⑦前置信息-营销活动方案.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-a前置信息/A-a-⑧前置信息-产品资料-8.5更新.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-b每月月初设定/①门店目标设定.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-b每月月初设定/②金三角设定.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-b每月月初设定/④社保增减-8.5新增.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-b每月月初设定/⑤门店类别及核算信息.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-b每月月初设定/⑥工资核算浮动条件设置.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-b每月月初设定/⑦总经理经理核算条件.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-b每月月初设定/⑧毛巾品类及单价设定.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/.DS_Store 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-10社保变动-8.5新增.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-①请假.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-②人员调动.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-③宿舍.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑤业务操作-6个版块/.DS_Store 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑤业务操作-6个版块/副本播报-字段(1).xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑤业务操作-6个版块/拓客字段-报表-奖励-科目/拓客汇总表【带奖励】.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑤业务操作-6个版块/拓客字段-报表-奖励-科目/插件②-拓客.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑤业务操作-6个版块/插件-预约.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑤业务操作-6个版块/消耗.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑤业务操作-6个版块/退卡.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑤业务操作-6个版块/邀约字段-报表/插件③-邀约.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑥报销及明细上传.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑧毛巾的收发登记.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/A-c日常操作/A-c-⑨每日工作-科技部.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/B-a-报表字段/B-a-⑧每日早报.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/B-a-报表字段/B-a-(①-16)报表字段及股份字段.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/B-b-②股份核算套表-8.8.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/增加/A-a-①-增加.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/增加/A-a-②-增加.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/增加/A-b-②-增加.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/增加/A-b-⑨-增加.xlsx 0 → 100644
No preview for this file type
参考资料/整体-8.15/整体-(8-14更新).xlsx 0 → 100644
No preview for this file type