793 lines
22 KiB
Go
793 lines
22 KiB
Go
package main
|
||
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"strings"
|
||
"syscall/js"
|
||
"wasm-go/internal/api"
|
||
"wasm-go/internal/excel"
|
||
"wasm-go/internal/prompt"
|
||
)
|
||
|
||
func createErrorJSValue(msg string) js.Value {
|
||
errorObj := map[string]string{"error": msg}
|
||
jsonBytes, _ := json.Marshal(errorObj)
|
||
return js.Global().Get("JSON").Call("parse", string(jsonBytes))
|
||
}
|
||
|
||
var DefaultLLMConfig = LLMConfig{
|
||
Provider: "openai",
|
||
BaseURL: "https://api.deepseek.com",
|
||
Model: "deepseek-v4-flash",
|
||
APIKey: "sk-c2f04b4d635b4df0aace0432f3c6d6f4",
|
||
}
|
||
|
||
func main() {
|
||
// 注册各种功能函数
|
||
js.Global().Set("analyzeCompanyIndustryAsync", js.FuncOf(analyzeCompanyIndustryAsync))
|
||
js.Global().Set("parseExcelAsync", js.FuncOf(parseExcelAsync))
|
||
js.Global().Set("convertExcelToJsonViaLLM", js.FuncOf(convertExcelToJsonViaLLM))
|
||
js.Global().Set("callLLMAsync", js.FuncOf(callLLMAsync))
|
||
js.Global().Set("callTaxHealthAsync", js.FuncOf(callTaxHealthAsync))
|
||
js.Global().Set("queryTaxResultAsync", js.FuncOf(queryTaxResultAsync))
|
||
js.Global().Set("getPrompt", js.FuncOf(getPrompt))
|
||
// 保持程序运行
|
||
select {} // 无限循环,保持程序运行
|
||
}
|
||
|
||
// analyzeCompanyIndustryAsync 异步版本的函数,返回Promise
|
||
func analyzeCompanyIndustryAsync(this js.Value, args []js.Value) interface{} {
|
||
// 获取公司名称参数和配置参数
|
||
companyName := args[0].String()
|
||
configJSON := args[1].String() // 配置参数,可选
|
||
|
||
// 创建一个通道来处理结果
|
||
resultChan := make(chan interface{}, 1)
|
||
errorChan := make(chan error, 1) // 使用error类型而不是interface{}
|
||
|
||
// 在goroutine中执行异步操作
|
||
go func() {
|
||
|
||
config := parseLLMConfig(configJSON)
|
||
|
||
// 创建可配置的LLM客户端
|
||
llmClient := createConfigurableLLMClient(config)
|
||
|
||
// 创建企业行业分类器
|
||
classifier := api.NewCompanyIndustryClassifier(llmClient)
|
||
|
||
// 分析企业行业
|
||
result, err := classifier.ClassifyCompany(companyName)
|
||
if err != nil {
|
||
// 发送错误到错误通道
|
||
errorChan <- err
|
||
} else {
|
||
// 发送结果到结果通道,包含使用的配置信息
|
||
resultWithConfig := map[string]interface{}{
|
||
"data": result,
|
||
}
|
||
resultChan <- resultWithConfig
|
||
}
|
||
}()
|
||
|
||
// 创建Promise
|
||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||
if len(promiseArgs) < 2 {
|
||
// 如果参数不足,返回一个立即拒绝的Promise
|
||
return nil
|
||
}
|
||
|
||
resolve := promiseArgs[0]
|
||
reject := promiseArgs[1]
|
||
|
||
// 启动一个goroutine来处理结果
|
||
go func() {
|
||
select {
|
||
case result := <-resultChan:
|
||
// 将复杂结构体序列化为JSON
|
||
jsonResult, err := json.Marshal(result)
|
||
if err != nil {
|
||
// 序列化失败,返回错误
|
||
reject.Invoke(createErrorJSValue("JSON序列化失败: " + err.Error()))
|
||
return
|
||
}
|
||
|
||
// 将JSON字符串解析为JavaScript对象
|
||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||
resolve.Invoke(jsResult)
|
||
case err := <-errorChan:
|
||
// 将错误转换为JavaScript值
|
||
reject.Invoke(createErrorJSValue(err.Error()))
|
||
}
|
||
}()
|
||
|
||
return nil
|
||
}))
|
||
|
||
return promise
|
||
}
|
||
|
||
// parseExcelAsync 解析Excel文件的异步函数
|
||
func parseExcelAsync(this js.Value, args []js.Value) interface{} {
|
||
// 获取Excel文件的ArrayBuffer
|
||
arrayBuffer := args[0]
|
||
uint8Array := js.Global().Get("Uint8Array").New(arrayBuffer)
|
||
|
||
// 创建字节切片
|
||
length := uint8Array.Get("length").Int()
|
||
excelBytes := make([]byte, length)
|
||
|
||
// 将数据复制到Go字节切片
|
||
for i := 0; i < length; i++ {
|
||
excelBytes[i] = byte(uint8Array.Index(i).Int())
|
||
}
|
||
|
||
// 创建一个通道来处理结果
|
||
resultChan := make(chan interface{}, 1)
|
||
errorChan := make(chan error, 1)
|
||
|
||
// 在goroutine中执行异步操作
|
||
go func() {
|
||
// 创建Excel读取器
|
||
reader, err := excel.NewXLSXReaderFromBytes(excelBytes)
|
||
if err != nil {
|
||
errorChan <- err
|
||
return
|
||
}
|
||
|
||
// 读取所有工作表
|
||
sheetNames, err := reader.GetSheetNames()
|
||
if err != nil {
|
||
errorChan <- err
|
||
return
|
||
}
|
||
|
||
sheets := make(map[string][][]string)
|
||
sheetErrors := make(map[string]string)
|
||
|
||
for _, sheetName := range sheetNames {
|
||
sheetData, err := reader.GetSheetData(sheetName)
|
||
if err != nil {
|
||
sheetErrors[sheetName] = err.Error()
|
||
continue
|
||
}
|
||
sheets[sheetName] = sheetData
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"sheets": sheets,
|
||
}
|
||
if len(sheetErrors) > 0 {
|
||
result["errors"] = sheetErrors
|
||
}
|
||
|
||
resultChan <- result
|
||
}()
|
||
|
||
// 创建Promise
|
||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||
if len(promiseArgs) < 2 {
|
||
// 如果参数不足,返回一个立即拒绝的Promise
|
||
return nil
|
||
}
|
||
|
||
resolve := promiseArgs[0]
|
||
reject := promiseArgs[1]
|
||
|
||
// 启动一个goroutine来处理结果
|
||
go func() {
|
||
select {
|
||
case result := <-resultChan:
|
||
jsonResult, err := json.Marshal(result)
|
||
if err != nil {
|
||
reject.Invoke(createErrorJSValue("JSON序列化失败: " + err.Error()))
|
||
return
|
||
}
|
||
|
||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||
resolve.Invoke(jsResult)
|
||
case err := <-errorChan:
|
||
reject.Invoke(createErrorJSValue(err.Error()))
|
||
}
|
||
}()
|
||
|
||
return nil
|
||
}))
|
||
|
||
return promise
|
||
}
|
||
|
||
// getPrompt 获取提示词
|
||
func getPrompt(this js.Value, args []js.Value) interface{} {
|
||
period := args[0].String()
|
||
// 根据period映射相应的prompt
|
||
var pmt string
|
||
switch period {
|
||
case "Q1", "第一季度":
|
||
pmt = prompt.Quarterly2Prompt
|
||
case "Q2", "第二季度":
|
||
pmt = prompt.Quarterly2Prompt
|
||
case "Q3", "第三季度":
|
||
pmt = prompt.Quarterly3Prompt
|
||
case "年度":
|
||
pmt = prompt.AnnualPrompt
|
||
default:
|
||
pmt = `你是一个专业的财务数据分析师。请分析以下财务报表数据,并将其转换为适合税务健康评估的JSON格式。只需要返回JSON数据,不要包含其他解释文字。返回格式应该是一个包含财务指标及其数值的对象,例如:{"LC0000003E_T0I0331": 741213833.14, "LC0000003E_T0I0101": 578064138.06}`
|
||
}
|
||
// 创建一个通道来处理结果
|
||
resultChan := make(chan interface{}, 1)
|
||
errorChan := make(chan error, 1)
|
||
|
||
go func() {
|
||
allows := []string{"Q1", "第一季度", "Q2", "第二季度", "Q3", "第三季度", "年度"}
|
||
isValid := false
|
||
for _, allowed := range allows {
|
||
if allowed == period {
|
||
isValid = true
|
||
break
|
||
}
|
||
}
|
||
if isValid {
|
||
result := map[string]interface{}{
|
||
"prompt": pmt,
|
||
"period": period,
|
||
}
|
||
resultChan <- result
|
||
} else {
|
||
errorChan <- fmt.Errorf("所选周期错误,支持的周期: Q1, 第一季度, Q2, 第二季度, Q3, 第三季度, 年度")
|
||
return
|
||
}
|
||
|
||
}()
|
||
|
||
// 创建Promise
|
||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||
if len(promiseArgs) < 2 {
|
||
// 如果参数不足,返回一个立即拒绝的Promise
|
||
return nil
|
||
}
|
||
|
||
resolve := promiseArgs[0]
|
||
reject := promiseArgs[1]
|
||
|
||
// 启动一个goroutine来处理结果
|
||
go func() {
|
||
select {
|
||
case result := <-resultChan:
|
||
jsonResult, err := json.Marshal(result)
|
||
if err != nil {
|
||
reject.Invoke(createErrorJSValue("JSON序列化失败: " + err.Error()))
|
||
return
|
||
}
|
||
|
||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||
resolve.Invoke(jsResult)
|
||
case err := <-errorChan:
|
||
reject.Invoke(createErrorJSValue(err.Error()))
|
||
}
|
||
}()
|
||
|
||
return nil
|
||
}))
|
||
|
||
return promise
|
||
|
||
}
|
||
|
||
// convertExcelToJsonViaLLM 将Excel数据通过LLM转换为JSON格式的函数
|
||
func convertExcelToJsonViaLLM(this js.Value, args []js.Value) interface{} {
|
||
// 获取Excel文件的ArrayBuffer和参数
|
||
arrayBuffer := args[0]
|
||
period := args[1].String() // 期间参数 (Q1, Q2, Q3, Q4, 年度等)
|
||
configJSON := args[2].String() // 配置参数,可选
|
||
|
||
// 根据period映射相应的prompt
|
||
var pmt string
|
||
switch period {
|
||
case "Q1", "第一季度":
|
||
pmt = prompt.Quarterly1Prompt
|
||
case "Q2", "第二季度":
|
||
pmt = prompt.Quarterly2Prompt
|
||
case "Q3", "第三季度":
|
||
pmt = prompt.Quarterly3Prompt
|
||
case "年度":
|
||
pmt = prompt.AnnualPrompt
|
||
default:
|
||
pmt = `你是一个专业的财务数据分析师。请分析以下财务报表数据,并将其转换为适合税务健康评估的JSON格式。只需要返回JSON数据,不要包含其他解释文字。返回格式应该是一个包含财务指标及其数值的对象,例如:{"LC0000003E_T0I0331": 741213833.14, "LC0000003E_T0I0101": 578064138.06}`
|
||
}
|
||
|
||
// 创建字节切片
|
||
uint8Array := js.Global().Get("Uint8Array").New(arrayBuffer)
|
||
length := uint8Array.Get("length").Int()
|
||
excelBytes := make([]byte, length)
|
||
|
||
// 将数据复制到Go字节切片
|
||
for i := 0; i < length; i++ {
|
||
excelBytes[i] = byte(uint8Array.Index(i).Int())
|
||
}
|
||
|
||
// 创建一个通道来处理结果
|
||
resultChan := make(chan interface{}, 1)
|
||
errorChan := make(chan error, 1)
|
||
|
||
// 在goroutine中执行异步操作
|
||
go func() {
|
||
// 创建Excel读取器
|
||
reader, err := excel.NewXLSXReaderFromBytes(excelBytes)
|
||
if err != nil {
|
||
errorChan <- err
|
||
return
|
||
}
|
||
|
||
// 读取所有工作表
|
||
sheetNames, err := reader.GetSheetNames()
|
||
if err != nil {
|
||
errorChan <- err
|
||
return
|
||
}
|
||
|
||
sheets := make(map[string][][]string)
|
||
sheetErrors := make(map[string]string)
|
||
|
||
for _, sheetName := range sheetNames {
|
||
sheetData, err := reader.GetSheetData(sheetName)
|
||
if err != nil {
|
||
sheetErrors[sheetName] = err.Error()
|
||
continue
|
||
}
|
||
sheets[sheetName] = sheetData
|
||
}
|
||
|
||
if len(sheetErrors) > 0 {
|
||
errorChan <- fmt.Errorf("部分工作表读取失败: %v", sheetErrors)
|
||
return
|
||
}
|
||
|
||
var allMarkdownTables strings.Builder
|
||
allMarkdownTables.WriteString("以下是Excel表格的数据:\n\n")
|
||
|
||
for sheetName, data := range sheets {
|
||
if len(data) == 0 {
|
||
continue
|
||
}
|
||
|
||
allMarkdownTables.WriteString(fmt.Sprintf("## 工作表: %s\n", sheetName))
|
||
markdown := excel.ConvertToMarkdown(data)
|
||
allMarkdownTables.WriteString(markdown)
|
||
allMarkdownTables.WriteString("\n\n")
|
||
}
|
||
|
||
// 合并提示词和表格数据
|
||
finalPrompt := fmt.Sprintf("%s\n\n%s", pmt, allMarkdownTables.String())
|
||
|
||
config := parseLLMConfig(configJSON)
|
||
|
||
// 创建可配置的LLM客户端
|
||
llmClient := createConfigurableLLMClient(config)
|
||
|
||
// 调用大模型
|
||
response, err := llmClient.Chat([]api.ChatMessage{
|
||
{Role: "user", Content: finalPrompt},
|
||
})
|
||
if err != nil {
|
||
errorChan <- err
|
||
return
|
||
}
|
||
if response == nil {
|
||
errorChan <- fmt.Errorf("LLM响应为空")
|
||
return
|
||
}
|
||
|
||
// 解析LLM返回的响应,提取JSON内容
|
||
parsedJSON := extractJSONFromResponse(response.Choices[0].Message.Content)
|
||
|
||
// 尝试将解析的JSON字符串转换为map结构
|
||
var jsonData map[string]interface{}
|
||
if err := json.Unmarshal([]byte(parsedJSON), &jsonData); err != nil {
|
||
// 如果解析失败,返回原始字符串
|
||
result := map[string]interface{}{
|
||
"raw_response": response.Choices[0].Message.Content,
|
||
"parsed_json": parsedJSON,
|
||
"conversion": "success",
|
||
"parse_error": err.Error(),
|
||
}
|
||
resultChan <- result
|
||
} else {
|
||
// 成功解析为JSON对象
|
||
result := map[string]interface{}{
|
||
"json_data": jsonData,
|
||
"raw_response": response.Choices[0].Message.Content,
|
||
"conversion": "success",
|
||
}
|
||
resultChan <- result
|
||
}
|
||
}()
|
||
|
||
// 创建Promise
|
||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||
if len(promiseArgs) < 2 {
|
||
// 如果参数不足,返回一个立即拒绝的Promise
|
||
return nil
|
||
}
|
||
|
||
resolve := promiseArgs[0]
|
||
reject := promiseArgs[1]
|
||
|
||
// 启动一个goroutine来处理结果
|
||
go func() {
|
||
select {
|
||
case result := <-resultChan:
|
||
jsonResult, err := json.Marshal(result)
|
||
if err != nil {
|
||
reject.Invoke(createErrorJSValue("JSON序列化失败: " + err.Error()))
|
||
return
|
||
}
|
||
|
||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||
resolve.Invoke(jsResult)
|
||
case err := <-errorChan:
|
||
reject.Invoke(createErrorJSValue(err.Error()))
|
||
}
|
||
}()
|
||
|
||
return nil
|
||
}))
|
||
|
||
return promise
|
||
}
|
||
|
||
// LLMConfig 定义大模型客户端配置
|
||
type LLMConfig struct {
|
||
Provider string `json:"provider"` // "ollama" 或 "openai"
|
||
BaseURL string `json:"base_url"`
|
||
Model string `json:"model"`
|
||
APIKey string `json:"api_key,omitempty"`
|
||
}
|
||
|
||
func parseLLMConfig(configJSON string) LLMConfig {
|
||
var config LLMConfig
|
||
if configJSON != "" {
|
||
if err := json.Unmarshal([]byte(configJSON), &config); err != nil {
|
||
fmt.Printf("解析LLM配置失败: %v\n", err)
|
||
config = DefaultLLMConfig
|
||
}
|
||
}
|
||
if config.Provider == "" || config.Provider == "default" {
|
||
config = DefaultLLMConfig
|
||
}
|
||
return config
|
||
}
|
||
|
||
// createConfigurableLLMClient 创建可配置的大模型客户端
|
||
func createConfigurableLLMClient(config LLMConfig) *api.LLMClient {
|
||
|
||
switch strings.ToLower(config.Provider) {
|
||
case "ollama":
|
||
return api.NewOllamaClient(config.BaseURL, config.Model)
|
||
case "openai":
|
||
return api.NewOpenAIClient(config.APIKey, config.Model, config.BaseURL)
|
||
default:
|
||
// 默认使用Ollama
|
||
return api.NewOllamaClient(config.BaseURL, config.Model)
|
||
}
|
||
}
|
||
|
||
// extractJSONFromResponse 从LLM响应中提取JSON内容
|
||
// 查找并提取 ```json {...} ``` 或 ``` {...} ``` 中的内容
|
||
func extractJSONFromResponse(response string) string {
|
||
// 首先尝试匹配 ```json 开头的代码块
|
||
start := strings.Index(response, "```json")
|
||
if start != -1 {
|
||
start += 7 // 跳过 "```json"
|
||
end := strings.Index(response[start:], "```")
|
||
if end != -1 {
|
||
jsonContent := strings.TrimSpace(response[start : start+end])
|
||
return jsonContent
|
||
}
|
||
}
|
||
|
||
// 然后尝试匹配 ``` 开头的代码块(假设是JSON)
|
||
start = strings.Index(response, "```")
|
||
if start != -1 {
|
||
start += 3 // 跳过 "```"
|
||
end := strings.Index(response[start:], "```")
|
||
if end != -1 {
|
||
jsonContent := strings.TrimSpace(response[start : start+end])
|
||
// 检查是否看起来像JSON
|
||
jsonContent = strings.TrimSpace(jsonContent)
|
||
if strings.HasPrefix(jsonContent, "{") || strings.HasPrefix(jsonContent, "[") {
|
||
return jsonContent
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果没有找到代码块,尝试直接解析整个响应是否为JSON
|
||
response = strings.TrimSpace(response)
|
||
if strings.HasPrefix(response, "{") && strings.HasSuffix(response, "}") ||
|
||
strings.HasPrefix(response, "[") && strings.HasSuffix(response, "]") {
|
||
return response
|
||
}
|
||
|
||
// 如果以上都失败,返回原内容
|
||
return response
|
||
}
|
||
|
||
// callLLMAsync 调用大模型的异步函数
|
||
func callLLMAsync(this js.Value, args []js.Value) interface{} {
|
||
// 获取提示词参数和配置参数
|
||
prompt := args[0].String()
|
||
configJSON := args[1].String() // 配置参数,可选
|
||
|
||
// 创建一个通道来处理结果
|
||
resultChan := make(chan interface{}, 1)
|
||
errorChan := make(chan error, 1)
|
||
|
||
// 在goroutine中执行异步操作
|
||
go func() {
|
||
config := parseLLMConfig(configJSON)
|
||
|
||
// 创建可配置的LLM客户端
|
||
llmClient := createConfigurableLLMClient(config)
|
||
|
||
// 调用大模型
|
||
response, err := llmClient.Chat([]api.ChatMessage{
|
||
{Role: "user", Content: prompt},
|
||
})
|
||
if response == nil {
|
||
errorChan <- fmt.Errorf("LLM响应为空")
|
||
return
|
||
}
|
||
if err != nil {
|
||
errorChan <- err
|
||
return
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"response": response.Choices[0].Message.Content,
|
||
}
|
||
|
||
resultChan <- result
|
||
}()
|
||
|
||
// 创建Promise
|
||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||
if len(promiseArgs) < 2 {
|
||
// 如果参数不足,返回一个立即拒绝的Promise
|
||
return nil
|
||
}
|
||
|
||
resolve := promiseArgs[0]
|
||
reject := promiseArgs[1]
|
||
|
||
// 启动一个goroutine来处理结果
|
||
go func() {
|
||
select {
|
||
case result := <-resultChan:
|
||
jsonResult, err := json.Marshal(result)
|
||
if err != nil {
|
||
reject.Invoke(createErrorJSValue("JSON序列化失败: " + err.Error()))
|
||
return
|
||
}
|
||
|
||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||
resolve.Invoke(jsResult)
|
||
case err := <-errorChan:
|
||
reject.Invoke(createErrorJSValue(err.Error()))
|
||
}
|
||
}()
|
||
|
||
return nil
|
||
}))
|
||
|
||
return promise
|
||
}
|
||
|
||
// callTaxHealthAsync 调用税务健康API的异步函数
|
||
// 注意:由于WASM环境的CORS限制,我们需要通过后端代理调用真实API
|
||
func callTaxHealthAsync(this js.Value, args []js.Value) interface{} {
|
||
// 获取公司信息参数
|
||
companyInfoJSON := args[0].String()
|
||
|
||
// 创建一个通道来处理结果
|
||
resultChan := make(chan interface{}, 1)
|
||
errorChan := make(chan error, 1)
|
||
|
||
// 在goroutine中执行异步操作
|
||
go func() {
|
||
// 解析输入的JSON参数
|
||
var requestData map[string]interface{}
|
||
err := json.Unmarshal([]byte(companyInfoJSON), &requestData)
|
||
if err != nil {
|
||
errorChan <- err
|
||
return
|
||
}
|
||
|
||
// 从输入数据中提取各个字段
|
||
reqNo, _ := requestData["req_no"].(string)
|
||
callback, _ := requestData["callback"].(string)
|
||
companyName, _ := requestData["company_name"].(string)
|
||
period, _ := requestData["period"].(string)
|
||
year, _ := requestData["year"].(string)
|
||
cit, _ := requestData["cit"].(float64)
|
||
vat, _ := requestData["vat"].(float64)
|
||
inputVat, _ := requestData["input_vat"].(float64)
|
||
outputVat, _ := requestData["output_vat"].(float64)
|
||
preCIT, _ := requestData["pre_cit"].(float64)
|
||
preVAT, _ := requestData["pre_vat"].(float64)
|
||
preInputVat, _ := requestData["pre_input_vat"].(float64)
|
||
preOutputVat, _ := requestData["pre_output_vat"].(float64)
|
||
|
||
// 检查是否提供了Excel文件URL
|
||
fileUrl, hasFileUrl := requestData["file_url"].(string)
|
||
|
||
// 从requestData中获取data字段
|
||
data, hasData := requestData["data"].(map[string]interface{})
|
||
if !hasData {
|
||
// 尝试将整个 requestData 的 data 部分作为map
|
||
if dataSlice, ok := requestData["data"].([]interface{}); ok {
|
||
// 转换slice为map
|
||
data = make(map[string]interface{})
|
||
for _, item := range dataSlice {
|
||
if itemMap, ok := item.(map[string]interface{}); ok {
|
||
for k, v := range itemMap {
|
||
data[k] = v
|
||
}
|
||
}
|
||
}
|
||
hasData = true
|
||
}
|
||
}
|
||
|
||
// 创建税务健康服务客户端
|
||
// 注意:在真实的实现中,这些应该是安全存储的
|
||
taxHealthService := api.NewTaxHealthService("1554047490758508546", "00d502fcac7a2b0e227751cd6d8b0c725c55f71adcaccc6a50c4d63c73db6c8add")
|
||
|
||
// 构建税务评估请求
|
||
request := api.TaxEvalRequest{
|
||
ReqNo: reqNo,
|
||
Callback: callback,
|
||
Detail: api.TaxEvalDetail{
|
||
CompanyName: companyName,
|
||
Period: period,
|
||
Year: year,
|
||
CIT: cit,
|
||
VAT: vat,
|
||
InputVAT: inputVat,
|
||
OutputVAT: outputVat,
|
||
PreCIT: preCIT,
|
||
PreVAT: preVAT,
|
||
PreInputVAT: preInputVat,
|
||
PreOutputVAT: preOutputVat,
|
||
},
|
||
}
|
||
|
||
// 如果有文件URL,则使用文件URL;否则使用数据
|
||
if hasFileUrl && fileUrl != "" {
|
||
request.Detail.FileURL = fileUrl
|
||
} else if hasData {
|
||
request.Detail.Data = data
|
||
}
|
||
|
||
// 调用税务健康API
|
||
taxResponse, err := taxHealthService.EvaluateTaxHealth(request)
|
||
if err != nil {
|
||
errorChan <- err
|
||
return
|
||
}
|
||
|
||
// 检查是否成功获取订单号
|
||
if taxResponse.Code != 200 || taxResponse.Data.OrderNo == "" {
|
||
errorChan <- fmt.Errorf("税务健康API调用失败或未返回订单号: %+v", taxResponse)
|
||
return
|
||
}
|
||
|
||
orderNo := taxResponse.Data.OrderNo
|
||
|
||
// 轮询查询结果,最多等待5分钟(60次 * 5秒)
|
||
// 注意:在WASM环境中,我们不能使用长时间阻塞操作
|
||
// 因此这里只是返回订单号,轮询应该在前端JavaScript中处理
|
||
result := map[string]interface{}{
|
||
"initial_response": taxResponse,
|
||
"order_no": orderNo,
|
||
"message": "税务评估已提交,正在处理中,请使用订单号查询结果",
|
||
}
|
||
|
||
resultChan <- result
|
||
}()
|
||
|
||
// 创建Promise
|
||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||
if len(promiseArgs) < 2 {
|
||
// 如果参数不足,返回一个立即拒绝的Promise
|
||
return nil
|
||
}
|
||
|
||
resolve := promiseArgs[0]
|
||
reject := promiseArgs[1]
|
||
|
||
// 启动一个goroutine来处理结果
|
||
go func() {
|
||
select {
|
||
case result := <-resultChan:
|
||
jsonResult, err := json.Marshal(result)
|
||
if err != nil {
|
||
reject.Invoke(createErrorJSValue("JSON序列化失败: " + err.Error()))
|
||
return
|
||
}
|
||
|
||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||
resolve.Invoke(jsResult)
|
||
case err := <-errorChan:
|
||
reject.Invoke(createErrorJSValue(err.Error()))
|
||
}
|
||
}()
|
||
|
||
return nil
|
||
}))
|
||
|
||
return promise
|
||
}
|
||
|
||
// queryTaxResultAsync 查询税务评估结果的异步函数
|
||
func queryTaxResultAsync(this js.Value, args []js.Value) interface{} {
|
||
// 获取订单号参数
|
||
orderNo := args[0].String()
|
||
|
||
// 创建一个通道来处理结果
|
||
resultChan := make(chan interface{}, 1)
|
||
errorChan := make(chan error, 1)
|
||
|
||
// 在goroutine中执行异步操作
|
||
go func() {
|
||
// 创建税务健康服务客户端
|
||
taxHealthService := api.NewTaxHealthService("1554047490758508546", "00d502fcac7a2b0e227751cd6d8b0c725c55f71adcaccc6a50c4d63c73db6c8add")
|
||
|
||
// 查询税务评估结果
|
||
queryResponse, err := taxHealthService.QueryTaxEvalResult(orderNo)
|
||
if err != nil {
|
||
errorChan <- err
|
||
return
|
||
}
|
||
|
||
result := map[string]interface{}{
|
||
"query_response": queryResponse,
|
||
"message": "查询税务评估结果成功",
|
||
}
|
||
|
||
resultChan <- result
|
||
}()
|
||
|
||
// 创建Promise
|
||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||
if len(promiseArgs) < 2 {
|
||
// 如果参数不足,返回一个立即拒绝的Promise
|
||
return nil
|
||
}
|
||
|
||
resolve := promiseArgs[0]
|
||
reject := promiseArgs[1]
|
||
|
||
// 启动一个goroutine来处理结果
|
||
go func() {
|
||
select {
|
||
case result := <-resultChan:
|
||
jsonResult, err := json.Marshal(result)
|
||
if err != nil {
|
||
reject.Invoke(createErrorJSValue("JSON序列化失败: " + err.Error()))
|
||
return
|
||
}
|
||
|
||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||
resolve.Invoke(jsResult)
|
||
case err := <-errorChan:
|
||
reject.Invoke(createErrorJSValue(err.Error()))
|
||
}
|
||
}()
|
||
|
||
return nil
|
||
}))
|
||
|
||
return promise
|
||
}
|