feat: 新增 error 和 pass 两个 DFPWM 二进制文件
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
-1492
File diff suppressed because it is too large
Load Diff
@@ -1,42 +0,0 @@
|
||||
# Debug Session: cdn-backend-unreachable
|
||||
|
||||
- Status: OPEN
|
||||
- Started: 2026-06-20
|
||||
- Symptom:
|
||||
- After enabling Alibaba Cloud CDN for `ticket.fse-media.group`, ticket price calculation fails.
|
||||
- The ticket query page does not display ticket items.
|
||||
- Constraints:
|
||||
- No business logic changes before runtime evidence.
|
||||
- First code change in existing files must be instrumentation only.
|
||||
- Hypotheses:
|
||||
1. CDN origin/path forwarding for API routes is incorrect.
|
||||
2. Frontend requests use relative URLs and now point at the CDN/static origin instead of backend.
|
||||
3. Backend CORS or host validation blocks requests from `ticket.fse-media.group`.
|
||||
4. HTTPS, certificate, or mixed-content policy blocks API requests.
|
||||
- Next steps:
|
||||
1. Locate the ticket-order and ticket-query frontend request code.
|
||||
2. Identify backend API base URL configuration and deployment assumptions.
|
||||
3. Reproduce with browser/network evidence and add instrumentation only if needed.
|
||||
- Runtime evidence:
|
||||
1. Live check on `https://ticket.fse-media.group/order` shows `GET /api/public/lines`, `GET /api/public/stations`, and `GET /api/public/config` all return `200`.
|
||||
2. Live check on `https://ticket.fse-media.group/search` shows `GET /api/public/tickets?q=` and `GET /api/public/popular` succeed, and the ticket list renders 23 rows.
|
||||
3. Direct fetch on the live site confirms `/api/public/fares/query?from=HC-01&to=HC-02` returns valid fare data.
|
||||
4. Frontend code uses same-origin relative API paths, so CDN did not break API origin resolution itself.
|
||||
5. Live responses for `/ticket-order.js`, `/ticket-search.js`, and `/public-status.js` return `Cache-Control: max-age=43200`, while the affected HTML pages reference them without version query parameters.
|
||||
- Hypothesis result:
|
||||
1. CDN origin/path forwarding for API routes is incorrect: falsified by live `200` responses.
|
||||
2. Frontend requests use relative URLs and now point at the wrong origin: falsified by successful same-origin API responses.
|
||||
3. Backend CORS or host validation blocks CDN domain: falsified by successful browser fetches from the production page.
|
||||
4. HTTPS/certificate/mixed-content issue on API requests: not supported by runtime API evidence.
|
||||
- Root cause direction:
|
||||
1. The codebase contained many hardcoded `http://ticket.fse-media.group/...` links in public pages and JS.
|
||||
2. In a CDN + HTTPS deployment, these hardcoded HTTP jumps can split users onto a different protocol path and create intermittent failures or stale-cache behavior.
|
||||
3. The affected public pages loaded critical JS assets without version parameters, while CDN/browser caching allowed 12-hour reuse of older scripts.
|
||||
4. The booking page had an independent selection-state bug: after both endpoints were selected, clicking a new station only replaced the destination and never restarted the origin/destination flow, which made fare/path results look "stuck".
|
||||
- Fix applied:
|
||||
1. Replaced all hardcoded `http://ticket.fse-media.group` links in `web/*.html` and `web/*.js` with `https://ticket.fse-media.group`.
|
||||
2. This keeps all public navigation, ticket detail, and token detail links on the same HTTPS/CDN path as the working API requests.
|
||||
3. Added explicit version query parameters to the critical scripts in `ticket-order.html` and `ticket-search.html` so the CDN fetches a fresh asset URL after deployment.
|
||||
4. Updated `ticket-order.js` so that clicking a new station after a full start/end selection restarts the selection flow and clears stale route highlights.
|
||||
- Pending verification:
|
||||
1. User to verify ticket price calculation and ticket search list under the CDN domain after redeploy/cache refresh.
|
||||
BIN
Binary file not shown.
@@ -1,39 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const dir = path.join(__dirname, 'web');
|
||||
const files = fs.readdirSync(dir).filter(f => f.endsWith('.html'));
|
||||
|
||||
for (const file of files) {
|
||||
let p = path.join(dir, file);
|
||||
let c = fs.readFileSync(p, 'utf8');
|
||||
|
||||
// Fix missing closing quotes for placeholders
|
||||
c = c.replace(/placeholder="中文名 style/g, 'placeholder="中文名" style');
|
||||
c = c.replace(/placeholder="英文名 style/g, 'placeholder="英文名" style');
|
||||
|
||||
// Fix missing < in closing tags
|
||||
c = c.replace(/中文名\/label>/g, '中文名</label>');
|
||||
c = c.replace(/英文名\/label>/g, '英文名</label>');
|
||||
c = c.replace(/特急票价\/label>/g, '特急票价</label>');
|
||||
c = c.replace(/可换乘到的站点\/label>/g, '可换乘到的站点</label>');
|
||||
c = c.replace(/可换乘\/span>/g, '可换乘</span>');
|
||||
c = c.replace(/仪表盘\/div>/g, '仪表盘</div>');
|
||||
c = c.replace(/今日售票额\/div>/g, '今日售票额</div>');
|
||||
c = c.replace(/站点数\/div>/g, '站点数</div>');
|
||||
c = c.replace(/线路与票价\/div>/g, '线路与票价</div>');
|
||||
c = c.replace(/控制台\/div>/g, '控制台</div>');
|
||||
c = c.replace(/控制台\/title>/g, '控制台</title>');
|
||||
c = c.replace(/登录\/title>/g, '登录</title>');
|
||||
c = c.replace(/登录\/div>/g, '登录</div>');
|
||||
c = c.replace(/加载中\.\.\.\/div>/g, '加载中...</div>');
|
||||
c = c.replace(/凭证不存在\/h2>/g, '凭证不存在</h2>');
|
||||
c = c.replace(/凭证码\/th>/g, '凭证码</th>');
|
||||
c = c.replace(/状态\/th>/g, '状态</th>');
|
||||
c = c.replace(/文件名\/th>/g, '文件名</th>');
|
||||
c = c.replace(/文件夹\/th>/g, '文件夹</th>'); // In case it was replaced to this
|
||||
c = c.replace(/生成凭证码\/button>/g, '生成凭证码</button>');
|
||||
c = c.replace(/复制凭证码\/button>/g, '复制凭证码</button>');
|
||||
|
||||
fs.writeFileSync(p, c, 'utf8');
|
||||
}
|
||||
console.log('Done');
|
||||
BIN
Binary file not shown.
@@ -233,7 +233,7 @@
|
||||
</div>
|
||||
|
||||
<script src="/custom-dialog.js?v=11"></script>
|
||||
<script src="/ticket-order.js?v=20"></script>
|
||||
<script src="/ticket-order.js?v=21"></script>
|
||||
<script src="/public-status.js?v=13"></script>
|
||||
<script src="/ai-assistant.js?v=6"></script>
|
||||
<script>
|
||||
|
||||
@@ -408,6 +408,58 @@
|
||||
return merged;
|
||||
}
|
||||
|
||||
function getStationPoint(code) {
|
||||
const normalized = String(code || '').trim();
|
||||
if (!normalized) return null;
|
||||
const canonical = stationCanonicalByCode[normalized] || normalized;
|
||||
const x = stationXByCanonical[canonical];
|
||||
const y = stationYByCanonical[normalized];
|
||||
if (!Number.isFinite(x) || !Number.isFinite(y)) return null;
|
||||
return { x, y };
|
||||
}
|
||||
|
||||
function renderRouteOverlay() {
|
||||
const svgEl = mapContainer.querySelector('svg');
|
||||
if (!svgEl) return;
|
||||
|
||||
const existing = svgEl.querySelector('.route-overlay-group');
|
||||
if (existing) existing.remove();
|
||||
|
||||
if (!Array.isArray(currentRoute) || currentRoute.length < 2) return;
|
||||
|
||||
const points = currentRoute.map(getStationPoint).filter(Boolean);
|
||||
if (points.length < 2) return;
|
||||
|
||||
const ns = 'http://www.w3.org/2000/svg';
|
||||
const group = document.createElementNS(ns, 'g');
|
||||
group.setAttribute('class', 'route-overlay-group');
|
||||
|
||||
const pathData = points.map((pt, idx) => `${idx === 0 ? 'M' : 'L'} ${pt.x} ${pt.y}`).join(' ');
|
||||
|
||||
const glow = document.createElementNS(ns, 'path');
|
||||
glow.setAttribute('d', pathData);
|
||||
glow.setAttribute('fill', 'none');
|
||||
glow.setAttribute('stroke', 'rgba(250, 204, 21, 0.38)');
|
||||
glow.setAttribute('stroke-width', '18');
|
||||
glow.setAttribute('stroke-linecap', 'round');
|
||||
glow.setAttribute('stroke-linejoin', 'round');
|
||||
|
||||
const main = document.createElementNS(ns, 'path');
|
||||
main.setAttribute('d', pathData);
|
||||
main.setAttribute('fill', 'none');
|
||||
main.setAttribute('stroke', '#facc15');
|
||||
main.setAttribute('stroke-width', '8');
|
||||
main.setAttribute('stroke-linecap', 'round');
|
||||
main.setAttribute('stroke-linejoin', 'round');
|
||||
|
||||
group.appendChild(glow);
|
||||
group.appendChild(main);
|
||||
|
||||
const firstStation = svgEl.querySelector('.map-station');
|
||||
if (firstStation) svgEl.insertBefore(group, firstStation);
|
||||
else svgEl.appendChild(group);
|
||||
}
|
||||
|
||||
function updateSelectionUI(skipPreview = false) {
|
||||
if (!(selection[0] && selection[1])) {
|
||||
currentRoute = [];
|
||||
@@ -446,6 +498,8 @@
|
||||
if (el) el.classList.add('route-transfer');
|
||||
}
|
||||
}
|
||||
|
||||
renderRouteOverlay();
|
||||
|
||||
// Auto preview if both selected
|
||||
if(!skipPreview && selection[0] && selection[1]) previewPrice();
|
||||
|
||||
Reference in New Issue
Block a user