diff --git a/data/customers.json b/data/customers.json index 8422af0..a35e955 100644 --- a/data/customers.json +++ b/data/customers.json @@ -1,22 +1,22 @@ [ { - "id": "24849eb6e78a42998d0b7b08b5979756", - "createdAt": "2026-01-04T12:14:26.825475+08:00", - "customerName": "2025-12-22", - "intendedProduct": "予芯", + "id": "b933a0edb8cb4d1a85fdd6ca50fc4376", + "createdAt": "2026-01-07T16:40:38.094131+08:00", + "customerName": "予芯", + "intendedProduct": "2025/12/22", "version": "1.9.4", "description": "训练失败看不到错误日志", "solution": "已解决", "type": "功能问题", "module": "模型工坊", - "statusProgress": "", + "statusProgress": "已修复", "reporter": "" }, { - "id": "a10e4beaa8134473bfd80fba4b33aee7", - "createdAt": "2026-01-04T12:14:26.826755+08:00", - "customerName": "2025/12/23", - "intendedProduct": "诺因智能", + "id": "179dd08fe93d4fbf9c078c362486aa65", + "createdAt": "2026-01-07T16:40:38.095578+08:00", + "customerName": "诺因智能", + "intendedProduct": "2025/12/23", "version": "1.9.4", "description": "客户端上传大文件失败", "solution": "技术优化,修复中", @@ -26,10 +26,10 @@ "reporter": "" }, { - "id": "20188f28fe1e40e589e171a542cf3a26", - "createdAt": "2026-01-04T12:14:26.827195+08:00", - "customerName": "2025/12/23", - "intendedProduct": "良业集团", + "id": "2700f88f74c94903a48369c86e05221a", + "createdAt": "2026-01-07T16:40:38.096324+08:00", + "customerName": "良业", + "intendedProduct": "2025/12/23", "version": "1.9.4", "description": "数据集发布感觉操作繁琐,如果在模型工坊里直接选择需要训练的图片会更方便", "solution": "", @@ -39,10 +39,10 @@ "reporter": "" }, { - "id": "b1f033d8f2b54b5cae52764f9e4eb727", - "createdAt": "2026-01-04T12:14:26.827545+08:00", - "customerName": "2025/12/25", - "intendedProduct": "斯蒂尔", + "id": "7ae437bfeaa84e579b012a4ec5fae794", + "createdAt": "2026-01-07T16:40:38.097176+08:00", + "customerName": "斯蒂尔", + "intendedProduct": "2025/12/25", "version": "1.9.4", "description": "1.试用账号图片生成速度比较慢(2分钟1张图)\n2.生图效果不理想", "solution": "试用资源有限", @@ -52,10 +52,10 @@ "reporter": "" }, { - "id": "ce7df9ffeab34998a040ee0af5b21789", - "createdAt": "2026-01-04T12:14:26.827889+08:00", - "customerName": "2025/12/26", - "intendedProduct": "求之", + "id": "e45d0a13be724c129a3c4e446517a940", + "createdAt": "2026-01-07T16:40:38.098053+08:00", + "customerName": "求之", + "intendedProduct": "2025/12/26", "version": "1.9.4", "description": "1.训练过程不太透明,以及无法提前终止模型训练\n2.训练过程无法断点继续训练;\n3.试用账号资源有限,训练时长过长", "solution": "1、训练过程的透明化(日志化)和目前的易用化,有一些产品设计矛盾,之前主要还是在做易用化。\n接下来我们会在更透明,更强的客户对过程的操控粒度上提升。\n2、训练时长的事情实在抱歉,最近客户比较多,我们资源有限", @@ -65,10 +65,10 @@ "reporter": "" }, { - "id": "be855bfa554e4e71abcee1cb5c614c3d", - "createdAt": "2026-01-04T12:14:26.828428+08:00", - "customerName": "2025/12/26", - "intendedProduct": "诺因智能", + "id": "157ee3180f9c47efb38ab52e3a3b2b4f", + "createdAt": "2026-01-07T16:40:38.099239+08:00", + "customerName": "诺因智能", + "intendedProduct": "2025/12/26", "version": "1.9.4", "description": "训练进程显示什么时候上线", "solution": "训练日志可视化,我们大约需要一个月的时间可以满足上线使用", @@ -78,10 +78,10 @@ "reporter": "" }, { - "id": "93924ee960434cf1b3a358321efcf5a5", - "createdAt": "2026-01-04T12:14:26.828857+08:00", - "customerName": "2025/12/26", - "intendedProduct": "诺因智能", + "id": "b7371743ec5549af8ce643e136334ccf", + "createdAt": "2026-01-07T16:40:38.100073+08:00", + "customerName": "诺因智能", + "intendedProduct": "2025/12/26", "version": "1.9.4", "description": "(igev模型)全量训练是指从0开始? 增量是在现在的ckpt上做微调是吗? ", "solution": "全量训练:在加载开源基础的权重上进行增量训练\n增量训练:在您的数据上训练的checkpoint上进行的增量训练", @@ -91,10 +91,10 @@ "reporter": "" }, { - "id": "6d748e5ec8814e938509c0784902e5bc", - "createdAt": "2026-01-04T12:14:26.829476+08:00", - "customerName": "2025/12/26", - "intendedProduct": "斯蒂尔", + "id": "c87211e0dc6b42f1bb2127259cf64e81", + "createdAt": "2026-01-07T16:40:38.101288+08:00", + "customerName": "斯蒂尔", + "intendedProduct": "2025/12/26", "version": "1.9.4", "description": "数据生成效果改进优化方式?试用账号配置卡数", "solution": "4090,24g,然后生图是单卡单线程\n目前系统上挂载了2张GPU", @@ -104,10 +104,10 @@ "reporter": "" }, { - "id": "74e79089d5e7477f8388ad62515704f2", - "createdAt": "2026-01-04T12:14:26.830017+08:00", - "customerName": "2025/12/26", - "intendedProduct": "良业", + "id": "d14245e86d3d4ee399996ba6d26b23de", + "createdAt": "2026-01-07T16:40:38.101877+08:00", + "customerName": "良业", + "intendedProduct": "2025/12/26", "version": "1.9.4", "description": "1、训练时需要添加测试图,无法理解,模型分析结果可以用训练集\n2、训练失败时需提示原因,方便下一步操作。", "solution": "1、训练过程中,根据训练集的数据来更新模型参数;在通过验证集来验证;\n2、训练失败有日志可以查看,您滚动下屏幕至右侧可以看到哈", @@ -117,10 +117,10 @@ "reporter": "" }, { - "id": "f4a97d749e9843419dc74c9990e0035f", - "createdAt": "2026-01-04T12:14:26.830529+08:00", - "customerName": "2025/12/29", - "intendedProduct": "良业", + "id": "e6fe3693b67d406e9edd056fc48c7119", + "createdAt": "2026-01-07T16:40:38.102556+08:00", + "customerName": "良业", + "intendedProduct": "2025/12/29", "version": "1.9.4", "description": "1.试了几个模型,没训练出来,感觉不出效果\n", "solution": "补充数据集", @@ -130,10 +130,10 @@ "reporter": "" }, { - "id": "d8aa7b048820406d932b410ecc3fd83f", - "createdAt": "2026-01-04T12:14:26.830915+08:00", - "customerName": "2025/12/29", - "intendedProduct": "诺因智能", + "id": "ec24619e11014cb4a3e2f6d9e4b2d618", + "createdAt": "2026-01-07T16:40:38.103257+08:00", + "customerName": "诺因智能", + "intendedProduct": "2025/12/29", "version": "1.9.4", "description": "1.总轮数与拓展参数(num_steps)不一致的时候,以哪个为准结束训练", "solution": "目前StereoNet-V2.5支持使用steps参数,其他的还是以epoch为准", @@ -143,10 +143,10 @@ "reporter": "" }, { - "id": "fa1a6afdc1cf47728eb3940be1a554d9", - "createdAt": "2026-01-04T12:14:26.831304+08:00", - "customerName": "2025/12/30", - "intendedProduct": "良业", + "id": "a9fc0da9bee44acba2d43d15e06079ed", + "createdAt": "2026-01-07T16:40:38.10396+08:00", + "customerName": "良业", + "intendedProduct": "2025/12/30", "version": "1.9.4", "description": "户外同一个草坪测试,用yolo检测640*480图片,检测时间\u003c100ms,分割精度\u003c10像素,出错率1/10万,使用x3可以吗?", "solution": "100ms可以", @@ -156,10 +156,10 @@ "reporter": "" }, { - "id": "515c58d6e5184393a60462701ee97768", - "createdAt": "2026-01-04T12:14:26.831727+08:00", - "customerName": "2025/12/30", - "intendedProduct": "良业", + "id": "0bd2e8d859d7466293182181490d56b4", + "createdAt": "2026-01-07T16:40:38.104695+08:00", + "customerName": "良业", + "intendedProduct": "2025/12/30", "version": "1.9.4", "description": "训练任务无效果", "solution": "数据集少了,补数后需要保存快照", @@ -169,10 +169,10 @@ "reporter": "" }, { - "id": "751cbd5497a849888641270f88012b0d", - "createdAt": "2026-01-04T12:14:26.832123+08:00", - "customerName": "2025/12/30", - "intendedProduct": "诺因智能", + "id": "3576f30f7b7d489e91f2c638b9aae7af", + "createdAt": "2026-01-07T16:40:38.105387+08:00", + "customerName": "诺因智能", + "intendedProduct": "2025/12/30", "version": "1.9.4", "description": "现在平台上的V2.5就可以,需要完成的ckpt,这个预计什么时候可以更新啊", "solution": "", @@ -182,25 +182,25 @@ "reporter": "" }, { - "id": "c754c98a22684a9c8cec940869ca7511", - "createdAt": "2026-01-04T12:14:26.832483+08:00", - "customerName": "2025-12-31", - "intendedProduct": "诺因智能", + "id": "1cdb5f53ee734caf859fc0597a60f13a", + "createdAt": "2026-01-07T16:40:38.106029+08:00", + "customerName": "诺因智能", + "intendedProduct": "2025/12/31", "version": "1.9.4", "description": "境外网站的加速,下载部分数据集时速度会很慢", "solution": "", "type": "反馈", - "module": "", + "module": "数据集", "statusProgress": "", "reporter": "" }, { - "id": "876f234b07da45138ec2d85ea4294c9b", - "createdAt": "2026-01-04T12:14:26.83287+08:00", - "customerName": "2025/12/31", - "intendedProduct": "诺因智能", - "version": "1.9.6", - "description": "模型ckpt的匹配,这个可以公开镜像也可以是根据账户权限设置的私有镜像,都OK,但是得有", + "id": "e01001a4667d45e0872d506df39be397", + "createdAt": "2026-01-07T16:40:38.106833+08:00", + "customerName": "诺因智能", + "intendedProduct": "2025/12/31", + "version": "1.9.4", + "description": "诺因智能需要完整的模型 checkpoint,而不仅仅是 backbone 部分", "solution": "", "type": "需求", "module": "模型工坊", @@ -208,11 +208,11 @@ "reporter": "" }, { - "id": "7db1edba452d48f8b5b2e56854bbd92c", - "createdAt": "2026-01-04T12:14:26.833264+08:00", - "customerName": "2025/12/31", - "intendedProduct": "诺因智能", - "version": "1.9.7", + "id": "e52a8badaab840a2a6dd27a614d1e929", + "createdAt": "2026-01-07T16:40:38.107656+08:00", + "customerName": "诺因智能", + "intendedProduct": "2025/12/31", + "version": "1.9.4", "description": "模型推理的指标对比按钮无法选择", "solution": "", "type": "需求", @@ -221,11 +221,11 @@ "reporter": "" }, { - "id": "beca6e1a2791409fb750c4a1ca1c16e8", - "createdAt": "2026-01-04T12:14:26.834896+08:00", - "customerName": "2025/12/31", - "intendedProduct": "诺因智能", - "version": "1.9.8", + "id": "bbf8dd91213b4d96b96bbeb43ed9930e", + "createdAt": "2026-01-07T16:40:38.108654+08:00", + "customerName": "诺因智能", + "intendedProduct": "2025/12/31", + "version": "1.9.4", "description": "推理评测可以增加定量参数,推理的时候能否增加一下epe衡量模型精度的指标", "solution": "", "type": "需求", diff --git a/frontend/index.html b/frontend/index.html index a82e7e4..10d4a71 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -266,12 +266,12 @@
- - + +
- - + +
@@ -371,12 +371,12 @@
- - + +
- - + +
diff --git a/frontend/js/main.js b/frontend/js/main.js index 9c2e740..03cde0c 100644 --- a/frontend/js/main.js +++ b/frontend/js/main.js @@ -351,7 +351,7 @@ document.addEventListener('DOMContentLoaded', function () { // Populate customer filter dropdown function populateCustomerFilter() { console.log('Populating filter, allCustomers:', allCustomers); - const uniqueCustomers = [...new Set(allCustomers.map(c => c.intendedProduct).filter(c => c))]; + const uniqueCustomers = [...new Set(allCustomers.map(c => c.customerName).filter(c => c))]; console.log('Unique customers:', uniqueCustomers); customerFilter.innerHTML = ''; @@ -405,7 +405,7 @@ document.addEventListener('DOMContentLoaded', function () { let next = [...allCustomers]; if (selectedCustomerFilter) { - next = next.filter(c => c.intendedProduct === selectedCustomerFilter); + next = next.filter(c => c.customerName === selectedCustomerFilter); } if (customerSearchQuery) { @@ -450,9 +450,9 @@ document.addEventListener('DOMContentLoaded', function () { ].map(toCsvCell).join(','); const lines = customers.map(c => { - const date = normalizeDateValue(c.customerName) || (c.customerName || ''); + const date = normalizeDateValue(c.intendedProduct) || (c.intendedProduct || ''); const cells = [ - c.intendedProduct || '', + c.customerName || '', c.version || '', c.description || '', c.solution || '', @@ -560,10 +560,10 @@ document.addEventListener('DOMContentLoaded', function () { customers.forEach(customer => { const row = document.createElement('tr'); - const date = customer.customerName || ''; + const date = customer.intendedProduct || ''; const fields = [ - { value: customer.intendedProduct || '', name: 'intendedProduct' }, + { value: customer.customerName || '', name: 'customerName' }, { value: customer.version || '', name: 'version' }, { value: customer.description || '', name: 'description' }, { value: customer.solution || '', name: 'solution' }, @@ -677,8 +677,8 @@ document.addEventListener('DOMContentLoaded', function () { e.preventDefault(); const formData = { - customerName: document.getElementById('customerName').value, - intendedProduct: document.getElementById('intendedProduct').value, + customerName: document.getElementById('createCustomerName').value, + intendedProduct: document.getElementById('createIntendedProduct').value, version: document.getElementById('createVersion').value, description: document.getElementById('createDescription').value, solution: document.getElementById('createSolution').value, @@ -755,8 +755,8 @@ document.addEventListener('DOMContentLoaded', function () { const customer = await response.json(); document.getElementById('editCustomerId').value = customer.id; - document.getElementById('editCustomerName').value = normalizeDateValue(customer.customerName); - document.getElementById('editIntendedProduct').value = customer.intendedProduct || ''; + document.getElementById('editCustomerName').value = customer.customerName || ''; + document.getElementById('editIntendedProduct').value = normalizeDateValue(customer.intendedProduct); document.getElementById('editVersion').value = customer.version || ''; document.getElementById('editDescription').value = customer.description || ''; document.getElementById('editSolution').value = customer.solution || ''; diff --git a/internal/handlers/customer_handler.go b/internal/handlers/customer_handler.go index 3b661a8..2c8b442 100644 --- a/internal/handlers/customer_handler.go +++ b/internal/handlers/customer_handler.go @@ -8,10 +8,10 @@ import ( "strconv" "strings" "time" - + "crm-go/internal/storage" "crm-go/models" - + "github.com/xuri/excelize/v2" ) @@ -28,31 +28,31 @@ func NewCustomerHandler(storage storage.CustomerStorage) *CustomerHandler { func (h *CustomerHandler) GetCustomers(w http.ResponseWriter, r *http.Request) { page := 1 pageSize := 10 - + if pageStr := r.URL.Query().Get("page"); pageStr != "" { if p, err := strconv.Atoi(pageStr); err == nil && p > 0 { page = p } } - + if pageSizeStr := r.URL.Query().Get("pageSize"); pageSizeStr != "" { if ps, err := strconv.Atoi(pageSizeStr); err == nil && ps > 0 { pageSize = ps } } - + customers, err := h.storage.GetAllCustomers() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - + total := len(customers) totalPages := (total + pageSize - 1) / pageSize - + start := (page - 1) * pageSize end := start + pageSize - + if start >= total { customers = []models.Customer{} } else if end > total { @@ -60,7 +60,7 @@ func (h *CustomerHandler) GetCustomers(w http.ResponseWriter, r *http.Request) { } else { customers = customers[start:end] } - + response := map[string]interface{}{ "customers": customers, "total": total, @@ -68,7 +68,7 @@ func (h *CustomerHandler) GetCustomers(w http.ResponseWriter, r *http.Request) { "pageSize": pageSize, "totalPages": totalPages, } - + w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(response) } @@ -78,30 +78,30 @@ func (h *CustomerHandler) GetCustomerByID(w http.ResponseWriter, r *http.Request urlPath := r.URL.Path // The path should be /api/customers/{id} pathParts := strings.Split(urlPath, "/") - + if len(pathParts) < 4 { http.Error(w, "Invalid URL format", http.StatusBadRequest) return } - + id := pathParts[3] // Get the ID from the path - + // Remove query parameters if any if idx := strings.Index(id, "?"); idx != -1 { id = id[:idx] } - + customer, err := h.storage.GetCustomerByID(id) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - + if customer == nil { http.Error(w, "Customer not found", http.StatusNotFound) return } - + w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(customer) } @@ -112,7 +112,7 @@ func (h *CustomerHandler) CreateCustomer(w http.ResponseWriter, r *http.Request) http.Error(w, "Invalid request body", http.StatusBadRequest) return } - + customer := models.Customer{ CustomerName: req.CustomerName, IntendedProduct: req.IntendedProduct, @@ -125,12 +125,12 @@ func (h *CustomerHandler) CreateCustomer(w http.ResponseWriter, r *http.Request) Reporter: req.Reporter, CreatedAt: time.Now(), } - + if err := h.storage.CreateCustomer(customer); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(customer) @@ -141,30 +141,30 @@ func (h *CustomerHandler) UpdateCustomer(w http.ResponseWriter, r *http.Request) urlPath := r.URL.Path // The path should be /api/customers/{id} pathParts := strings.Split(urlPath, "/") - + if len(pathParts) < 4 { http.Error(w, "Invalid URL format", http.StatusBadRequest) return } - + id := pathParts[3] // Get the ID from the path - + // Remove query parameters if any if idx := strings.Index(id, "?"); idx != -1 { id = id[:idx] } - + var req models.UpdateCustomerRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request body", http.StatusBadRequest) return } - + if err := h.storage.UpdateCustomer(id, req); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - + w.WriteHeader(http.StatusOK) } @@ -173,24 +173,24 @@ func (h *CustomerHandler) DeleteCustomer(w http.ResponseWriter, r *http.Request) urlPath := r.URL.Path // The path should be /api/customers/{id} pathParts := strings.Split(urlPath, "/") - + if len(pathParts) < 4 { http.Error(w, "Invalid URL format", http.StatusBadRequest) return } - + id := pathParts[3] // Get the ID from the path - + // Remove query parameters if any if idx := strings.Index(id, "?"); idx != -1 { id = id[:idx] } - + if err := h.storage.DeleteCustomer(id); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - + w.WriteHeader(http.StatusOK) } @@ -200,21 +200,21 @@ func (h *CustomerHandler) ImportCustomers(w http.ResponseWriter, r *http.Request http.Error(w, "Unable to parse form", http.StatusBadRequest) return } - + file, handler, err := r.FormFile("file") if err != nil { http.Error(w, "Unable to get file", http.StatusBadRequest) return } defer file.Close() - + // Check file extension filename := handler.Filename isExcel := strings.HasSuffix(strings.ToLower(filename), ".xlsx") - + importedCount := 0 duplicateCount := 0 - + if isExcel { // Parse as Excel file f, err := excelize.OpenReader(file) @@ -223,62 +223,62 @@ func (h *CustomerHandler) ImportCustomers(w http.ResponseWriter, r *http.Request return } defer f.Close() - + // Get the first sheet sheets := f.GetSheetList() if len(sheets) == 0 { http.Error(w, "No sheets found in Excel file", http.StatusBadRequest) return } - + // Read all rows from the first sheet rows, err := f.GetRows(sheets[0]) if err != nil { http.Error(w, "Unable to read Excel file", http.StatusBadRequest) return } - + // Skip header row if exists for i, row := range rows { if i == 0 { continue // Skip header row } - + if len(row) < 2 { continue // Skip rows with insufficient data } - + customer := models.Customer{ ID: "", // Will be generated by the storage CreatedAt: time.Now(), CustomerName: getValue(row, 0), - IntendedProduct: getValue(row, 1), - Version: getValue(row, 2), - Description: getValue(row, 3), - Solution: getValue(row, 4), - Type: getValue(row, 5), - Module: getValue(row, 6), - StatusProgress: getValue(row, 7), - Reporter: getValue(row, 8), + Version: getValue(row, 1), + Description: getValue(row, 2), + Solution: getValue(row, 3), + Type: getValue(row, 4), + Module: getValue(row, 5), + StatusProgress: getValue(row, 6), + Reporter: getValue(row, 7), + IntendedProduct: getValue(row, 8), } - + // Check for duplicate exists, err := h.storage.CustomerExists(customer) if err != nil { http.Error(w, "Error checking for duplicate customer", http.StatusInternalServerError) return } - + if exists { duplicateCount++ continue // Skip duplicate } - + if err := h.storage.CreateCustomer(customer); err != nil { http.Error(w, "Error saving customer", http.StatusInternalServerError) return } - + importedCount++ } } else { @@ -288,64 +288,64 @@ func (h *CustomerHandler) ImportCustomers(w http.ResponseWriter, r *http.Request http.Error(w, "Unable to read file", http.StatusBadRequest) return } - + reader := csv.NewReader(strings.NewReader(string(content))) records, err := reader.ReadAll() if err != nil { http.Error(w, "Unable to parse CSV file", http.StatusBadRequest) return } - + // Skip header row if exists for i, row := range records { if i == 0 { continue // Skip header row } - + if len(row) < 2 { continue // Skip rows with insufficient data } - + customer := models.Customer{ ID: "", // Will be generated by the storage CreatedAt: time.Now(), CustomerName: getValue(row, 0), - IntendedProduct: getValue(row, 1), - Version: getValue(row, 2), - Description: getValue(row, 3), - Solution: getValue(row, 4), - Type: getValue(row, 5), - Module: getValue(row, 6), - StatusProgress: getValue(row, 7), - Reporter: getValue(row, 8), + Version: getValue(row, 1), + Description: getValue(row, 2), + Solution: getValue(row, 3), + Type: getValue(row, 4), + Module: getValue(row, 5), + StatusProgress: getValue(row, 6), + Reporter: getValue(row, 7), + IntendedProduct: getValue(row, 8), } - + // Check for duplicate exists, err := h.storage.CustomerExists(customer) if err != nil { http.Error(w, "Error checking for duplicate customer", http.StatusInternalServerError) return } - + if exists { duplicateCount++ continue // Skip duplicate } - + if err := h.storage.CreateCustomer(customer); err != nil { http.Error(w, "Error saving customer", http.StatusInternalServerError) return } - + importedCount++ } } - + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]interface{}{ - "message": "Customers imported successfully", - "importedCount": importedCount, + "message": "Customers imported successfully", + "importedCount": importedCount, "duplicateCount": duplicateCount, }) } diff --git a/sample_customers.csv b/sample_customers.csv index d18d8d7..708d4b7 100644 --- a/sample_customers.csv +++ b/sample_customers.csv @@ -1,5 +1,5 @@ -Customer Name,Intended Product,Version,Description,Solution,Type,Module,Status & Progress,Reporter -ABC Company,Product A,v1.0,Enterprise client,Cloud solution,Enterprise,CRM,In Progress,John Doe -XYZ Corp,Product B,v2.1,New prospect,On-premise,Prospect,Sales,Lead,Jane Smith -Tech Solutions,Product C,v1.5,Existing customer,Hybrid,Existing,Support,Closed Won,Mike Johnson -Global Inc,Product A,v2.0,International client,Cloud solution,Enterprise,CRM,Negotiation,Sarah Wilson \ No newline at end of file +客户,版本,描述,解决方案,类型,模块,状态与进度,报告人,时间 +予芯,1.9.4,训练失败看不到错误日志,已解决,功能问题,模型工坊,,管理员,2025-12-22 +诺因智能,1.9.4,客户端上传大文件失败,技术优化,功能问题,数据空间,已修复,管理员,2025-12-23 +良业集团,1.9.4,"数据集发布感觉操作繁琐,如果在模型工坊里直接选择需要训练的图片会更方便",,反馈,"数据集,模型工坊",,管理员,2025-12-23 +斯蒂尔,1.9.4,"1.试用账号图片生成速度比较慢(2分钟1张图); 2.生图效果不理想",试用资源有限,反馈,数据生成,,管理员,2025-12-25 \ No newline at end of file