Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19060d2ce1 | ||
|
|
a24c2068ef |
@@ -2,8 +2,8 @@
|
||||
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
|
||||
wiki_page: Troubleshooting
|
||||
wiki_url: https://git.ilapage.cn/OPC/goauto/wiki/Troubleshooting
|
||||
wiki_revision: 03ea269058b50fea2be7842b9c284018987c82d9
|
||||
synchronized_at: 2026-09-21T08:14:54Z
|
||||
wiki_revision: cc305694c6d7a6dfaa0e2eb150183fd36bb864a6
|
||||
synchronized_at: 2026-10-05T06:51:22Z
|
||||
<!-- gitea-wiki-mirror:end -->
|
||||
|
||||
# 故障排查
|
||||
@@ -104,3 +104,11 @@ adb -s <device-serial> exec-out run-as cn.ilapage.goauto.agent cat files/purchas
|
||||
```
|
||||
|
||||
先列出文件,再读取本次任务/attempt 的准确文件名;不得扩大为导出所有应用数据或完整数据库。新版安装前的失败不会补生成日志;需要用户授权后重试才能产生新证据。Release 若禁止 run-as 则停止,不更改权限绕过;首版没有导出界面。该功能用于确定拒绝分支,并不代表已经修复对应采购故障。
|
||||
## SYB 商品列表查询等待(#355)
|
||||
|
||||
实现绑定 `a24c206`,仅 Web 客户端;已通过本地合成数据测试与构建,尚未合并 main 或发布线上。
|
||||
|
||||
- `web/src/api/goauto/syb-products.js` 的 `listSybProducts` 为 `GET /api/admin/v1/syb-products` 单独设置默认 `timeout: 60000`,覆盖 SYB 商品页搜索、翻页和修改每页数量。全局请求默认仍为 10000ms,其他页面及详情、AI 匹配、采购、采集、退货操作的原超时不变。
|
||||
- 保留现有加载、错误提示、取消和旧请求隔离逻辑,不增加自动重试。慢请求在 10~60 秒间完成时不再被原 10 秒客户端预算提前中止;超过 60 秒仍会超时,上游更短的超时也可能先终止请求。
|
||||
- 此调整不优化后端执行速度。处理阶段筛选当前先加载候选并计算阶段、后分页;不选店铺且采购类型为全部时,候选可能很大。遇到持续慢查询,应另行分析候选预筛选与数据库执行计划,不能据此认为延长前端预算已解决后端性能问题。
|
||||
- 只需发布包含该提交的 Web 资源即可生效,不要求数据库迁移、Android 安装或后端参数变更;发布仍需人工授权。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listSybProducts(params, options = {}) {
|
||||
return request({ url: '/api/admin/v1/syb-products', method: 'get', params, ...options })
|
||||
return request({ url: '/api/admin/v1/syb-products', method: 'get', params, timeout: 60000, ...options })
|
||||
}
|
||||
|
||||
export function getSybProduct(productId) {
|
||||
|
||||
@@ -2,6 +2,28 @@ import { expect, test } from '@playwright/test'
|
||||
|
||||
const sybProductRoute = [{ path: '/goauto-order-workbench', component: 'Layout', menuName: 'GoAutoOrderWorkbench', title: '订单工作台', visible: '0', children: [{ path: '/syb-products', component: '/goauto/syb-products/index', menuName: 'GoAutoSybProducts', title: 'SYB 商品', visible: '0' }] }]
|
||||
|
||||
test('SYB 商品列表超过 10 秒后仍正常显示,不重复请求', async({ page, context }) => {
|
||||
await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }])
|
||||
let listCalls = 0
|
||||
await page.route('**/api/**', async route => {
|
||||
const url = new URL(route.request().url())
|
||||
if (url.pathname.startsWith('/src/api/')) return route.continue()
|
||||
if (url.pathname.endsWith('/api/v1/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '测试管理员', avatar: '', introduction: '', permissions: [] }}})
|
||||
if (url.pathname.endsWith('/api/v1/menurole')) return route.fulfill({ json: { code: 200, data: sybProductRoute }})
|
||||
if (url.pathname.endsWith('/api/admin/v1/syb-products')) {
|
||||
listCalls++
|
||||
await new Promise(resolve => setTimeout(resolve, 12000))
|
||||
return route.fulfill({ json: { code: 200, data: { items: [{ id: 355, orderCode: 'TEST-355', productTitle: '延迟查询成功的测试商品', quantity: 1, parseStatus: 'success' }], total: 1, page: 1, pageSize: 200 }}})
|
||||
}
|
||||
if (url.pathname.endsWith('/api/admin/v1/purchase-tasks/batch-preview')) return route.fulfill({ json: { code: 200, data: { items: [{ sybProductId: 355, eligible: false, processStage: 'return_pending', processStageLabel: '退货待确认' }] }}})
|
||||
return route.fulfill({ json: { code: 200, data: [] }})
|
||||
})
|
||||
await page.goto('/#/syb-products')
|
||||
await expect(page.getByText('延迟查询成功的测试商品')).toBeVisible({ timeout: 20000 })
|
||||
expect(listCalls).toBe(1)
|
||||
await expect(page.getByText(/timeout of 10000ms exceeded/)).toHaveCount(0)
|
||||
})
|
||||
|
||||
test('SYB 商品首次网络失败时静默重试一次并恢复列表', async({ page, context }) => {
|
||||
await context.addCookies([{ name: 'Admin-Token', value: 'prototype-test-token', domain: 'localhost', path: '/' }])
|
||||
let listCalls = 0
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
const { test } = require('node:test')
|
||||
const assert = require('node:assert/strict')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
|
||||
const source = fs.readFileSync(path.join(__dirname, '../../src/api/goauto/syb-products.js'), 'utf8')
|
||||
const names = [...source.matchAll(/export function (\w+)/g)].map(match => match[1])
|
||||
const load = request => new Function('request', source.replace(/^import .+\n/gm, '').replace(/export function /g, 'function ') + `\nreturn { ${names.join(',')} }`)(request)
|
||||
|
||||
test('search, pagination and page-size changes use the list-only 60-second timeout', () => {
|
||||
const api = load(config => config)
|
||||
for (const params of [
|
||||
{ page: 1, pageSize: 200, shopName: '', processStage: 'return_pending', purchaseType: 'all' },
|
||||
{ page: 2, pageSize: 200 },
|
||||
{ page: 1, pageSize: 500 }
|
||||
]) {
|
||||
const config = api.listSybProducts(params)
|
||||
assert.equal(config.timeout, 60000)
|
||||
assert.equal(config.params, params)
|
||||
assert.equal(config.url, '/api/admin/v1/syb-products')
|
||||
assert.equal(config.method, 'get')
|
||||
}
|
||||
})
|
||||
|
||||
test('existing cancellation and error options are preserved', () => {
|
||||
const controller = new AbortController()
|
||||
const config = load(config => config).listSybProducts({}, { signal: controller.signal, suppressNetworkError: true })
|
||||
assert.equal(config.timeout, 60000)
|
||||
assert.equal(config.signal, controller.signal)
|
||||
assert.equal(config.suppressNetworkError, true)
|
||||
controller.abort()
|
||||
assert.equal(config.signal.aborted, true)
|
||||
})
|
||||
|
||||
test('other SYB API functions do not acquire the list timeout; global timeout stays 10 seconds', () => {
|
||||
const api = load(config => config)
|
||||
for (const name of names.filter(name => name !== 'listSybProducts')) {
|
||||
assert.equal(api[name](1, {}).timeout, undefined, name)
|
||||
}
|
||||
const globalRequest = fs.readFileSync(path.join(__dirname, '../../src/utils/request.js'), 'utf8')
|
||||
assert.match(globalRequest, /timeout:\s*10000\b/)
|
||||
})
|
||||
|
||||
test('timeout and cancellation failures propagate without new retries', async () => {
|
||||
for (const code of ['ECONNABORTED', 'ERR_CANCELED']) {
|
||||
let calls = 0
|
||||
const failure = Object.assign(new Error(code), { code })
|
||||
const api = load(() => { calls++; return Promise.reject(failure) })
|
||||
await assert.rejects(api.listSybProducts({}), error => error === failure)
|
||||
assert.equal(calls, 1)
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user