接入阿里云二要素
This commit is contained in:
194
internal/infrastructure/external/alicloud/README.md
vendored
Normal file
194
internal/infrastructure/external/alicloud/README.md
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
# 阿里云二要素验证服务
|
||||
|
||||
这个服务提供了调用阿里云身份证二要素验证API的功能,用于验证姓名和身份证号码是否匹配。
|
||||
|
||||
## 功能特性
|
||||
|
||||
- 身份证二要素验证(姓名 + 身份证号)
|
||||
- 支持详细验证结果返回
|
||||
- 支持简单布尔值判断
|
||||
- 错误处理和中文错误信息
|
||||
|
||||
## 配置说明
|
||||
|
||||
### 必需配置
|
||||
|
||||
- `Host`: 阿里云API的域名地址
|
||||
- `AppCode`: 阿里云市场应用的AppCode
|
||||
|
||||
### 配置示例
|
||||
|
||||
```go
|
||||
host := "https://kzidcardv1.market.alicloudapi.com"
|
||||
appCode := "您的AppCode"
|
||||
```
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 创建服务实例
|
||||
|
||||
```go
|
||||
service := NewAlicloudService(host, appCode)
|
||||
```
|
||||
|
||||
### 2. 调用API
|
||||
|
||||
#### 身份证二要素验证示例
|
||||
|
||||
```go
|
||||
// 构建请求参数
|
||||
params := map[string]interface{}{
|
||||
"name": "张三",
|
||||
"idcard": "110101199001011234",
|
||||
}
|
||||
|
||||
// 调用API
|
||||
responseBody, err := service.CallAPI("api-mall/api/id_card/check", params)
|
||||
if err != nil {
|
||||
log.Printf("验证失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析完整响应结构
|
||||
var response struct {
|
||||
Msg string `json:"msg"`
|
||||
Success bool `json:"success"`
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
Birthday string `json:"birthday"`
|
||||
Result int `json:"result"`
|
||||
Address string `json:"address"`
|
||||
OrderNo string `json:"orderNo"`
|
||||
Sex string `json:"sex"`
|
||||
Desc string `json:"desc"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(responseBody, &response); err != nil {
|
||||
log.Printf("响应解析失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查响应状态
|
||||
if response.Code != 200 {
|
||||
log.Printf("API返回错误: code=%d, msg=%s", response.Code, response.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
idCardData := response.Data
|
||||
|
||||
// 判断验证结果
|
||||
if idCardData.Result == 1 {
|
||||
fmt.Println("身份证信息验证通过")
|
||||
} else {
|
||||
fmt.Println("身份证信息验证失败")
|
||||
}
|
||||
```
|
||||
|
||||
#### 通用API调用
|
||||
|
||||
```go
|
||||
// 调用其他阿里云API
|
||||
params := map[string]interface{}{
|
||||
"param1": "value1",
|
||||
"param2": "value2",
|
||||
}
|
||||
|
||||
responseBody, err := service.CallAPI("your/api/path", params)
|
||||
if err != nil {
|
||||
log.Printf("API调用失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 根据具体API的响应结构进行解析
|
||||
// 每个API的响应结构可能不同,需要根据API文档定义相应的结构体
|
||||
var response struct {
|
||||
Msg string `json:"msg"`
|
||||
Code int `json:"code"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(responseBody, &response); err != nil {
|
||||
log.Printf("响应解析失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 处理响应数据
|
||||
fmt.Printf("响应数据: %s\n", string(responseBody))
|
||||
```
|
||||
|
||||
## 响应格式
|
||||
|
||||
### 通用响应结构
|
||||
|
||||
```json
|
||||
{
|
||||
"msg": "成功",
|
||||
"success": true,
|
||||
"code": 200,
|
||||
"data": {
|
||||
// 具体的业务数据
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 身份证验证响应示例
|
||||
|
||||
#### 成功响应 (code: 200)
|
||||
|
||||
```json
|
||||
{
|
||||
"msg": "成功",
|
||||
"success": true,
|
||||
"code": 200,
|
||||
"data": {
|
||||
"birthday": "19840816",
|
||||
"result": 1,
|
||||
"address": "浙江省杭州市淳安县",
|
||||
"orderNo": "202406271440416095174",
|
||||
"sex": "男",
|
||||
"desc": "不一致"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 参数错误响应 (code: 400)
|
||||
|
||||
```json
|
||||
{
|
||||
"msg": "请输入有效的身份证号码",
|
||||
"code": 400,
|
||||
"data": null
|
||||
}
|
||||
```
|
||||
|
||||
### 错误响应
|
||||
|
||||
```json
|
||||
{
|
||||
"msg": "AppCode无效",
|
||||
"success": false,
|
||||
"code": 400
|
||||
}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
服务定义了以下错误类型:
|
||||
|
||||
- `ErrDatasource`: 数据源异常
|
||||
- `ErrSystem`: 系统异常
|
||||
- `ErrInvalid`: 身份证信息不匹配
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 请确保您的AppCode有效且有足够的调用额度
|
||||
2. 身份证号码必须是18位有效格式
|
||||
3. 姓名必须是真实有效的姓名
|
||||
4. 建议在生产环境中添加适当的重试机制和超时设置
|
||||
5. 请遵守阿里云API的使用规范和频率限制
|
||||
|
||||
## 依赖
|
||||
|
||||
- Go 1.16+
|
||||
- 标准库:`net/http`, `encoding/json`, `net/url`
|
||||
82
internal/infrastructure/external/alicloud/alicloud_service.go
vendored
Normal file
82
internal/infrastructure/external/alicloud/alicloud_service.go
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
package alicloud
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrDatasource = errors.New("数据源异常")
|
||||
ErrSystem = errors.New("系统异常")
|
||||
)
|
||||
|
||||
// AlicloudConfig 阿里云配置
|
||||
type AlicloudConfig struct {
|
||||
Host string
|
||||
AppCode string
|
||||
}
|
||||
|
||||
// AlicloudService 阿里云服务
|
||||
type AlicloudService struct {
|
||||
config AlicloudConfig
|
||||
}
|
||||
|
||||
// NewAlicloudService 创建阿里云服务实例
|
||||
func NewAlicloudService(host, appCode string) *AlicloudService {
|
||||
return &AlicloudService{
|
||||
config: AlicloudConfig{
|
||||
Host: host,
|
||||
AppCode: appCode,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CallAPI 调用阿里云API的通用方法
|
||||
// path: API路径(如 "api-mall/api/id_card/check")
|
||||
// params: 请求参数
|
||||
func (a *AlicloudService) CallAPI(path string, params map[string]interface{}) (respBytes []byte, err error) {
|
||||
// 构建请求URL
|
||||
reqURL := a.config.Host + "/" + path
|
||||
|
||||
// 构建请求参数
|
||||
formData := url.Values{}
|
||||
for key, value := range params {
|
||||
formData.Set(key, fmt.Sprintf("%v", value))
|
||||
}
|
||||
|
||||
// 创建HTTP请求
|
||||
req, err := http.NewRequest("POST", reqURL, strings.NewReader(formData.Encode()))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrSystem, err.Error())
|
||||
}
|
||||
|
||||
// 设置请求头
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
|
||||
req.Header.Set("Authorization", "APPCODE "+a.config.AppCode)
|
||||
|
||||
// 发送请求
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrSystem, err.Error())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 读取响应体
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrSystem, err.Error())
|
||||
}
|
||||
|
||||
// 直接返回原始响应body,让调用方自己处理
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// GetConfig 获取配置信息
|
||||
func (a *AlicloudService) GetConfig() AlicloudConfig {
|
||||
return a.config
|
||||
}
|
||||
143
internal/infrastructure/external/alicloud/alicloud_service_test.go
vendored
Normal file
143
internal/infrastructure/external/alicloud/alicloud_service_test.go
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
package alicloud
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRealAlicloudAPI(t *testing.T) {
|
||||
// 使用真实的阿里云API配置
|
||||
host := "https://kzidcardv1.market.alicloudapi.com"
|
||||
appCode := "d55b58829efb41c8aa8e86769cba4844"
|
||||
|
||||
service := NewAlicloudService(host, appCode)
|
||||
|
||||
// 测试真实的身份证验证
|
||||
name := "张荣宏"
|
||||
idCard := "45212220000827423X"
|
||||
|
||||
fmt.Printf("开始测试阿里云二要素验证API...\n")
|
||||
fmt.Printf("姓名: %s\n", name)
|
||||
fmt.Printf("身份证: %s\n", idCard)
|
||||
|
||||
// 构建请求参数
|
||||
params := map[string]interface{}{
|
||||
"name": name,
|
||||
"idcard": idCard,
|
||||
}
|
||||
|
||||
// 调用真实API
|
||||
responseBody, err := service.CallAPI("api-mall/api/id_card/check", params)
|
||||
if err != nil {
|
||||
t.Logf("API调用失败: %v", err)
|
||||
fmt.Printf("错误详情: %v\n", err)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
// 打印原始响应数据
|
||||
fmt.Printf("API响应成功!\n")
|
||||
fmt.Printf("原始响应数据: %s\n", string(responseBody))
|
||||
|
||||
// 解析完整响应结构
|
||||
var response struct {
|
||||
Msg string `json:"msg"`
|
||||
Success bool `json:"success"`
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
Birthday string `json:"birthday"`
|
||||
Result int `json:"result"`
|
||||
Address string `json:"address"`
|
||||
OrderNo string `json:"orderNo"`
|
||||
Sex string `json:"sex"`
|
||||
Desc string `json:"desc"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(responseBody, &response); err != nil {
|
||||
t.Logf("响应数据解析失败: %v", err)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
// 检查响应状态
|
||||
if response.Code != 200 {
|
||||
t.Logf("API返回错误: code=%d, msg=%s", response.Code, response.Msg)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
idCardData := response.Data
|
||||
|
||||
// 打印详细响应结果
|
||||
fmt.Printf("验证结果: %d\n", idCardData.Result)
|
||||
fmt.Printf("描述: %s\n", idCardData.Desc)
|
||||
fmt.Printf("生日: %s\n", idCardData.Birthday)
|
||||
fmt.Printf("性别: %s\n", idCardData.Sex)
|
||||
fmt.Printf("地址: %s\n", idCardData.Address)
|
||||
fmt.Printf("订单号: %s\n", idCardData.OrderNo)
|
||||
|
||||
// 将完整响应转换为JSON并打印
|
||||
jsonResponse, _ := json.MarshalIndent(idCardData, "", " ")
|
||||
fmt.Printf("完整响应JSON:\n%s\n", string(jsonResponse))
|
||||
|
||||
// 判断验证结果
|
||||
if idCardData.Result == 1 {
|
||||
fmt.Printf("验证结果: 通过\n")
|
||||
} else {
|
||||
fmt.Printf("验证结果: 失败\n")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAlicloudAPIError 测试错误响应
|
||||
func TestAlicloudAPIError(t *testing.T) {
|
||||
// 使用真实的阿里云API配置
|
||||
host := "https://kzidcardv1.market.alicloudapi.com"
|
||||
appCode := "d55b58829efb41c8aa8e86769cba4844"
|
||||
|
||||
service := NewAlicloudService(host, appCode)
|
||||
|
||||
// 测试无效的身份证号码
|
||||
name := "张三"
|
||||
invalidIdCard := "123456789"
|
||||
|
||||
fmt.Printf("测试错误响应 - 无效身份证号\n")
|
||||
fmt.Printf("姓名: %s\n", name)
|
||||
fmt.Printf("身份证: %s\n", invalidIdCard)
|
||||
|
||||
// 构建请求参数
|
||||
params := map[string]interface{}{
|
||||
"name": name,
|
||||
"idcard": invalidIdCard,
|
||||
}
|
||||
|
||||
// 调用真实API
|
||||
responseBody, err := service.CallAPI("api-mall/api/id_card/check", params)
|
||||
if err != nil {
|
||||
fmt.Printf("网络请求错误: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var response struct {
|
||||
Msg string `json:"msg"`
|
||||
Code int `json:"code"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(responseBody, &response); err != nil {
|
||||
fmt.Printf("响应解析失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查是否为错误响应
|
||||
if response.Code != 200 {
|
||||
fmt.Printf("预期的错误响应: code=%d, msg=%s\n", response.Code, response.Msg)
|
||||
fmt.Printf("错误处理正确: API返回错误状态\n")
|
||||
} else {
|
||||
t.Error("期望返回错误,但实际成功")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
76
internal/infrastructure/external/alicloud/example.go
vendored
Normal file
76
internal/infrastructure/external/alicloud/example.go
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package alicloud
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// ExampleUsage 使用示例
|
||||
func ExampleUsage() {
|
||||
// 创建阿里云服务实例
|
||||
// 请替换为您的实际配置
|
||||
host := "https://kzidcardv1.market.alicloudapi.com"
|
||||
appCode := "您的AppCode"
|
||||
|
||||
service := NewAlicloudService(host, appCode)
|
||||
|
||||
// 示例:验证身份证信息
|
||||
name := "张三"
|
||||
idCard := "110101199001011234"
|
||||
|
||||
// 构建请求参数
|
||||
params := map[string]interface{}{
|
||||
"name": name,
|
||||
"idcard": idCard,
|
||||
}
|
||||
|
||||
// 调用API
|
||||
responseBody, err := service.CallAPI("api-mall/api/id_card/check", params)
|
||||
if err != nil {
|
||||
log.Printf("验证失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析完整响应结构
|
||||
var response struct {
|
||||
Msg string `json:"msg"`
|
||||
Success bool `json:"success"`
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
Birthday string `json:"birthday"`
|
||||
Result int `json:"result"`
|
||||
Address string `json:"address"`
|
||||
OrderNo string `json:"orderNo"`
|
||||
Sex string `json:"sex"`
|
||||
Desc string `json:"desc"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(responseBody, &response); err != nil {
|
||||
log.Printf("响应解析失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查响应状态
|
||||
if response.Code != 200 {
|
||||
log.Printf("API返回错误: code=%d, msg=%s", response.Code, response.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
idCardData := response.Data
|
||||
|
||||
fmt.Printf("验证结果: %d\n", idCardData.Result)
|
||||
fmt.Printf("描述: %s\n", idCardData.Desc)
|
||||
fmt.Printf("生日: %s\n", idCardData.Birthday)
|
||||
fmt.Printf("性别: %s\n", idCardData.Sex)
|
||||
fmt.Printf("地址: %s\n", idCardData.Address)
|
||||
fmt.Printf("订单号: %s\n", idCardData.OrderNo)
|
||||
|
||||
// 判断验证结果
|
||||
if idCardData.Result == 1 {
|
||||
fmt.Println("身份证信息验证通过")
|
||||
} else {
|
||||
fmt.Println("身份证信息验证失败")
|
||||
}
|
||||
}
|
||||
162
internal/infrastructure/external/alicloud/example_advanced.go
vendored
Normal file
162
internal/infrastructure/external/alicloud/example_advanced.go
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
package alicloud
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
// ExampleAdvancedUsage 高级使用示例
|
||||
func ExampleAdvancedUsage() {
|
||||
// 创建阿里云服务实例
|
||||
host := "https://kzidcardv1.market.alicloudapi.com"
|
||||
appCode := "您的AppCode"
|
||||
|
||||
service := NewAlicloudService(host, appCode)
|
||||
|
||||
// 示例1: 身份证二要素验证
|
||||
fmt.Println("=== 示例1: 身份证二要素验证 ===")
|
||||
exampleIdCardCheck(service)
|
||||
|
||||
// 示例2: 其他API调用(假设)
|
||||
fmt.Println("\n=== 示例2: 其他API调用 ===")
|
||||
exampleOtherAPI(service)
|
||||
}
|
||||
|
||||
// exampleIdCardCheck 身份证验证示例
|
||||
func exampleIdCardCheck(service *AlicloudService) {
|
||||
// 构建请求参数
|
||||
params := map[string]interface{}{
|
||||
"name": "张三",
|
||||
"idcard": "110101199001011234",
|
||||
}
|
||||
|
||||
// 调用API
|
||||
responseBody, err := service.CallAPI("api-mall/api/id_card/check", params)
|
||||
if err != nil {
|
||||
log.Printf("身份证验证失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 解析完整响应结构
|
||||
var response struct {
|
||||
Msg string `json:"msg"`
|
||||
Success bool `json:"success"`
|
||||
Code int `json:"code"`
|
||||
Data struct {
|
||||
Birthday string `json:"birthday"`
|
||||
Result int `json:"result"`
|
||||
Address string `json:"address"`
|
||||
OrderNo string `json:"orderNo"`
|
||||
Sex string `json:"sex"`
|
||||
Desc string `json:"desc"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(responseBody, &response); err != nil {
|
||||
log.Printf("响应解析失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查响应状态
|
||||
if response.Code != 200 {
|
||||
log.Printf("API返回错误: code=%d, msg=%s", response.Code, response.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
idCardData := response.Data
|
||||
|
||||
// 处理验证结果
|
||||
fmt.Printf("验证结果: %d (%s)\n", idCardData.Result, idCardData.Desc)
|
||||
fmt.Printf("生日: %s\n", idCardData.Birthday)
|
||||
fmt.Printf("性别: %s\n", idCardData.Sex)
|
||||
fmt.Printf("地址: %s\n", idCardData.Address)
|
||||
fmt.Printf("订单号: %s\n", idCardData.OrderNo)
|
||||
|
||||
if idCardData.Result == 1 {
|
||||
fmt.Println("✅ 身份证信息验证通过")
|
||||
} else {
|
||||
fmt.Println("❌ 身份证信息验证失败")
|
||||
}
|
||||
}
|
||||
|
||||
// exampleOtherAPI 其他API调用示例
|
||||
func exampleOtherAPI(service *AlicloudService) {
|
||||
// 假设调用其他API
|
||||
params := map[string]interface{}{
|
||||
"param1": "value1",
|
||||
"param2": "value2",
|
||||
}
|
||||
|
||||
// 调用API
|
||||
responseBody, err := service.CallAPI("other/api/path", params)
|
||||
if err != nil {
|
||||
log.Printf("API调用失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 根据具体API的响应结构进行解析
|
||||
// 这里只是示例,实际使用时需要根据API文档定义相应的结构体
|
||||
fmt.Printf("API响应数据: %s\n", string(responseBody))
|
||||
|
||||
// 示例:解析通用响应结构
|
||||
var genericData map[string]interface{}
|
||||
if err := json.Unmarshal(responseBody, &genericData); err != nil {
|
||||
log.Printf("响应解析失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("解析后的数据: %+v\n", genericData)
|
||||
}
|
||||
|
||||
// ExampleErrorHandling 错误处理示例
|
||||
func ExampleErrorHandling() {
|
||||
host := "https://kzidcardv1.market.alicloudapi.com"
|
||||
appCode := "您的AppCode"
|
||||
|
||||
service := NewAlicloudService(host, appCode)
|
||||
|
||||
// 测试各种错误情况
|
||||
testCases := []struct {
|
||||
name string
|
||||
idCard string
|
||||
desc string
|
||||
}{
|
||||
{"张三", "123456789", "无效身份证号"},
|
||||
{"", "110101199001011234", "空姓名"},
|
||||
{"张三", "", "空身份证号"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
fmt.Printf("\n测试: %s\n", tc.desc)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"name": tc.name,
|
||||
"idcard": tc.idCard,
|
||||
}
|
||||
|
||||
responseBody, err := service.CallAPI("api-mall/api/id_card/check", params)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 网络请求错误: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 解析响应
|
||||
var response struct {
|
||||
Msg string `json:"msg"`
|
||||
Code int `json:"code"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(responseBody, &response); err != nil {
|
||||
fmt.Printf("❌ 响应解析失败: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if response.Code != 200 {
|
||||
fmt.Printf("❌ 预期错误: code=%d, msg=%s\n", response.Code, response.Msg)
|
||||
} else {
|
||||
fmt.Printf("⚠️ 意外成功\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user