init
This commit is contained in:
commit
b551b4016c
150
.gitignore
vendored
Normal file
150
.gitignore
vendored
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, built with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
# Dependency directories (remove the comment below to include it)
|
||||||
|
# vendor/
|
||||||
|
|
||||||
|
# Go workspace file
|
||||||
|
go.work
|
||||||
|
go.work.sum
|
||||||
|
|
||||||
|
# Build output
|
||||||
|
/bin/
|
||||||
|
/build/
|
||||||
|
/dist/
|
||||||
|
|
||||||
|
# IDE files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS generated files
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
._*
|
||||||
|
.Spotlight-V100
|
||||||
|
.Trashes
|
||||||
|
ehthumbs.db
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Log files
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# Environment variables
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development
|
||||||
|
.env.test
|
||||||
|
.env.production
|
||||||
|
|
||||||
|
# Configuration files with sensitive data
|
||||||
|
config/local.yaml
|
||||||
|
config/production.yaml
|
||||||
|
config/development.yaml
|
||||||
|
config/*.local.yaml
|
||||||
|
|
||||||
|
# Database files
|
||||||
|
*.db
|
||||||
|
*.sqlite
|
||||||
|
*.sqlite3
|
||||||
|
|
||||||
|
# Temporary files
|
||||||
|
tmp/
|
||||||
|
temp/
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# Coverage reports
|
||||||
|
coverage.txt
|
||||||
|
coverage.html
|
||||||
|
coverage.out
|
||||||
|
|
||||||
|
# Air live reload tool
|
||||||
|
tmp/
|
||||||
|
|
||||||
|
# Delve debugger
|
||||||
|
__debug_bin
|
||||||
|
|
||||||
|
# GoLand
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# VS Code
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Emacs
|
||||||
|
*~
|
||||||
|
\#*\#
|
||||||
|
/.emacs.desktop
|
||||||
|
/.emacs.desktop.lock
|
||||||
|
*.elc
|
||||||
|
auto-save-list
|
||||||
|
tramp
|
||||||
|
.\#*
|
||||||
|
|
||||||
|
# Vim
|
||||||
|
[._]*.s[a-v][a-z]
|
||||||
|
[._]*.sw[a-p]
|
||||||
|
[._]s[a-rt-v][a-z]
|
||||||
|
[._]ss[a-gi-z]
|
||||||
|
[._]sw[a-p]
|
||||||
|
|
||||||
|
# JetBrains IDEs
|
||||||
|
.idea/
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# Local development files
|
||||||
|
*.local
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Kubernetes
|
||||||
|
*.kubeconfig
|
||||||
|
|
||||||
|
# Certificates and keys
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
|
*.crt
|
||||||
|
*.p12
|
||||||
|
*.pfx
|
||||||
|
|
||||||
|
# Backup files
|
||||||
|
*.bak
|
||||||
|
*.backup
|
||||||
|
|
||||||
|
# Node modules (if using any frontend tools)
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Yarn
|
||||||
|
yarn-error.log
|
||||||
|
|
||||||
|
# NPM
|
||||||
|
npm-debug.log*
|
||||||
|
|
||||||
|
# MacOS
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
Desktop.ini
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Linux
|
||||||
|
*~
|
||||||
|
|
||||||
|
# Application specific
|
||||||
|
# Add your application specific ignores here
|
||||||
35
README.md
Normal file
35
README.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# HospitalPay-Go
|
||||||
|
|
||||||
|
医院支付系统后端服务
|
||||||
|
|
||||||
|
## 项目结构
|
||||||
|
|
||||||
|
```
|
||||||
|
├── api # API 接口定义
|
||||||
|
├── cmd # 主程序入口
|
||||||
|
├── config # 配置文件
|
||||||
|
├── internal # 内部包
|
||||||
|
│ ├── handler # HTTP 处理器
|
||||||
|
│ ├── middleware # 中间件
|
||||||
|
│ ├── model # 数据模型
|
||||||
|
│ ├── repository # 数据仓储层
|
||||||
|
│ └── service # 业务逻辑层
|
||||||
|
├── pkg # 可以被外部项目引用的包
|
||||||
|
└── scripts # 脚本文件
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速开始
|
||||||
|
|
||||||
|
1. 安装依赖
|
||||||
|
```bash
|
||||||
|
go mod download
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 运行项目
|
||||||
|
```bash
|
||||||
|
go run cmd/main.go
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
配置文件位于 `config` 目录下,使用 YAML 格式。
|
||||||
48
cmd/main.go
Normal file
48
cmd/main.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/config"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/pkg/database"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/pkg/logger"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/server"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 初始化配置
|
||||||
|
if err := config.Init(); err != nil {
|
||||||
|
log.Fatalf("Failed to initialize config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化日志
|
||||||
|
if err := logger.Init(); err != nil {
|
||||||
|
log.Fatalf("Failed to initialize logger: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化数据库
|
||||||
|
if err := database.Init(); err != nil {
|
||||||
|
logger.Fatalf("Failed to initialize database: %v", err)
|
||||||
|
}
|
||||||
|
defer database.Close()
|
||||||
|
|
||||||
|
// 启动监控服务器
|
||||||
|
if config.GlobalConfig.Monitoring.Enabled {
|
||||||
|
go func() {
|
||||||
|
http.Handle("/metrics", promhttp.Handler())
|
||||||
|
addr := ":" + config.GlobalConfig.Monitoring.PrometheusPort
|
||||||
|
logger.Infof("Starting monitoring server on %s", addr)
|
||||||
|
if err := http.ListenAndServe(addr, nil); err != nil {
|
||||||
|
logger.Fatalf("Failed to start monitoring server: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建并启动 Socket 服务器
|
||||||
|
socketServer := server.NewSocketServer()
|
||||||
|
if err := socketServer.Start(); err != nil {
|
||||||
|
logger.Fatalf("Failed to start socket server: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
48
cmd/main/main.go
Normal file
48
cmd/main/main.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// 加载配置文件
|
||||||
|
viper.SetConfigName("config")
|
||||||
|
viper.SetConfigType("yaml")
|
||||||
|
viper.AddConfigPath("./config")
|
||||||
|
|
||||||
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
|
log.Fatalf("Error reading config file: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 创建 Gin 引擎
|
||||||
|
r := gin.Default()
|
||||||
|
|
||||||
|
// 注册路由
|
||||||
|
setupRoutes(r)
|
||||||
|
|
||||||
|
// 启动服务器
|
||||||
|
port := viper.GetString("server.port")
|
||||||
|
if port == "" {
|
||||||
|
port = "8080"
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.Run(":" + port); err != nil {
|
||||||
|
log.Fatalf("Server failed to start: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupRoutes(r *gin.Engine) {
|
||||||
|
// 健康检查
|
||||||
|
r.GET("/health", func(c *gin.Context) {
|
||||||
|
c.JSON(200, gin.H{
|
||||||
|
"status": "ok",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: 在这里添加其他路由
|
||||||
|
}
|
||||||
44
config/config.yaml
Normal file
44
config/config.yaml
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
server:
|
||||||
|
port: "8080"
|
||||||
|
hospital_code: "9999"
|
||||||
|
mode: "debug" # debug, release, test
|
||||||
|
read_timeout: 30s
|
||||||
|
write_timeout: 30s
|
||||||
|
max_conn_num: 100
|
||||||
|
|
||||||
|
database:
|
||||||
|
driver: "mysql"
|
||||||
|
host: "localhost"
|
||||||
|
port: 3306
|
||||||
|
username: "root"
|
||||||
|
password: "root"
|
||||||
|
dbname: "hospital_pay"
|
||||||
|
charset: "utf8mb4"
|
||||||
|
parseTime: true
|
||||||
|
loc: "Local"
|
||||||
|
max_idle_conns: 10
|
||||||
|
max_open_conns: 100
|
||||||
|
conn_max_lifetime: 3600s
|
||||||
|
|
||||||
|
redis:
|
||||||
|
host: localhost
|
||||||
|
port: 6379
|
||||||
|
password: ""
|
||||||
|
db: 0
|
||||||
|
|
||||||
|
jwt:
|
||||||
|
secret: your-secret-key
|
||||||
|
expire: 24h # token 过期时间
|
||||||
|
|
||||||
|
log:
|
||||||
|
level: "debug" # debug, info, warn, error, fatal
|
||||||
|
format: "json" # json, text
|
||||||
|
output_path: "logs/app.log"
|
||||||
|
max_size: 500 # MB
|
||||||
|
max_age: 28 # 天
|
||||||
|
max_backups: 10
|
||||||
|
compress: true
|
||||||
|
|
||||||
|
monitoring:
|
||||||
|
enabled: true
|
||||||
|
prometheus_port: "9090"
|
||||||
294
doc/api.md
Normal file
294
doc/api.md
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
# 医院支付系统接口文档
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
- [1. 概述](#1-概述)
|
||||||
|
- [2. 通信协议](#2-通信协议)
|
||||||
|
- [3. 接口列表](#3-接口列表)
|
||||||
|
- [4. 错误码说明](#4-错误码说明)
|
||||||
|
- [5. 数据结构](#5-数据结构)
|
||||||
|
- [6. 对接示例](#6-对接示例)
|
||||||
|
|
||||||
|
## 1. 概述
|
||||||
|
|
||||||
|
### 1.1 文档说明
|
||||||
|
本文档详细描述了医院支付系统的接口规范,包括接口定义、参数说明、错误码等信息。
|
||||||
|
|
||||||
|
### 1.2 修订记录
|
||||||
|
| 版本号 | 修订日期 | 修订说明 |
|
||||||
|
|--------|----------|----------|
|
||||||
|
| v1.0.0 | 2024-03-25 | 初始版本 |
|
||||||
|
|
||||||
|
## 2. 通信协议
|
||||||
|
|
||||||
|
### 2.1 基本信息
|
||||||
|
- 通信方式:Socket TCP
|
||||||
|
- 字符编码:UTF-8
|
||||||
|
- 数据格式:JSON
|
||||||
|
- 端口配置:通过配置文件指定
|
||||||
|
|
||||||
|
### 2.2 消息格式
|
||||||
|
|
||||||
|
#### 请求消息格式
|
||||||
|
\`\`\`
|
||||||
|
长度(4位) + 功能码(4位) + 医院编码(4位) + 时间戳(19位) + JSON数据
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
示例:
|
||||||
|
\`\`\`
|
||||||
|
005700059999FJJXYY712024-08-01 09:00:44{"FCode":"3516022343"}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
#### 响应消息格式
|
||||||
|
\`\`\`
|
||||||
|
长度(4位) + JSON数据
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
示例:
|
||||||
|
\`\`\`
|
||||||
|
0216{"ResultCode":"0000","ResultData":{"FCode":"3516022343","FName":null,"AmountA":414.54}}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## 3. 接口列表
|
||||||
|
|
||||||
|
### 3.1 入院登记
|
||||||
|
- **功能码**: 0001
|
||||||
|
- **功能说明**: 病人入院时进行登记
|
||||||
|
- **请求参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"FCode": "string" // 病人编号
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
- **响应参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"ResultCode": "string", // 结果代码
|
||||||
|
"ResultData": {
|
||||||
|
"FCode": "string", // 病人编号
|
||||||
|
"FName": "string", // 病人姓名
|
||||||
|
"AmountA": decimal, // A类金额
|
||||||
|
"AmountB": decimal, // B类金额
|
||||||
|
"AmountC": decimal, // C类金额
|
||||||
|
"BankAccNo": "string", // 银行账号
|
||||||
|
"BankAmount": decimal, // 银行余额
|
||||||
|
"Fflag": int, // 状态标志
|
||||||
|
"Flimitflag": int, // 限制标志
|
||||||
|
"Flimitamt": decimal // 限制金额
|
||||||
|
}
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### 3.2 消费额度查询
|
||||||
|
- **功能码**: 0002
|
||||||
|
- **功能说明**: 查询病人当月消费额度
|
||||||
|
- **请求参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"FCode": "string" // 病人编号
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
- **响应参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"AmountA": decimal, // A类消费金额
|
||||||
|
"AmountB": decimal, // B类消费金额
|
||||||
|
"FreeAmountA": decimal, // A类可用金额
|
||||||
|
"FreeAmountB": decimal, // B类可用金额
|
||||||
|
"Checkflag": int, // 检查标志
|
||||||
|
"FCode": "string", // 病人编号
|
||||||
|
"FCriminal": "string", // 病人姓名
|
||||||
|
"Flag": int // 状态标志
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### 3.3 出院处理
|
||||||
|
- **功能码**: 0003
|
||||||
|
- **功能说明**: 病人出院时的处理
|
||||||
|
- **请求参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"FCode": "string" // 病人编号
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
- **响应参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"Result": boolean, // 处理结果
|
||||||
|
"ReMsg": "string" // 结果消息
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### 3.4 消费记录
|
||||||
|
- **功能码**: 0004
|
||||||
|
- **功能说明**: 记录病人消费信息
|
||||||
|
- **请求参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"FCode": "string", // 病人编号
|
||||||
|
"InvoiceNo": "string", // 发票号
|
||||||
|
"AmountA": decimal, // A类金额
|
||||||
|
"AmountB": decimal, // B类金额
|
||||||
|
"Amount": decimal, // 总金额
|
||||||
|
"FreeAmountA": decimal, // A类可用金额
|
||||||
|
"FreeAmountB": decimal, // B类可用金额
|
||||||
|
"CrtDate": "string", // 创建日期
|
||||||
|
"FCriminal": "string", // 病人姓名
|
||||||
|
"CardCode": "string", // 卡号
|
||||||
|
"OrderId": int // 订单ID
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
- **响应参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"ResultCode": "string", // 结果代码
|
||||||
|
"ResultMsg": "string" // 结果消息
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### 3.5 实时余额查询
|
||||||
|
- **功能码**: 0005
|
||||||
|
- **功能说明**: 查询病人实时余额
|
||||||
|
- **请求参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"FCode": "string" // 病人编号
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
- **响应参数**: 同入院登记响应
|
||||||
|
|
||||||
|
### 3.6 发票同步
|
||||||
|
- **功能码**: 0006
|
||||||
|
- **功能说明**: 同步发票信息
|
||||||
|
- **请求参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"InvoiceList": [
|
||||||
|
"string" // 发票号列表
|
||||||
|
]
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
- **响应参数**:
|
||||||
|
\`\`\`json
|
||||||
|
{
|
||||||
|
"ResultCode": "string",
|
||||||
|
"ResultData": [
|
||||||
|
{
|
||||||
|
"BankFlag": int, // 银行标志
|
||||||
|
"CAmount": decimal, // 金额
|
||||||
|
"FCode": "string", // 病人编号
|
||||||
|
"Origid": "string", // 原始ID
|
||||||
|
"SendDate": "string" // 发送日期
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
## 4. 错误码说明
|
||||||
|
|
||||||
|
| 错误码 | 说明 | 处理建议 |
|
||||||
|
|--------|------|----------|
|
||||||
|
| 0000 | 成功 | - |
|
||||||
|
| 0005 | 未找到病人信息 | 检查病人编号是否正确 |
|
||||||
|
| 0006 | 入院处理失败 | 检查病人状态 |
|
||||||
|
| 0007 | 病人已入院 | 无需重复入院 |
|
||||||
|
| 0008 | 系统异常 | 联系系统管理员 |
|
||||||
|
|
||||||
|
## 5. 数据结构
|
||||||
|
|
||||||
|
### 5.1 金额说明
|
||||||
|
- AmountA: A类金额,用于...
|
||||||
|
- AmountB: B类金额,用于...
|
||||||
|
- AmountC: C类金额,用于...
|
||||||
|
- FreeAmountA: A类可用金额
|
||||||
|
- FreeAmountB: B类可用金额
|
||||||
|
|
||||||
|
### 5.2 状态标志说明
|
||||||
|
- Fflag: 0-正常,1-已入院
|
||||||
|
- Flimitflag: 0-无限制,1-有限制
|
||||||
|
- Checkflag: 检查标志
|
||||||
|
- BankFlag: 银行标志
|
||||||
|
|
||||||
|
## 6. 对接示例
|
||||||
|
|
||||||
|
### 6.1 Go语言示例代码
|
||||||
|
|
||||||
|
\`\`\`go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
func sendRequest(conn net.Conn, functionCode string, hospitalCode string, data interface{}) error {
|
||||||
|
jsonData, err := json.Marshal(data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造消息
|
||||||
|
message := fmt.Sprintf("%04d%s%s%s%s",
|
||||||
|
len(jsonData)+27, // 总长度
|
||||||
|
functionCode, // 功能码
|
||||||
|
hospitalCode, // 医院编码
|
||||||
|
time.Now().Format("2006-01-02 15:04:05"),
|
||||||
|
string(jsonData))
|
||||||
|
|
||||||
|
// 发送消息
|
||||||
|
_, err = conn.Write([]byte(message))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收响应
|
||||||
|
func receiveResponse(conn net.Conn) (string, error) {
|
||||||
|
buffer := make([]byte, 4096)
|
||||||
|
n, err := conn.Read(buffer)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
response := string(buffer[:n])
|
||||||
|
// 解析响应:前4位为长度,之后为JSON数据
|
||||||
|
return response[4:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 建立连接
|
||||||
|
conn, err := net.Dial("tcp", "192.168.1.1:8080")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// 构造请求数据
|
||||||
|
reqData := map[string]string{
|
||||||
|
"FCode": "3516022343",
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送请求
|
||||||
|
err = sendRequest(conn, "0001", "9999", reqData)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接收响应
|
||||||
|
response, err := receiveResponse(conn)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Response:", response)
|
||||||
|
}
|
||||||
|
\`\`\`
|
||||||
|
|
||||||
|
### 6.2 注意事项
|
||||||
|
|
||||||
|
1. 数据传输编码统一使用 UTF-8
|
||||||
|
2. 金额字段使用 decimal 类型,避免浮点数精度问题
|
||||||
|
3. 时间戳格式:2006-01-02 15:04:05
|
||||||
|
4. 建议每次请求建立新的连接
|
||||||
|
5. 注意处理连接超时情况
|
||||||
|
6. 响应码为"0000"时表示处理成功
|
||||||
883
doc/建新接口代码.txt
Normal file
883
doc/建新接口代码.txt
Normal file
@ -0,0 +1,883 @@
|
|||||||
|
// SocketServiceForm.ClientConnection
|
||||||
|
using System;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using JXHospitalWSBLL;
|
||||||
|
using SocketServiceForm;
|
||||||
|
|
||||||
|
public class ClientConnection
|
||||||
|
{
|
||||||
|
private Thread threadClient;
|
||||||
|
|
||||||
|
private Socket socket;
|
||||||
|
|
||||||
|
private Form1 frmMain;
|
||||||
|
|
||||||
|
private bool doesClose;
|
||||||
|
|
||||||
|
public ClientConnection(Form1 f1, Socket socket)
|
||||||
|
{
|
||||||
|
frmMain = f1;
|
||||||
|
this.socket = socket;
|
||||||
|
threadClient = new Thread(MoniterMsg);
|
||||||
|
threadClient.IsBackground = true;
|
||||||
|
threadClient.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MoniterMsg()
|
||||||
|
{
|
||||||
|
while (!doesClose)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] byteMsgRec = new byte[4194304];
|
||||||
|
int length = socket.Receive(byteMsgRec, byteMsgRec.Length, SocketFlags.None);
|
||||||
|
if (length > 0)
|
||||||
|
{
|
||||||
|
string strMsgRec = Encoding.UTF8.GetString(byteMsgRec, 0, length);
|
||||||
|
ShowMsg("从" + socket.RemoteEndPoint.ToString() + "接收消息:" + strMsgRec);
|
||||||
|
strMsgRec.Substring(0, 4);
|
||||||
|
string _JXsendObj = strMsgRec.Substring(4, strMsgRec.Length - 4);
|
||||||
|
string _fun = _JXsendObj.Substring(0, 4);
|
||||||
|
string _obj = _JXsendObj.Substring(35, _JXsendObj.Length - 35);
|
||||||
|
switch (_fun)
|
||||||
|
{
|
||||||
|
case "0001":
|
||||||
|
SendMsg(JXHospitalBLL.CriminalIn(_obj));
|
||||||
|
break;
|
||||||
|
case "0002":
|
||||||
|
SendMsg(JXHospitalBLL.CriminalConsumedQuota(_obj));
|
||||||
|
break;
|
||||||
|
case "0003":
|
||||||
|
SendMsg(JXHospitalBLL.CriminalOut(_obj));
|
||||||
|
break;
|
||||||
|
case "0004":
|
||||||
|
SendMsg(JXHospitalBLL.CriminalConsume(_obj));
|
||||||
|
break;
|
||||||
|
case "0005":
|
||||||
|
SendMsg(JXHospitalBLL.RealTimeBalance(_obj));
|
||||||
|
break;
|
||||||
|
case "0006":
|
||||||
|
SendMsg(JXHospitalBLL.SynInvoiceResult(_obj));
|
||||||
|
break;
|
||||||
|
case "0007":
|
||||||
|
SendMsg(JXHospitalBLL.MonitorSocketResult(_obj));
|
||||||
|
break;
|
||||||
|
case "0008":
|
||||||
|
SendMsg(JXHospitalBLL.CancelOrderResult(_obj));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (socket != null)
|
||||||
|
{
|
||||||
|
ShowErr("客户端" + socket.RemoteEndPoint.ToString() + "断开连接:", ex);
|
||||||
|
}
|
||||||
|
frmMain.RemoveListItem(socket.RemoteEndPoint.ToString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowErr(string msg, Exception ex)
|
||||||
|
{
|
||||||
|
frmMain.ShowErr(msg, ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowMsg(string msg)
|
||||||
|
{
|
||||||
|
frmMain.ShowReqTxt(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SendMsg(string msg)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] msgSendByte = Encoding.UTF8.GetBytes(Encoding.UTF8.GetBytes(msg).Length.ToString("0000") + msg);
|
||||||
|
socket.Send(msgSendByte);
|
||||||
|
ShowMsg("发送消息:" + Encoding.UTF8.GetString(msgSendByte, 0, msgSendByte.Length));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
ShowErr("发送消息:", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
doesClose = true;
|
||||||
|
threadClient.Abort();
|
||||||
|
socket.Shutdown(SocketShutdown.Both);
|
||||||
|
socket.Close();
|
||||||
|
socket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// JXHospitalWSBLL.JXHospitalBLL
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Web.Script.Serialization;
|
||||||
|
using JXHospitalWSBLL;
|
||||||
|
using JXHospitalWSDAL;
|
||||||
|
|
||||||
|
public class JXHospitalBLL
|
||||||
|
{
|
||||||
|
public static string GetSocketIp()
|
||||||
|
{
|
||||||
|
return ConfigurationManager.ConnectionStrings["SocketIP"].ConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetSocketPort()
|
||||||
|
{
|
||||||
|
return ConfigurationManager.ConnectionStrings["SocketPort"].ConnectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CriminalIn(string FCode)
|
||||||
|
{
|
||||||
|
ResponCriminalIn re = new ResponCriminalIn();
|
||||||
|
JavaScriptSerializer jss = new JavaScriptSerializer();
|
||||||
|
ReqFCode _fcode = jss.Deserialize<ReqFCode>(FCode);
|
||||||
|
string errorMsg = "";
|
||||||
|
string errorCode = "";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom();
|
||||||
|
re.ResultData = (from b in db.T_Criminal
|
||||||
|
join c in db.T_Criminal_card on b.FCode equals c.fcrimecode into temp
|
||||||
|
from tt in temp.DefaultIfEmpty()
|
||||||
|
where b.FCode.Equals(_fcode.FCode)
|
||||||
|
select new CriminalEntity
|
||||||
|
{
|
||||||
|
AmountB = ((tt == null) ? 0m : tt.AmountB.Value),
|
||||||
|
AmountC = ((tt == null) ? 0m : tt.AmountC.Value),
|
||||||
|
AmountA = ((tt == null) ? 0m : tt.AmountA.Value),
|
||||||
|
BankAccNo = tt.BankAccNo,
|
||||||
|
BankAmount = ((tt.BankAmount == null) ? 0m : tt.BankAmount.Value),
|
||||||
|
FCode = b.FCode,
|
||||||
|
FName = b.FName,
|
||||||
|
Fflag = (b.fflag.HasValue ? b.fflag.Value : 0),
|
||||||
|
Flimitflag = (b.flimitflag.HasValue ? b.flimitflag.Value : 0),
|
||||||
|
Flimitamt = (b.flimitamt.HasValue ? b.flimitamt.Value : 0m)
|
||||||
|
}).FirstOrDefault();
|
||||||
|
if (re.ResultData == null)
|
||||||
|
{
|
||||||
|
re.ResultCode = "0005";
|
||||||
|
re.ResultData = new CriminalEntity();
|
||||||
|
}
|
||||||
|
else if (re.ResultData.Fflag == 1)
|
||||||
|
{
|
||||||
|
re.ResultCode = "0007";
|
||||||
|
re.ResultData = new CriminalEntity();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
db.proc_CriminalInHospital(_fcode.FCode, ref errorMsg, ref errorCode);
|
||||||
|
if (errorCode == "1")
|
||||||
|
{
|
||||||
|
re.ResultCode = "0000";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
re.ResultCode = "0006";
|
||||||
|
re.ResultData = new CriminalEntity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
re.ResultCode = "0008";
|
||||||
|
re.ResultData = new CriminalEntity();
|
||||||
|
}
|
||||||
|
return jss.Serialize(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CriminalConsumedQuota(string FCode)
|
||||||
|
{
|
||||||
|
InvoiceEntity reModel = new InvoiceEntity();
|
||||||
|
JavaScriptSerializer jss = new JavaScriptSerializer();
|
||||||
|
ReqFCode _fcode = jss.Deserialize<ReqFCode>(FCode);
|
||||||
|
DateTime FirstDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
|
||||||
|
DateTime EndDate = DateTime.Parse(FirstDate.AddMonths(1).ToShortDateString()).AddSeconds(-1.0);
|
||||||
|
using (JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom())
|
||||||
|
{
|
||||||
|
proc_CriminalConsumedResult a = db.proc_CriminalConsumed(_fcode.FCode, FirstDate, EndDate).FirstOrDefault();
|
||||||
|
if (a != null)
|
||||||
|
{
|
||||||
|
InvoiceEntity invoiceEntity = new InvoiceEntity();
|
||||||
|
invoiceEntity.AmountA = Convert.ToDecimal((!a.AmountA.HasValue) ? new decimal?(0m) : a.AmountA);
|
||||||
|
invoiceEntity.AmountB = Convert.ToDecimal((!a.AmountB.HasValue) ? new decimal?(0m) : a.AmountB);
|
||||||
|
invoiceEntity.FreeAmountA = Convert.ToDecimal((!a.FreeAmountA.HasValue) ? new decimal?(0m) : a.FreeAmountA);
|
||||||
|
invoiceEntity.FreeAmountB = Convert.ToDecimal((!a.FreeAmountB.HasValue) ? new decimal?(0m) : a.FreeAmountB);
|
||||||
|
invoiceEntity.Checkflag = a.checkflag.Value;
|
||||||
|
invoiceEntity.FCode = a.fcrimecode;
|
||||||
|
invoiceEntity.FCriminal = a.fcriminal;
|
||||||
|
invoiceEntity.Flag = (a.Flag.HasValue ? a.Flag.Value : 0);
|
||||||
|
reModel = invoiceEntity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return jss.Serialize(reModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CriminalOut(string FCode)
|
||||||
|
{
|
||||||
|
ResultEntity reModel = new ResultEntity();
|
||||||
|
JavaScriptSerializer jss = new JavaScriptSerializer();
|
||||||
|
ReqFCode _fcode = jss.Deserialize<ReqFCode>(FCode);
|
||||||
|
string errorMsg = "";
|
||||||
|
string errorCode = "";
|
||||||
|
using (JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom())
|
||||||
|
{
|
||||||
|
db.proc_CriminalOutHospital(_fcode.FCode, ref errorMsg, ref errorCode);
|
||||||
|
if (errorCode == "1")
|
||||||
|
{
|
||||||
|
reModel.Result = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reModel.Result = false;
|
||||||
|
}
|
||||||
|
reModel.ReMsg = errorMsg;
|
||||||
|
}
|
||||||
|
return jss.Serialize(reModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CriminalConsume(string reqModel)
|
||||||
|
{
|
||||||
|
JavaScriptSerializer jss = new JavaScriptSerializer();
|
||||||
|
ReqInoiveEntity _req = jss.Deserialize<ReqInoiveEntity>(reqModel);
|
||||||
|
ResponNormalModel reModel = new ResponNormalModel();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom())
|
||||||
|
{
|
||||||
|
T_Invoice t_Invoice = new T_Invoice();
|
||||||
|
t_Invoice.InvoiceNo = _req.InvoiceNo;
|
||||||
|
t_Invoice.CardCode = _req.CardCode;
|
||||||
|
t_Invoice.Amount = _req.Amount;
|
||||||
|
t_Invoice.AmountA = _req.AmountA;
|
||||||
|
t_Invoice.AmountB = _req.AmountB;
|
||||||
|
t_Invoice.Checkflag = 0;
|
||||||
|
t_Invoice.Crtby = "建新";
|
||||||
|
t_Invoice.Crtdate = _req.CrtDate;
|
||||||
|
t_Invoice.FCrimeCode = _req.FCode;
|
||||||
|
t_Invoice.FCriminal = _req.FCriminal;
|
||||||
|
t_Invoice.Flag = 1;
|
||||||
|
t_Invoice.FreeAmountA = _req.FreeAmountA;
|
||||||
|
t_Invoice.FreeAmountB = _req.FreeAmountB;
|
||||||
|
t_Invoice.OrderDate = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
|
||||||
|
t_Invoice.OrderId = _req.OrderId;
|
||||||
|
t_Invoice.PayDate = Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"));
|
||||||
|
t_Invoice.PType = "建新消费";
|
||||||
|
t_Invoice.TypeFlag = 30;
|
||||||
|
t_Invoice.OrderStatus = 1;
|
||||||
|
t_Invoice.Fifoflag = -1;
|
||||||
|
T_Invoice invoice = t_Invoice;
|
||||||
|
db.T_Invoice.InsertOnSubmit(invoice);
|
||||||
|
var _criminal = (from crinimal in db.T_Criminal
|
||||||
|
join area in db.T_AREA on crinimal.FAreaCode equals area.FCode into temp
|
||||||
|
from tt in temp.DefaultIfEmpty()
|
||||||
|
where crinimal.FCode.Equals(_req.FCode)
|
||||||
|
select new
|
||||||
|
{
|
||||||
|
FAreaCode = ((crinimal.FAreaCode == null) ? "0" : crinimal.FAreaCode),
|
||||||
|
FAreaName = ((tt.FName == null) ? "0" : tt.FName)
|
||||||
|
}).FirstOrDefault();
|
||||||
|
if (_req.AmountA > 0m)
|
||||||
|
{
|
||||||
|
string vouno = "";
|
||||||
|
db.CREATESEQNO("vouno", 1, ref vouno);
|
||||||
|
T_Vcrd t_Vcrd = new T_Vcrd();
|
||||||
|
t_Vcrd.Vouno = "JXVouNo" + vouno;
|
||||||
|
t_Vcrd.CardCode = _req.CardCode;
|
||||||
|
t_Vcrd.FCrimeCode = _req.FCode;
|
||||||
|
t_Vcrd.DAmount = 0m;
|
||||||
|
t_Vcrd.CAmount = _req.AmountA;
|
||||||
|
t_Vcrd.CrtBy = "建新";
|
||||||
|
t_Vcrd.CrtDate = DateTime.Now;
|
||||||
|
t_Vcrd.DType = "建新消费";
|
||||||
|
t_Vcrd.Depositer = "";
|
||||||
|
t_Vcrd.Flag = 0;
|
||||||
|
t_Vcrd.FCriminal = _req.FCriminal;
|
||||||
|
t_Vcrd.Frealareacode = "";
|
||||||
|
t_Vcrd.FrealAreaName = "";
|
||||||
|
t_Vcrd.PType = "";
|
||||||
|
t_Vcrd.UDate = DateTime.Now;
|
||||||
|
t_Vcrd.OrigId = _req.InvoiceNo;
|
||||||
|
t_Vcrd.CardType = 0;
|
||||||
|
t_Vcrd.TypeFlag = 30;
|
||||||
|
t_Vcrd.AccType = 0;
|
||||||
|
t_Vcrd.BankFlag = 0;
|
||||||
|
t_Vcrd.CheckFlag = 0;
|
||||||
|
t_Vcrd.pc = 0;
|
||||||
|
t_Vcrd.FAreaCode = _criminal.FAreaCode;
|
||||||
|
t_Vcrd.FAreaName = _criminal.FAreaName;
|
||||||
|
t_Vcrd.FinancePayFlag = 0;
|
||||||
|
T_Vcrd vcrd = t_Vcrd;
|
||||||
|
db.T_Vcrd.InsertOnSubmit(vcrd);
|
||||||
|
}
|
||||||
|
if (_req.AmountB > 0m)
|
||||||
|
{
|
||||||
|
string vouno2 = "";
|
||||||
|
db.CREATESEQNO("vouno", 1, ref vouno2);
|
||||||
|
T_Vcrd t_Vcrd2 = new T_Vcrd();
|
||||||
|
t_Vcrd2.Vouno = "JXVouNo" + vouno2;
|
||||||
|
t_Vcrd2.CardCode = _req.CardCode;
|
||||||
|
t_Vcrd2.FCrimeCode = _req.FCode;
|
||||||
|
t_Vcrd2.DAmount = 0m;
|
||||||
|
t_Vcrd2.CAmount = _req.AmountB;
|
||||||
|
t_Vcrd2.CrtBy = "建新";
|
||||||
|
t_Vcrd2.CrtDate = DateTime.Now;
|
||||||
|
t_Vcrd2.DType = "建新消费";
|
||||||
|
t_Vcrd2.Depositer = "";
|
||||||
|
t_Vcrd2.Flag = 0;
|
||||||
|
t_Vcrd2.FCriminal = _req.FCriminal;
|
||||||
|
t_Vcrd2.Frealareacode = "";
|
||||||
|
t_Vcrd2.FrealAreaName = "";
|
||||||
|
t_Vcrd2.PType = "";
|
||||||
|
t_Vcrd2.UDate = DateTime.Now;
|
||||||
|
t_Vcrd2.OrigId = _req.InvoiceNo;
|
||||||
|
t_Vcrd2.CardType = 0;
|
||||||
|
t_Vcrd2.TypeFlag = 30;
|
||||||
|
t_Vcrd2.AccType = 1;
|
||||||
|
t_Vcrd2.BankFlag = 0;
|
||||||
|
t_Vcrd2.CheckFlag = 0;
|
||||||
|
t_Vcrd2.pc = 0;
|
||||||
|
t_Vcrd2.FAreaCode = _criminal.FAreaCode;
|
||||||
|
t_Vcrd2.FAreaName = _criminal.FAreaName;
|
||||||
|
t_Vcrd2.FinancePayFlag = 0;
|
||||||
|
T_Vcrd vcrd2 = t_Vcrd2;
|
||||||
|
db.T_Vcrd.InsertOnSubmit(vcrd2);
|
||||||
|
}
|
||||||
|
T_Criminal_card a = db.T_Criminal_card.Where((T_Criminal_card b) => b.fcrimecode.Equals(_req.FCode)).FirstOrDefault();
|
||||||
|
a.AmountA -= (decimal?)_req.AmountA;
|
||||||
|
a.AmountB -= (decimal?)_req.AmountB;
|
||||||
|
a.BankAmount = a.AmountA + a.AmountB + a.AmountC;
|
||||||
|
db.SubmitChanges();
|
||||||
|
}
|
||||||
|
reModel.ResultCode = "0000";
|
||||||
|
reModel.ResultMsg = "";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
reModel.ResultCode = "0008";
|
||||||
|
reModel.ResultMsg = ex.Message;
|
||||||
|
}
|
||||||
|
return jss.Serialize(reModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string RealTimeBalance(string FCode)
|
||||||
|
{
|
||||||
|
ResponCriminalIn rspModel = new ResponCriminalIn();
|
||||||
|
JavaScriptSerializer jss = new JavaScriptSerializer();
|
||||||
|
ReqFCode _fcode = jss.Deserialize<ReqFCode>(FCode);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom();
|
||||||
|
T_Criminal_card a = db.T_Criminal_card.Where((T_Criminal_card b) => b.fcrimecode.Equals(_fcode.FCode)).FirstOrDefault();
|
||||||
|
if (a != null)
|
||||||
|
{
|
||||||
|
rspModel.ResultData = new CriminalEntity
|
||||||
|
{
|
||||||
|
AmountA = (a.AmountA.HasValue ? a.AmountA.Value : 0m),
|
||||||
|
AmountB = (a.AmountB.HasValue ? a.AmountB.Value : 0m),
|
||||||
|
AmountC = (a.AmountC.HasValue ? a.AmountC.Value : 0m),
|
||||||
|
BankAccNo = a.BankAccNo,
|
||||||
|
BankAmount = (a.BankAmount.HasValue ? a.BankAmount.Value : 0m),
|
||||||
|
FCode = a.fcrimecode
|
||||||
|
};
|
||||||
|
}
|
||||||
|
rspModel.ResultCode = "0000";
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
rspModel.ResultCode = "0008";
|
||||||
|
rspModel.ResultData = new CriminalEntity();
|
||||||
|
}
|
||||||
|
return jss.Serialize(rspModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string SynInvoiceResult(string InvoiceNoList)
|
||||||
|
{
|
||||||
|
JavaScriptSerializer jss = new JavaScriptSerializer();
|
||||||
|
RsponEntity _rsp = new RsponEntity();
|
||||||
|
_rsp.ResultData = new List<RspVcrdEntity>();
|
||||||
|
List<string> _req = jss.Deserialize<List<string>>(InvoiceNoList);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using JXHospitalWSDBDataContextCustom db = new JXHospitalWSDBDataContextCustom();
|
||||||
|
var reList = (from a in db.T_Vcrd
|
||||||
|
where _req.Contains(a.OrigId)
|
||||||
|
group a by new { a.CardCode, a.FCrimeCode, a.BankFlag, a.OrigId, a.SendDate } into b
|
||||||
|
select new
|
||||||
|
{
|
||||||
|
cardcode = b.Key.CardCode,
|
||||||
|
fcrimecode = b.Key.FCrimeCode,
|
||||||
|
CAMOUNT = b.Sum((T_Vcrd c) => c.CAmount),
|
||||||
|
Bankflag = b.Key.BankFlag,
|
||||||
|
origid = b.Key.OrigId,
|
||||||
|
SendDate = b.Key.SendDate
|
||||||
|
}).ToList();
|
||||||
|
if (reList.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var re in reList)
|
||||||
|
{
|
||||||
|
_rsp.ResultData.Add(new RspVcrdEntity
|
||||||
|
{
|
||||||
|
BankFlag = (re.Bankflag.HasValue ? re.Bankflag.Value : 0),
|
||||||
|
CAmount = (re.CAMOUNT.HasValue ? re.CAMOUNT.Value : 0m),
|
||||||
|
FCode = re.fcrimecode,
|
||||||
|
Origid = re.origid,
|
||||||
|
SendDate = (re.SendDate.HasValue ? re.SendDate.Value : DateTime.Now)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_rsp.ResultData = new List<RspVcrdEntity>();
|
||||||
|
}
|
||||||
|
_rsp.ResultCode = "0000";
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
_rsp.ResultCode = "0008";
|
||||||
|
_rsp.ResultData = new List<RspVcrdEntity>();
|
||||||
|
}
|
||||||
|
return jss.Serialize(_rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string MonitorSocketResult(string ReqData)
|
||||||
|
{
|
||||||
|
JavaScriptSerializer jss = new JavaScriptSerializer();
|
||||||
|
ResponNormalModel responNormalModel = new ResponNormalModel();
|
||||||
|
responNormalModel.ResultCode = "0000";
|
||||||
|
responNormalModel.ResultMsg = "";
|
||||||
|
ResponNormalModel _rsp = responNormalModel;
|
||||||
|
return jss.Serialize(_rsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CancelOrderResult(string ReqData)
|
||||||
|
{
|
||||||
|
JavaScriptSerializer jss = new JavaScriptSerializer();
|
||||||
|
ResponNormalModel responNormalModel = new ResponNormalModel();
|
||||||
|
responNormalModel.ResultCode = "0000";
|
||||||
|
responNormalModel.ResultMsg = "";
|
||||||
|
ResponNormalModel _rsp = responNormalModel;
|
||||||
|
return jss.Serialize(_rsp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JXHospitalWSBLL.ResponNormalModel
|
||||||
|
public class ResponNormalModel
|
||||||
|
{
|
||||||
|
private string _ResultCode;
|
||||||
|
|
||||||
|
private string _ResultMsg;
|
||||||
|
|
||||||
|
public string ResultCode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _ResultCode;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_ResultCode = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ResultMsg
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _ResultMsg;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_ResultMsg = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// JXHospitalWSBLL.RspVcrdEntity
|
||||||
|
using System;
|
||||||
|
|
||||||
|
public class RspVcrdEntity
|
||||||
|
{
|
||||||
|
private int _BankFlag;
|
||||||
|
|
||||||
|
private decimal _CAmount;
|
||||||
|
|
||||||
|
private string _FCode;
|
||||||
|
|
||||||
|
private string _Origid;
|
||||||
|
|
||||||
|
private DateTime _SendDate;
|
||||||
|
|
||||||
|
public int BankFlag
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _BankFlag;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_BankFlag = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal CAmount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _CAmount;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_CAmount = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FCode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _FCode;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_FCode = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Origid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _Origid;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_Origid = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime SendDate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _SendDate;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_SendDate = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// JXHospitalWSBLL.CriminalEntity
|
||||||
|
public class CriminalEntity
|
||||||
|
{
|
||||||
|
private string _FCode;
|
||||||
|
|
||||||
|
private string _FName;
|
||||||
|
|
||||||
|
private decimal _AmountA;
|
||||||
|
|
||||||
|
private int _fflag;
|
||||||
|
|
||||||
|
private decimal _AmountB;
|
||||||
|
|
||||||
|
private string _BankAccNo;
|
||||||
|
|
||||||
|
private decimal _BankAmount;
|
||||||
|
|
||||||
|
private decimal _AmountC;
|
||||||
|
|
||||||
|
private int _flimitflag;
|
||||||
|
|
||||||
|
private decimal _flimitamt;
|
||||||
|
|
||||||
|
public string FCode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _FCode;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_FCode = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _FName;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_FName = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal AmountA
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _AmountA;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_AmountA = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Fflag
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _fflag;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_fflag = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal AmountB
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _AmountB;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_AmountB = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string BankAccNo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _BankAccNo;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_BankAccNo = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal BankAmount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _BankAmount;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_BankAmount = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal AmountC
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _AmountC;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_AmountC = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Flimitflag
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _flimitflag;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_flimitflag = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal Flimitamt
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _flimitamt;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_flimitamt = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// JXHospitalWSBLL.ReqInoiveEntity
|
||||||
|
using System;
|
||||||
|
|
||||||
|
public class ReqInoiveEntity
|
||||||
|
{
|
||||||
|
private string _FCode;
|
||||||
|
|
||||||
|
private string _InvoiceNo;
|
||||||
|
|
||||||
|
private decimal _AmountA;
|
||||||
|
|
||||||
|
private decimal _AmountB;
|
||||||
|
|
||||||
|
private decimal _Amount;
|
||||||
|
|
||||||
|
private decimal _FreeAmountA;
|
||||||
|
|
||||||
|
private decimal _FreeAmountB;
|
||||||
|
|
||||||
|
private DateTime _CrtDate;
|
||||||
|
|
||||||
|
private string _FCriminal;
|
||||||
|
|
||||||
|
private string _CardCode;
|
||||||
|
|
||||||
|
private int _OrderId;
|
||||||
|
|
||||||
|
public string FCode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _FCode;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_FCode = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string InvoiceNo
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _InvoiceNo;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_InvoiceNo = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal AmountA
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _AmountA;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_AmountA = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal AmountB
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _AmountB;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_AmountB = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal Amount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _Amount;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_Amount = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal FreeAmountA
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _FreeAmountA;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_FreeAmountA = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public decimal FreeAmountB
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _FreeAmountB;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_FreeAmountB = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime CrtDate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _CrtDate;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_CrtDate = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FCriminal
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _FCriminal;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_FCriminal = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CardCode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _CardCode;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_CardCode = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int OrderId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _OrderId;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_OrderId = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
doc/新建文本文档.txt
Normal file
48
doc/新建文本文档.txt
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
启动完毕,等待客户端连接......
|
||||||
|
客户端192.168.10.2:61062连接成功...
|
||||||
|
从192.168.10.2:61062接收消息:021600069999FJJXYY712024-07-31 04:20:45["INV210600480113","INV210600556113","INV210600575113","INV210600607113","INV210600740113","INV210600854113","INV210600857113","INV210601006113","INV210601010113","INV210601037113"]
|
||||||
|
发送消息:1197{"ResultCode":"0000","ResultData":[{"BankFlag":2,"CAmount":8.85,"FCode":"3516023594","Origid":"INV210600607113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":30.00,"FCode":"3516018601","Origid":"INV210600480113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":8.85,"FCode":"3516018601","Origid":"INV210600575113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516018601","Origid":"INV210600857113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":286.70,"FCode":"3516018601","Origid":"INV210601010113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":18.69,"FCode":"3516012606","Origid":"INV210600556113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600740113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600854113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":167.49,"FCode":"3516012606","Origid":"INV210601006113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":269.70,"FCode":"3516016258","Origid":"INV210601037113","SendDate":"\/Date(1624982400000)\/"}]}
|
||||||
|
----------------------Err begin------------------------
|
||||||
|
客户端192.168.10.2:61062断开连接::Thread was being aborted.
|
||||||
|
----------------------Err end ------------------------
|
||||||
|
从192.168.10.2:61692接收消息:021600069999FJJXYY712024-07-31 10:21:58["INV210600480113","INV210600556113","INV210600575113","INV210600607113","INV210600740113","INV210600854113","INV210600857113","INV210601006113","INV210601010113","INV210601037113"]
|
||||||
|
发送消息:1197{"ResultCode":"0000","ResultData":[{"BankFlag":2,"CAmount":8.85,"FCode":"3516023594","Origid":"INV210600607113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":30.00,"FCode":"3516018601","Origid":"INV210600480113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":8.85,"FCode":"3516018601","Origid":"INV210600575113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516018601","Origid":"INV210600857113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":286.70,"FCode":"3516018601","Origid":"INV210601010113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":18.69,"FCode":"3516012606","Origid":"INV210600556113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600740113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600854113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":167.49,"FCode":"3516012606","Origid":"INV210601006113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":269.70,"FCode":"3516016258","Origid":"INV210601037113","SendDate":"\/Date(1624982400000)\/"}]}
|
||||||
|
|
||||||
|
|
||||||
|
----------------------Err end ------------------------
|
||||||
|
客户端192.168.10.2:62796连接成功...
|
||||||
|
从192.168.10.2:62796接收消息:005700059999FJJXYY712024-08-01 09:00:44{"FCode":"3516022343"}
|
||||||
|
发送消息:0216{"ResultCode":"0000","ResultData":{"FCode":"3516022343","FName":null,"AmountA":414.54,"Fflag":0,"AmountB":0.27,"BankAccNo":"6230361101121167023","BankAmount":2440.5600,"AmountC":2025.75,"Flimitflag":0,"Flimitamt":0}}
|
||||||
|
----------------------Err begin------------------------
|
||||||
|
客户端192.168.10.2:62796断开连接::Thread was being aborted.
|
||||||
|
----------------------Err end ------------------------
|
||||||
|
从192.168.10.2:62797接收消息:027000049999FJJXYY712024-08-01 09:00:47{"FCode":"3516022343","InvoiceNo":"INV240800054113","AmountA":10.00,"AmountB":0.00,"Amount":10.00,"FreeAmountA":0.00,"FreeAmountB":0.00,"CrtDate":"\/Date(1722474044000)\/","FCriminal":"王东","CardCode":"2405007996","OrderId":1118337}
|
||||||
|
客户端192.168.10.2:62797连接成功...
|
||||||
|
发送消息:0036{"ResultCode":"0000","ResultMsg":""}
|
||||||
|
----------------------Err begin------------------------
|
||||||
|
客户端192.168.10.2:62797断开连接::Thread was being aborted.
|
||||||
|
----------------------Err end ------------------------
|
||||||
|
客户端192.168.10.2:62802连接成功...
|
||||||
|
从192.168.10.2:62802接收消息:005700059999FJJXYY712024-08-01 09:01:33{"FCode":"3516015811"}
|
||||||
|
发送消息:0212{"ResultCode":"0000","ResultData":{"FCode":"3516015811","FName":null,"AmountA":71.48,"Fflag":0,"AmountB":0.13,"BankAccNo":"6230361101034063160","BankAmount":124.7100,"AmountC":53.10,"Flimitflag":0,"Flimitamt":0}}
|
||||||
|
----------------------Err begin------------------------
|
||||||
|
客户端192.168.10.2:62802断开连接::Thread was being aborted.
|
||||||
|
----------------------Err end ------------------------
|
||||||
|
从192.168.10.2:62803接收消息:027300049999FJJXYY712024-08-01 09:01:37{"FCode":"3516015811","InvoiceNo":"INV240800060113","AmountA":10.00,"AmountB":0.00,"Amount":10.00,"FreeAmountA":0.00,"FreeAmountB":0.00,"CrtDate":"\/Date(1722474093000)\/","FCriminal":"中浩沣","CardCode":"2407008188","OrderId":1118343}
|
||||||
|
客户端192.168.10.2:62803连接成功...
|
||||||
|
发送消息:0036{"ResultCode":"0000","ResultMsg":""}
|
||||||
|
----------------------Err begin------------------------
|
||||||
|
客户端192.168.10.2:62803断开连接::Thread was being aborted.
|
||||||
|
----------------------Err end ------------------------
|
||||||
|
客户端192.168.10.2:63014连接成功...
|
||||||
|
从192.168.10.2:63014接收消息:021600069999FJJXYY712024-08-01 10:24:20["INV210600480113","INV210600556113","INV210600575113","INV210600607113","INV210600740113","INV210600854113","INV210600857113","INV210601006113","INV210601010113","INV210601037113"]
|
||||||
|
发送消息:1197{"ResultCode":"0000","ResultData":[{"BankFlag":2,"CAmount":8.85,"FCode":"3516023594","Origid":"INV210600607113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":30.00,"FCode":"3516018601","Origid":"INV210600480113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":8.85,"FCode":"3516018601","Origid":"INV210600575113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516018601","Origid":"INV210600857113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":286.70,"FCode":"3516018601","Origid":"INV210601010113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":18.69,"FCode":"3516012606","Origid":"INV210600556113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600740113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600854113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":167.49,"FCode":"3516012606","Origid":"INV210601006113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":269.70,"FCode":"3516016258","Origid":"INV210601037113","SendDate":"\/Date(1624982400000)\/"}]}
|
||||||
|
----------------------Err begin------------------------
|
||||||
|
客户端192.168.10.2:63014断开连接::Thread was being aborted.
|
||||||
|
----------------------Err end ------------------------
|
||||||
|
从192.168.10.2:63656接收消息:021600069999FJJXYY712024-08-01 04:25:32["INV210600480113","INV210600556113","INV210600575113","INV210600607113","INV210600740113","INV210600854113","INV210600857113","INV210601006113","INV210601010113","INV210601037113"]
|
||||||
|
发送消息:1197{"ResultCode":"0000","ResultData":[{"BankFlag":2,"CAmount":8.85,"FCode":"3516023594","Origid":"INV210600607113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":30.00,"FCode":"3516018601","Origid":"INV210600480113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":8.85,"FCode":"3516018601","Origid":"INV210600575113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516018601","Origid":"INV210600857113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":286.70,"FCode":"3516018601","Origid":"INV210601010113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":18.69,"FCode":"3516012606","Origid":"INV210600556113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600740113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":10.00,"FCode":"3516012606","Origid":"INV210600854113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":167.49,"FCode":"3516012606","Origid":"INV210601006113","SendDate":"\/Date(1624982400000)\/"},{"BankFlag":2,"CAmount":269.70,"FCode":"3516016258","Origid":"INV210601037113","SendDate":"\/Date(1624982400000)\/"}]}
|
||||||
|
客户端192.168.10.2:63656连接成功...
|
||||||
|
----------------------Err begin------------------------
|
||||||
|
客户端192.168.10.2:63656断开连接::Thread was being aborted.
|
||||||
|
----------------------Err end ------------------------
|
||||||
71
go.mod
Normal file
71
go.mod
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
module github.com/emsoft/HospitalPay-Go
|
||||||
|
|
||||||
|
go 1.23.0
|
||||||
|
|
||||||
|
toolchain go1.23.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/gin-gonic/gin v1.10.0
|
||||||
|
github.com/spf13/viper v1.20.0
|
||||||
|
gorm.io/gorm v1.25.12
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/bytedance/sonic v1.13.2 // indirect
|
||||||
|
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||||
|
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||||
|
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
|
github.com/gin-contrib/sse v1.0.0 // indirect
|
||||||
|
github.com/go-playground/locales v0.14.1 // indirect
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||||
|
github.com/go-playground/validator/v10 v10.25.0 // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.9.1 // indirect
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||||
|
github.com/goccy/go-json v0.10.5 // indirect
|
||||||
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||||
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
|
github.com/magiconair/properties v1.8.7 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.21.1 // indirect
|
||||||
|
github.com/prometheus/client_model v0.6.1 // indirect
|
||||||
|
github.com/prometheus/common v0.63.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.16.0 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.8.0 // indirect
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
|
github.com/spf13/afero v1.14.0 // indirect
|
||||||
|
github.com/spf13/cast v1.7.1 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.6 // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
|
golang.org/x/arch v0.15.0 // indirect
|
||||||
|
golang.org/x/crypto v0.36.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||||
|
golang.org/x/net v0.37.0 // indirect
|
||||||
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
|
golang.org/x/text v0.23.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.6 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
gorm.io/driver/mysql v1.5.7 // indirect
|
||||||
|
)
|
||||||
225
go.sum
Normal file
225
go.sum
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||||
|
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||||
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
|
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||||
|
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||||
|
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||||
|
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||||
|
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||||
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
|
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
|
||||||
|
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||||
|
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||||
|
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||||
|
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||||
|
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
|
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
|
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||||
|
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||||
|
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||||
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
|
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
|
||||||
|
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
|
||||||
|
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||||
|
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||||
|
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||||
|
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||||
|
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||||
|
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||||
|
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||||
|
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||||
|
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||||
|
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
|
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
|
||||||
|
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
|
github.com/go-sql-driver/mysql v1.9.1 h1:FrjNGn/BsJQjVRuSa8CBrM5BWA9BWoXXat3KrtSb/iI=
|
||||||
|
github.com/go-sql-driver/mysql v1.9.1/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||||
|
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||||
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||||
|
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||||
|
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
|
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||||
|
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||||
|
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||||
|
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||||
|
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||||
|
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||||
|
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||||
|
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||||
|
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||||
|
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||||
|
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||||
|
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
||||||
|
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
|
||||||
|
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
|
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||||
|
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
|
||||||
|
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||||
|
github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
|
||||||
|
github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||||
|
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||||
|
github.com/sagikazarmark/locafero v0.8.0 h1:mXaMVw7IqxNBxfv3LdWt9MDmcWDQ1fagDH918lOdVaQ=
|
||||||
|
github.com/sagikazarmark/locafero v0.8.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||||
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
|
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||||
|
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||||
|
github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
|
||||||
|
github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
|
||||||
|
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||||
|
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
|
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
|
||||||
|
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
|
||||||
|
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||||
|
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
||||||
|
github.com/spf13/viper v1.20.0 h1:zrxIyR3RQIOsarIrgL8+sAvALXul9jeEPa06Y0Ph6vY=
|
||||||
|
github.com/spf13/viper v1.20.0/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
|
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||||
|
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||||
|
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
|
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||||
|
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||||
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||||
|
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||||
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
|
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
|
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||||
|
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
|
golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw=
|
||||||
|
golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||||
|
golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||||
|
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||||
|
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||||
|
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||||
|
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||||
|
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||||
|
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||||
|
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||||
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||||
|
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||||
|
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||||
|
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||||
|
gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A=
|
||||||
|
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||||
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
|
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||||
90
internal/config/config.go
Normal file
90
internal/config/config.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Server ServerConfig `mapstructure:"server"`
|
||||||
|
Database DatabaseConfig `mapstructure:"database"`
|
||||||
|
Log LogConfig `mapstructure:"log"`
|
||||||
|
Monitoring MonitoringConfig `mapstructure:"monitoring"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerConfig struct {
|
||||||
|
Port string `mapstructure:"port"`
|
||||||
|
Mode string `mapstructure:"mode"`
|
||||||
|
HospitalCode string `mapstructure:"hospital_code"`
|
||||||
|
ReadTimeout time.Duration `mapstructure:"read_timeout"`
|
||||||
|
WriteTimeout time.Duration `mapstructure:"write_timeout"`
|
||||||
|
MaxConnNum int `mapstructure:"max_conn_num"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DatabaseConfig struct {
|
||||||
|
Driver string `mapstructure:"driver"`
|
||||||
|
Host string `mapstructure:"host"`
|
||||||
|
Port int `mapstructure:"port"`
|
||||||
|
Username string `mapstructure:"username"`
|
||||||
|
Password string `mapstructure:"password"`
|
||||||
|
DBName string `mapstructure:"dbname"`
|
||||||
|
Charset string `mapstructure:"charset"`
|
||||||
|
ParseTime bool `mapstructure:"parseTime"`
|
||||||
|
Loc string `mapstructure:"loc"`
|
||||||
|
MaxIdleConns int `mapstructure:"max_idle_conns"`
|
||||||
|
MaxOpenConns int `mapstructure:"max_open_conns"`
|
||||||
|
ConnMaxLifetime time.Duration `mapstructure:"conn_max_lifetime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LogConfig struct {
|
||||||
|
Level string `mapstructure:"level"`
|
||||||
|
Format string `mapstructure:"format"`
|
||||||
|
OutputPath string `mapstructure:"output_path"`
|
||||||
|
MaxSize int `mapstructure:"max_size"`
|
||||||
|
MaxAge int `mapstructure:"max_age"`
|
||||||
|
MaxBackups int `mapstructure:"max_backups"`
|
||||||
|
Compress bool `mapstructure:"compress"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MonitoringConfig struct {
|
||||||
|
Enabled bool `mapstructure:"enabled"`
|
||||||
|
PrometheusPort string `mapstructure:"prometheus_port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var GlobalConfig Config
|
||||||
|
|
||||||
|
func Init() error {
|
||||||
|
viper.SetConfigName("config")
|
||||||
|
viper.SetConfigType("yaml")
|
||||||
|
viper.AddConfigPath("./config")
|
||||||
|
|
||||||
|
if err := viper.ReadInConfig(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := viper.Unmarshal(&GlobalConfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证配置项
|
||||||
|
if err := validate(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func validate() error {
|
||||||
|
if GlobalConfig.Server.Port == "" {
|
||||||
|
return errors.New("server port is required")
|
||||||
|
}
|
||||||
|
if GlobalConfig.Server.HospitalCode == "" {
|
||||||
|
return errors.New("hospital code is required")
|
||||||
|
}
|
||||||
|
if GlobalConfig.Database.Host == "" {
|
||||||
|
return errors.New("database host is required")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
15
internal/model/base.go
Normal file
15
internal/model/base.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Base 模型基础字段
|
||||||
|
type Base struct {
|
||||||
|
ID uint `gorm:"primarykey" json:"id"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||||
|
}
|
||||||
70
internal/model/criminal.go
Normal file
70
internal/model/criminal.go
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// CriminalRequest 病人请求基础结构
|
||||||
|
type CriminalRequest struct {
|
||||||
|
FCode string `json:"FCode"` // 病人编号
|
||||||
|
}
|
||||||
|
|
||||||
|
// CriminalResponse 病人响应基础结构
|
||||||
|
type CriminalResponse struct {
|
||||||
|
ResultCode string `json:"ResultCode"` // 结果代码
|
||||||
|
ResultData interface{} `json:"ResultData"` // 响应数据
|
||||||
|
ResultMsg string `json:"ResultMsg"` // 结果消息
|
||||||
|
}
|
||||||
|
|
||||||
|
// CriminalInfo 病人信息
|
||||||
|
type CriminalInfo struct {
|
||||||
|
FCode string `json:"FCode"` // 病人编号
|
||||||
|
FName string `json:"FName"` // 病人姓名
|
||||||
|
AmountA float64 `json:"AmountA"` // A类金额
|
||||||
|
AmountB float64 `json:"AmountB"` // B类金额
|
||||||
|
AmountC float64 `json:"AmountC"` // C类金额
|
||||||
|
BankAccNo string `json:"BankAccNo"` // 银行账号
|
||||||
|
BankAmount float64 `json:"BankAmount"` // 银行余额
|
||||||
|
Fflag int `json:"Fflag"` // 状态标志
|
||||||
|
Flimitflag int `json:"Flimitflag"` // 限制标志
|
||||||
|
Flimitamt float64 `json:"Flimitamt"` // 限制金额
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeQuota 消费额度信息
|
||||||
|
type ConsumeQuota struct {
|
||||||
|
AmountA float64 `json:"AmountA"` // A类消费金额
|
||||||
|
AmountB float64 `json:"AmountB"` // B类消费金额
|
||||||
|
FreeAmountA float64 `json:"FreeAmountA"` // A类可用金额
|
||||||
|
FreeAmountB float64 `json:"FreeAmountB"` // B类可用金额
|
||||||
|
Checkflag int `json:"Checkflag"` // 检查标志
|
||||||
|
FCode string `json:"FCode"` // 病人编号
|
||||||
|
FCriminal string `json:"FCriminal"` // 病人姓名
|
||||||
|
Flag int `json:"Flag"` // 状态标志
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeRecord 消费记录
|
||||||
|
type ConsumeRecord struct {
|
||||||
|
FCode string `json:"FCode"` // 病人编号
|
||||||
|
InvoiceNo string `json:"InvoiceNo"` // 发票号
|
||||||
|
AmountA float64 `json:"AmountA"` // A类金额
|
||||||
|
AmountB float64 `json:"AmountB"` // B类金额
|
||||||
|
Amount float64 `json:"Amount"` // 总金额
|
||||||
|
FreeAmountA float64 `json:"FreeAmountA"` // A类可用金额
|
||||||
|
FreeAmountB float64 `json:"FreeAmountB"` // B类可用金额
|
||||||
|
CrtDate time.Time `json:"CrtDate"` // 创建日期
|
||||||
|
FCriminal string `json:"FCriminal"` // 病人姓名
|
||||||
|
CardCode string `json:"CardCode"` // 卡号
|
||||||
|
OrderId int64 `json:"OrderId"` // 订单ID
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvoiceSync 发票同步
|
||||||
|
type InvoiceSync struct {
|
||||||
|
InvoiceList []string `json:"InvoiceList"` // 发票号列表
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvoiceSyncResult 发票同步结果
|
||||||
|
type InvoiceSyncResult struct {
|
||||||
|
BankFlag int `json:"BankFlag"` // 银行标志
|
||||||
|
CAmount float64 `json:"CAmount"` // 金额
|
||||||
|
FCode string `json:"FCode"` // 病人编号
|
||||||
|
Origid string `json:"Origid"` // 原始ID
|
||||||
|
SendDate time.Time `json:"SendDate"` // 发送日期
|
||||||
|
}
|
||||||
78
internal/pkg/database/gorm_logger.go
Normal file
78
internal/pkg/database/gorm_logger.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/pkg/logger"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
gormlogger "gorm.io/gorm/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 自定义Gorm日志适配器
|
||||||
|
type GormLogger struct {
|
||||||
|
SlowThreshold time.Duration
|
||||||
|
LogLevel gormlogger.LogLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建新的Gorm日志适配器
|
||||||
|
func NewGormLogger() *GormLogger {
|
||||||
|
return &GormLogger{
|
||||||
|
SlowThreshold: 200 * time.Millisecond,
|
||||||
|
LogLevel: gormlogger.Info,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LogMode 设置日志级别
|
||||||
|
func (l *GormLogger) LogMode(level gormlogger.LogLevel) gormlogger.Interface {
|
||||||
|
newLogger := *l
|
||||||
|
newLogger.LogLevel = level
|
||||||
|
return &newLogger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info 打印信息
|
||||||
|
func (l *GormLogger) Info(ctx context.Context, msg string, data ...interface{}) {
|
||||||
|
if l.LogLevel >= gormlogger.Info {
|
||||||
|
logger.Infof(msg, data...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn 打印警告
|
||||||
|
func (l *GormLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
|
||||||
|
if l.LogLevel >= gormlogger.Warn {
|
||||||
|
logger.Warnf(msg, data...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error 打印错误
|
||||||
|
func (l *GormLogger) Error(ctx context.Context, msg string, data ...interface{}) {
|
||||||
|
if l.LogLevel >= gormlogger.Error {
|
||||||
|
logger.Errorf(msg, data...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace 打印SQL
|
||||||
|
func (l *GormLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
|
||||||
|
if l.LogLevel <= gormlogger.Silent {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
elapsed := time.Since(begin)
|
||||||
|
sql, rows := fc()
|
||||||
|
fields := []zap.Field{
|
||||||
|
zap.String("sql", sql),
|
||||||
|
zap.Int64("rows", rows),
|
||||||
|
zap.Duration("elapsed", elapsed),
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case err != nil && l.LogLevel >= gormlogger.Error && !errors.Is(err, gorm.ErrRecordNotFound):
|
||||||
|
logger.Error("GORM ERROR", fields...)
|
||||||
|
case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= gormlogger.Warn:
|
||||||
|
logger.Warn("GORM SLOW SQL", fields...)
|
||||||
|
case l.LogLevel >= gormlogger.Info:
|
||||||
|
logger.Debug("GORM SQL", fields...)
|
||||||
|
}
|
||||||
|
}
|
||||||
80
internal/pkg/database/mysql.go
Normal file
80
internal/pkg/database/mysql.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package database
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/config"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/pkg/logger"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
var DB *gorm.DB
|
||||||
|
|
||||||
|
// Init 初始化数据库连接
|
||||||
|
func Init() error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
dbConfig := config.GlobalConfig.Database
|
||||||
|
|
||||||
|
dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=%v&loc=%s",
|
||||||
|
dbConfig.Username,
|
||||||
|
dbConfig.Password,
|
||||||
|
dbConfig.Host,
|
||||||
|
dbConfig.Port,
|
||||||
|
dbConfig.DBName,
|
||||||
|
dbConfig.Charset,
|
||||||
|
dbConfig.ParseTime,
|
||||||
|
dbConfig.Loc,
|
||||||
|
)
|
||||||
|
|
||||||
|
DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
|
||||||
|
NamingStrategy: schema.NamingStrategy{
|
||||||
|
TablePrefix: "t_", // 表名前缀
|
||||||
|
SingularTable: true, // 使用单数表名
|
||||||
|
},
|
||||||
|
Logger: NewGormLogger(),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("connect to database failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置连接池
|
||||||
|
sqlDB, err := DB.DB()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get db instance failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlDB.SetMaxIdleConns(dbConfig.MaxIdleConns)
|
||||||
|
sqlDB.SetMaxOpenConns(dbConfig.MaxOpenConns)
|
||||||
|
sqlDB.SetConnMaxLifetime(dbConfig.ConnMaxLifetime)
|
||||||
|
|
||||||
|
// 测试连接
|
||||||
|
if err := sqlDB.Ping(); err != nil {
|
||||||
|
return fmt.Errorf("ping database failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("Database connected successfully")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDB 获取数据库连接
|
||||||
|
func GetDB() *gorm.DB {
|
||||||
|
return DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close 关闭数据库连接
|
||||||
|
func Close() error {
|
||||||
|
sqlDB, err := DB.DB()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return sqlDB.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transaction 事务处理
|
||||||
|
func Transaction(fn func(tx *gorm.DB) error) error {
|
||||||
|
return DB.Transaction(fn)
|
||||||
|
}
|
||||||
26
internal/pkg/errcode/errcode.go
Normal file
26
internal/pkg/errcode/errcode.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package errcode
|
||||||
|
|
||||||
|
// ErrorCode 错误码结构
|
||||||
|
type ErrorCode struct {
|
||||||
|
Code string
|
||||||
|
Message string
|
||||||
|
}
|
||||||
|
|
||||||
|
// 系统级错误码
|
||||||
|
var (
|
||||||
|
Success = &ErrorCode{Code: "0000", Message: "成功"}
|
||||||
|
ServerError = &ErrorCode{Code: "0008", Message: "系统异常"}
|
||||||
|
InvalidParams = &ErrorCode{Code: "0009", Message: "请求参数错误"}
|
||||||
|
NotFound = &ErrorCode{Code: "0005", Message: "未找到病人信息"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 业务级错误码
|
||||||
|
var (
|
||||||
|
CriminalInFailed = &ErrorCode{Code: "0006", Message: "入院处理失败"}
|
||||||
|
CriminalAlreadyIn = &ErrorCode{Code: "0007", Message: "病人已入院"}
|
||||||
|
CriminalOutFailed = &ErrorCode{Code: "1001", Message: "出院处理失败"}
|
||||||
|
ConsumeQuotaFailed = &ErrorCode{Code: "1002", Message: "消费额度查询失败"}
|
||||||
|
ConsumeRecordFailed = &ErrorCode{Code: "1003", Message: "消费记录保存失败"}
|
||||||
|
RealTimeBalanceFailed = &ErrorCode{Code: "1004", Message: "实时余额查询失败"}
|
||||||
|
InvoiceSyncFailed = &ErrorCode{Code: "1005", Message: "发票同步失败"}
|
||||||
|
)
|
||||||
131
internal/pkg/logger/logger.go
Normal file
131
internal/pkg/logger/logger.go
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
package logger
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/config"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapcore"
|
||||||
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Logger *zap.Logger
|
||||||
|
var SugaredLogger *zap.SugaredLogger
|
||||||
|
|
||||||
|
// Init 初始化日志
|
||||||
|
func Init() error {
|
||||||
|
logConfig := config.GlobalConfig.Log
|
||||||
|
|
||||||
|
// 确保日志目录存在
|
||||||
|
if err := os.MkdirAll(filepath.Dir(logConfig.OutputPath), 0755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置日志轮转
|
||||||
|
w := zapcore.AddSync(&lumberjack.Logger{
|
||||||
|
Filename: logConfig.OutputPath,
|
||||||
|
MaxSize: logConfig.MaxSize,
|
||||||
|
MaxBackups: logConfig.MaxBackups,
|
||||||
|
MaxAge: logConfig.MaxAge,
|
||||||
|
Compress: logConfig.Compress,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 设置日志级别
|
||||||
|
var level zapcore.Level
|
||||||
|
switch logConfig.Level {
|
||||||
|
case "debug":
|
||||||
|
level = zapcore.DebugLevel
|
||||||
|
case "info":
|
||||||
|
level = zapcore.InfoLevel
|
||||||
|
case "warn":
|
||||||
|
level = zapcore.WarnLevel
|
||||||
|
case "error":
|
||||||
|
level = zapcore.ErrorLevel
|
||||||
|
case "fatal":
|
||||||
|
level = zapcore.FatalLevel
|
||||||
|
default:
|
||||||
|
level = zapcore.InfoLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置日志编码器
|
||||||
|
encoderConfig := zapcore.EncoderConfig{
|
||||||
|
TimeKey: "time",
|
||||||
|
LevelKey: "level",
|
||||||
|
NameKey: "logger",
|
||||||
|
CallerKey: "caller",
|
||||||
|
MessageKey: "msg",
|
||||||
|
StacktraceKey: "stacktrace",
|
||||||
|
LineEnding: zapcore.DefaultLineEnding,
|
||||||
|
EncodeLevel: zapcore.LowercaseLevelEncoder,
|
||||||
|
EncodeTime: zapcore.ISO8601TimeEncoder,
|
||||||
|
EncodeDuration: zapcore.SecondsDurationEncoder,
|
||||||
|
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||||
|
}
|
||||||
|
|
||||||
|
var encoder zapcore.Encoder
|
||||||
|
if logConfig.Format == "json" {
|
||||||
|
encoder = zapcore.NewJSONEncoder(encoderConfig)
|
||||||
|
} else {
|
||||||
|
encoder = zapcore.NewConsoleEncoder(encoderConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建核心
|
||||||
|
core := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(w, zapcore.AddSync(os.Stdout)), level)
|
||||||
|
|
||||||
|
// 创建日志实例
|
||||||
|
Logger = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
|
||||||
|
SugaredLogger = Logger.Sugar()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logs a message at debug level
|
||||||
|
func Debug(msg string, fields ...zapcore.Field) {
|
||||||
|
Logger.Debug(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info logs a message at info level
|
||||||
|
func Info(msg string, fields ...zapcore.Field) {
|
||||||
|
Logger.Info(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warn logs a message at warn level
|
||||||
|
func Warn(msg string, fields ...zapcore.Field) {
|
||||||
|
Logger.Warn(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error logs a message at error level
|
||||||
|
func Error(msg string, fields ...zapcore.Field) {
|
||||||
|
Logger.Error(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatal logs a message at fatal level and then calls os.Exit(1)
|
||||||
|
func Fatal(msg string, fields ...zapcore.Field) {
|
||||||
|
Logger.Fatal(msg, fields...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debugf logs a formatted message at debug level
|
||||||
|
func Debugf(format string, args ...interface{}) {
|
||||||
|
SugaredLogger.Debugf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infof logs a formatted message at info level
|
||||||
|
func Infof(format string, args ...interface{}) {
|
||||||
|
SugaredLogger.Infof(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warnf logs a formatted message at warn level
|
||||||
|
func Warnf(format string, args ...interface{}) {
|
||||||
|
SugaredLogger.Warnf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf logs a formatted message at error level
|
||||||
|
func Errorf(format string, args ...interface{}) {
|
||||||
|
SugaredLogger.Errorf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fatalf logs a formatted message at fatal level and then calls os.Exit(1)
|
||||||
|
func Fatalf(format string, args ...interface{}) {
|
||||||
|
SugaredLogger.Fatalf(format, args...)
|
||||||
|
}
|
||||||
44
internal/pkg/metrics/metrics.go
Normal file
44
internal/pkg/metrics/metrics.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// RequestCounter 请求计数器
|
||||||
|
RequestCounter = promauto.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: "hospital_pay_requests_total",
|
||||||
|
Help: "请求总数,按功能码分类",
|
||||||
|
},
|
||||||
|
[]string{"function_code"},
|
||||||
|
)
|
||||||
|
|
||||||
|
// RequestDuration 请求处理时间
|
||||||
|
RequestDuration = promauto.NewHistogramVec(
|
||||||
|
prometheus.HistogramOpts{
|
||||||
|
Name: "hospital_pay_request_duration_seconds",
|
||||||
|
Help: "请求处理时间(秒)",
|
||||||
|
Buckets: prometheus.DefBuckets,
|
||||||
|
},
|
||||||
|
[]string{"function_code"},
|
||||||
|
)
|
||||||
|
|
||||||
|
// ErrorCounter 错误计数器
|
||||||
|
ErrorCounter = promauto.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: "hospital_pay_errors_total",
|
||||||
|
Help: "错误总数,按功能码和错误码分类",
|
||||||
|
},
|
||||||
|
[]string{"function_code", "error_code"},
|
||||||
|
)
|
||||||
|
|
||||||
|
// ActiveConnections 活跃连接数
|
||||||
|
ActiveConnections = promauto.NewGauge(
|
||||||
|
prometheus.GaugeOpts{
|
||||||
|
Name: "hospital_pay_active_connections",
|
||||||
|
Help: "当前活跃连接数",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
397
internal/server/socket.go
Normal file
397
internal/server/socket.go
Normal file
@ -0,0 +1,397 @@
|
|||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/config"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/model"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/pkg/errcode"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/pkg/logger"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/pkg/metrics"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/service"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SocketServer Socket 服务器
|
||||||
|
type SocketServer struct {
|
||||||
|
criminalService service.ICriminalService
|
||||||
|
listener net.Listener
|
||||||
|
connLimit chan struct{}
|
||||||
|
wg sync.WaitGroup
|
||||||
|
shutdown chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSocketServer 创建 Socket 服务器
|
||||||
|
func NewSocketServer() *SocketServer {
|
||||||
|
return &SocketServer{
|
||||||
|
criminalService: service.NewCriminalService(),
|
||||||
|
connLimit: make(chan struct{}, config.GlobalConfig.Server.MaxConnNum),
|
||||||
|
shutdown: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start 启动服务器
|
||||||
|
func (s *SocketServer) Start() error {
|
||||||
|
var err error
|
||||||
|
s.listener, err = net.Listen("tcp", ":"+config.GlobalConfig.Server.Port)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to start socket server: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册信号处理
|
||||||
|
go s.handleSignal()
|
||||||
|
|
||||||
|
logger.Infof("Socket server started on port %s", config.GlobalConfig.Server.Port)
|
||||||
|
|
||||||
|
// 开始接受连接
|
||||||
|
go s.acceptConnections()
|
||||||
|
|
||||||
|
// 等待关闭
|
||||||
|
<-s.shutdown
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 接受连接
|
||||||
|
func (s *SocketServer) acceptConnections() {
|
||||||
|
for {
|
||||||
|
conn, err := s.listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
select {
|
||||||
|
case <-s.shutdown:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
logger.Errorf("Failed to accept connection: %v", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录指标
|
||||||
|
metrics.ActiveConnections.Inc()
|
||||||
|
|
||||||
|
// 并发控制
|
||||||
|
select {
|
||||||
|
case s.connLimit <- struct{}{}:
|
||||||
|
s.wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer func() {
|
||||||
|
<-s.connLimit
|
||||||
|
metrics.ActiveConnections.Dec()
|
||||||
|
s.wg.Done()
|
||||||
|
}()
|
||||||
|
s.handleConnection(conn)
|
||||||
|
}()
|
||||||
|
default:
|
||||||
|
logger.Warnf("Connection limit reached, rejecting connection from %s", conn.RemoteAddr())
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理连接
|
||||||
|
func (s *SocketServer) handleConnection(conn net.Conn) {
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
// 设置超时
|
||||||
|
if err := conn.SetDeadline(time.Now().Add(config.GlobalConfig.Server.ReadTimeout)); err != nil {
|
||||||
|
logger.Errorf("Failed to set deadline: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录连接信息
|
||||||
|
remoteAddr := conn.RemoteAddr().String()
|
||||||
|
logger.Infof("New connection from %s", remoteAddr)
|
||||||
|
|
||||||
|
buffer := make([]byte, 4096)
|
||||||
|
n, err := conn.Read(buffer)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to read from connection: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
message := string(buffer[:n])
|
||||||
|
if len(message) < 31 { // 最小消息长度:4(长度) + 4(功能码) + 4(医院编码) + 19(时间戳)
|
||||||
|
logger.Errorf("Invalid message format from %s: %s", remoteAddr, message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析消息
|
||||||
|
length := message[:4]
|
||||||
|
functionCode := message[4:8]
|
||||||
|
hospitalCode := message[8:12]
|
||||||
|
timestamp := message[12:31]
|
||||||
|
data := message[31:]
|
||||||
|
|
||||||
|
logger.Infof("Received message from %s: length=%s, functionCode=%s, hospitalCode=%s, timestamp=%s, data=%s",
|
||||||
|
remoteAddr, length, functionCode, hospitalCode, timestamp, data)
|
||||||
|
|
||||||
|
// 请求计数
|
||||||
|
metrics.RequestCounter.WithLabelValues(functionCode).Inc()
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
|
// 验证医院编码
|
||||||
|
if hospitalCode != config.GlobalConfig.Server.HospitalCode {
|
||||||
|
logger.Warnf("Invalid hospital code from %s: %s", remoteAddr, hospitalCode)
|
||||||
|
s.sendResponse(conn, &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.InvalidParams.Code,
|
||||||
|
ResultMsg: "无效的医院编码",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建上下文
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// 处理请求
|
||||||
|
var response *model.CriminalResponse
|
||||||
|
switch functionCode {
|
||||||
|
case "0001":
|
||||||
|
response = s.handleCriminalIn(ctx, data)
|
||||||
|
case "0002":
|
||||||
|
response = s.handleConsumeQuota(ctx, data)
|
||||||
|
case "0003":
|
||||||
|
response = s.handleCriminalOut(ctx, data)
|
||||||
|
case "0004":
|
||||||
|
response = s.handleConsumeRecord(ctx, data)
|
||||||
|
case "0005":
|
||||||
|
response = s.handleRealTimeBalance(ctx, data)
|
||||||
|
case "0006":
|
||||||
|
response = s.handleInvoiceSync(ctx, data)
|
||||||
|
default:
|
||||||
|
response = &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.ServerError.Code,
|
||||||
|
ResultMsg: "未知的功能码",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 记录处理时间
|
||||||
|
duration := time.Since(start).Seconds()
|
||||||
|
metrics.RequestDuration.WithLabelValues(functionCode).Observe(duration)
|
||||||
|
|
||||||
|
// 发送响应
|
||||||
|
s.sendResponse(conn, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理入院登记
|
||||||
|
func (s *SocketServer) handleCriminalIn(ctx context.Context, data string) *model.CriminalResponse {
|
||||||
|
var req model.CriminalRequest
|
||||||
|
if err := json.Unmarshal([]byte(data), &req); err != nil {
|
||||||
|
logger.Errorf("Failed to unmarshal CriminalIn request: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0001", errcode.InvalidParams.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.InvalidParams.Code,
|
||||||
|
ResultMsg: "请求数据格式错误",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.criminalService.CriminalIn(ctx, req.FCode)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to process CriminalIn: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0001", errcode.ServerError.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.ServerError.Code,
|
||||||
|
ResultMsg: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理消费额度查询
|
||||||
|
func (s *SocketServer) handleConsumeQuota(ctx context.Context, data string) *model.CriminalResponse {
|
||||||
|
var req model.CriminalRequest
|
||||||
|
if err := json.Unmarshal([]byte(data), &req); err != nil {
|
||||||
|
logger.Errorf("Failed to unmarshal ConsumeQuota request: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0002", errcode.InvalidParams.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.InvalidParams.Code,
|
||||||
|
ResultMsg: "请求数据格式错误",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.criminalService.ConsumeQuota(ctx, req.FCode)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to process ConsumeQuota: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0002", errcode.ServerError.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.ServerError.Code,
|
||||||
|
ResultMsg: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理出院
|
||||||
|
func (s *SocketServer) handleCriminalOut(ctx context.Context, data string) *model.CriminalResponse {
|
||||||
|
var req model.CriminalRequest
|
||||||
|
if err := json.Unmarshal([]byte(data), &req); err != nil {
|
||||||
|
logger.Errorf("Failed to unmarshal CriminalOut request: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0003", errcode.InvalidParams.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.InvalidParams.Code,
|
||||||
|
ResultMsg: "请求数据格式错误",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.criminalService.CriminalOut(ctx, req.FCode)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to process CriminalOut: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0003", errcode.ServerError.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.ServerError.Code,
|
||||||
|
ResultMsg: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理消费记录
|
||||||
|
func (s *SocketServer) handleConsumeRecord(ctx context.Context, data string) *model.CriminalResponse {
|
||||||
|
var record model.ConsumeRecord
|
||||||
|
if err := json.Unmarshal([]byte(data), &record); err != nil {
|
||||||
|
logger.Errorf("Failed to unmarshal ConsumeRecord request: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0004", errcode.InvalidParams.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.InvalidParams.Code,
|
||||||
|
ResultMsg: "请求数据格式错误",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.criminalService.ConsumeRecord(ctx, &record)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to process ConsumeRecord: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0004", errcode.ServerError.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.ServerError.Code,
|
||||||
|
ResultMsg: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理实时余额查询
|
||||||
|
func (s *SocketServer) handleRealTimeBalance(ctx context.Context, data string) *model.CriminalResponse {
|
||||||
|
var req model.CriminalRequest
|
||||||
|
if err := json.Unmarshal([]byte(data), &req); err != nil {
|
||||||
|
logger.Errorf("Failed to unmarshal RealTimeBalance request: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0005", errcode.InvalidParams.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.InvalidParams.Code,
|
||||||
|
ResultMsg: "请求数据格式错误",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.criminalService.RealTimeBalance(ctx, req.FCode)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to process RealTimeBalance: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0005", errcode.ServerError.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.ServerError.Code,
|
||||||
|
ResultMsg: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理发票同步
|
||||||
|
func (s *SocketServer) handleInvoiceSync(ctx context.Context, data string) *model.CriminalResponse {
|
||||||
|
var req model.InvoiceSync
|
||||||
|
if err := json.Unmarshal([]byte(data), &req); err != nil {
|
||||||
|
logger.Errorf("Failed to unmarshal InvoiceSync request: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0006", errcode.InvalidParams.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.InvalidParams.Code,
|
||||||
|
ResultMsg: "请求数据格式错误",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := s.criminalService.InvoiceSync(ctx, req.InvoiceList)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to process InvoiceSync: %v", err)
|
||||||
|
metrics.ErrorCounter.WithLabelValues("0006", errcode.ServerError.Code).Inc()
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.ServerError.Code,
|
||||||
|
ResultMsg: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送响应
|
||||||
|
func (s *SocketServer) sendResponse(conn net.Conn, response *model.CriminalResponse) {
|
||||||
|
jsonData, err := json.Marshal(response)
|
||||||
|
if err != nil {
|
||||||
|
logger.Errorf("Failed to marshal response: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置写超时
|
||||||
|
if err := conn.SetWriteDeadline(time.Now().Add(config.GlobalConfig.Server.WriteTimeout)); err != nil {
|
||||||
|
logger.Errorf("Failed to set write deadline: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造响应消息:长度(4位) + JSON数据
|
||||||
|
message := fmt.Sprintf("%04d%s", len(jsonData), string(jsonData))
|
||||||
|
|
||||||
|
if _, err := conn.Write([]byte(message)); err != nil {
|
||||||
|
logger.Errorf("Failed to send response: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof("Response sent to %s: %s", conn.RemoteAddr().String(), message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优雅关闭
|
||||||
|
func (s *SocketServer) Stop() {
|
||||||
|
logger.Info("Stopping socket server...")
|
||||||
|
|
||||||
|
// 关闭监听器,停止接受新连接
|
||||||
|
if s.listener != nil {
|
||||||
|
s.listener.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 等待所有连接处理完成
|
||||||
|
logger.Info("Waiting for all connections to finish...")
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
s.wg.Wait()
|
||||||
|
close(done)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 设置超时
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
logger.Info("All connections finished")
|
||||||
|
case <-time.After(10 * time.Second):
|
||||||
|
logger.Warn("Timeout waiting for connections to finish")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通知关闭完成
|
||||||
|
close(s.shutdown)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理信号
|
||||||
|
func (s *SocketServer) handleSignal() {
|
||||||
|
c := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
// 等待信号
|
||||||
|
sig := <-c
|
||||||
|
logger.Infof("Received signal: %v", sig)
|
||||||
|
|
||||||
|
// 停止服务器
|
||||||
|
s.Stop()
|
||||||
|
}
|
||||||
151
internal/service/criminal.go
Normal file
151
internal/service/criminal.go
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/model"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/pkg/database"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/pkg/errcode"
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/pkg/logger"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CriminalService 病人服务实现
|
||||||
|
type CriminalService struct {
|
||||||
|
db *gorm.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCriminalService 创建病人服务
|
||||||
|
func NewCriminalService() *CriminalService {
|
||||||
|
return &CriminalService{
|
||||||
|
db: database.GetDB(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CriminalIn 入院登记
|
||||||
|
func (s *CriminalService) CriminalIn(ctx context.Context, fcode string) (*model.CriminalResponse, error) {
|
||||||
|
logger.Info("开始入院登记处理", zap.String("fcode", fcode))
|
||||||
|
|
||||||
|
// TODO: 实现数据库操作
|
||||||
|
// 这里是模拟实现,实际应该从数据库查询
|
||||||
|
info := &model.CriminalInfo{
|
||||||
|
FCode: fcode,
|
||||||
|
FName: "测试病人",
|
||||||
|
AmountA: 100.00,
|
||||||
|
AmountB: 50.00,
|
||||||
|
AmountC: 150.00,
|
||||||
|
BankAccNo: "6222021234567890",
|
||||||
|
BankAmount: 1000.00,
|
||||||
|
Fflag: 0,
|
||||||
|
Flimitflag: 0,
|
||||||
|
Flimitamt: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("入院登记处理完成", zap.String("fcode", fcode))
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.Success.Code,
|
||||||
|
ResultData: info,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeQuota 消费额度查询
|
||||||
|
func (s *CriminalService) ConsumeQuota(ctx context.Context, fcode string) (*model.CriminalResponse, error) {
|
||||||
|
logger.Info("开始消费额度查询", zap.String("fcode", fcode))
|
||||||
|
|
||||||
|
// TODO: 实现数据库操作
|
||||||
|
quota := &model.ConsumeQuota{
|
||||||
|
AmountA: 50.00,
|
||||||
|
AmountB: 30.00,
|
||||||
|
FreeAmountA: 0,
|
||||||
|
FreeAmountB: 0,
|
||||||
|
Checkflag: 0,
|
||||||
|
FCode: fcode,
|
||||||
|
FCriminal: "测试病人",
|
||||||
|
Flag: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("消费额度查询完成", zap.String("fcode", fcode))
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.Success.Code,
|
||||||
|
ResultData: quota,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CriminalOut 出院处理
|
||||||
|
func (s *CriminalService) CriminalOut(ctx context.Context, fcode string) (*model.CriminalResponse, error) {
|
||||||
|
logger.Info("开始出院处理", zap.String("fcode", fcode))
|
||||||
|
// TODO: 实现数据库操作
|
||||||
|
|
||||||
|
logger.Info("出院处理完成", zap.String("fcode", fcode))
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.Success.Code,
|
||||||
|
ResultMsg: "出院处理成功",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConsumeRecord 消费记录
|
||||||
|
func (s *CriminalService) ConsumeRecord(ctx context.Context, record *model.ConsumeRecord) (*model.CriminalResponse, error) {
|
||||||
|
logger.Info("开始保存消费记录",
|
||||||
|
zap.String("fcode", record.FCode),
|
||||||
|
zap.String("invoiceNo", record.InvoiceNo),
|
||||||
|
zap.Float64("amount", record.Amount))
|
||||||
|
|
||||||
|
// TODO: 实现数据库操作
|
||||||
|
|
||||||
|
logger.Info("消费记录保存完成", zap.String("fcode", record.FCode))
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.Success.Code,
|
||||||
|
ResultMsg: "消费记录保存成功",
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RealTimeBalance 实时余额查询
|
||||||
|
func (s *CriminalService) RealTimeBalance(ctx context.Context, fcode string) (*model.CriminalResponse, error) {
|
||||||
|
logger.Info("开始实时余额查询", zap.String("fcode", fcode))
|
||||||
|
|
||||||
|
// TODO: 实现数据库操作
|
||||||
|
info := &model.CriminalInfo{
|
||||||
|
FCode: fcode,
|
||||||
|
FName: "测试病人",
|
||||||
|
AmountA: 100.00,
|
||||||
|
AmountB: 50.00,
|
||||||
|
AmountC: 150.00,
|
||||||
|
BankAccNo: "6222021234567890",
|
||||||
|
BankAmount: 1000.00,
|
||||||
|
Fflag: 0,
|
||||||
|
Flimitflag: 0,
|
||||||
|
Flimitamt: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("实时余额查询完成", zap.String("fcode", fcode))
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.Success.Code,
|
||||||
|
ResultData: info,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InvoiceSync 发票同步
|
||||||
|
func (s *CriminalService) InvoiceSync(ctx context.Context, invoiceList []string) (*model.CriminalResponse, error) {
|
||||||
|
logger.Info("开始发票同步", zap.Strings("invoiceList", invoiceList))
|
||||||
|
|
||||||
|
// TODO: 实现数据库操作
|
||||||
|
results := make([]model.InvoiceSyncResult, 0)
|
||||||
|
for _, invoice := range invoiceList {
|
||||||
|
result := model.InvoiceSyncResult{
|
||||||
|
BankFlag: 2,
|
||||||
|
CAmount: 100.00,
|
||||||
|
FCode: "3516022343",
|
||||||
|
Origid: invoice,
|
||||||
|
SendDate: time.Now(),
|
||||||
|
}
|
||||||
|
results = append(results, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Info("发票同步完成", zap.Int("count", len(results)))
|
||||||
|
return &model.CriminalResponse{
|
||||||
|
ResultCode: errcode.Success.Code,
|
||||||
|
ResultData: results,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
28
internal/service/interface.go
Normal file
28
internal/service/interface.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/emsoft/HospitalPay-Go/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ICriminalService 病人服务接口
|
||||||
|
type ICriminalService interface {
|
||||||
|
// CriminalIn 入院登记
|
||||||
|
CriminalIn(ctx context.Context, fcode string) (*model.CriminalResponse, error)
|
||||||
|
|
||||||
|
// ConsumeQuota 消费额度查询
|
||||||
|
ConsumeQuota(ctx context.Context, fcode string) (*model.CriminalResponse, error)
|
||||||
|
|
||||||
|
// CriminalOut 出院处理
|
||||||
|
CriminalOut(ctx context.Context, fcode string) (*model.CriminalResponse, error)
|
||||||
|
|
||||||
|
// ConsumeRecord 消费记录
|
||||||
|
ConsumeRecord(ctx context.Context, record *model.ConsumeRecord) (*model.CriminalResponse, error)
|
||||||
|
|
||||||
|
// RealTimeBalance 实时余额查询
|
||||||
|
RealTimeBalance(ctx context.Context, fcode string) (*model.CriminalResponse, error)
|
||||||
|
|
||||||
|
// InvoiceSync 发票同步
|
||||||
|
InvoiceSync(ctx context.Context, invoiceList []string) (*model.CriminalResponse, error)
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user