// Query ERP parent plan table for two group numbers. // Read-only — no clicks, no modifications, no exports. const { chromium } = require('playwright-core'); const PROFILE = 'C:\\Users\\wxy\\AppData\\Local\\LTJT-ERP-Hermes-Chrome'; const CHROME = 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe'; const PLAN_URL = 'https://ltjt.yunzhi.run/System/Business/plan.asp'; const TARGETS = ['LW-260806A-A', 'LW-260623A-A']; async function main() { const context = await chromium.launchPersistentContext(PROFILE, { executablePath: CHROME, headless: false, viewport: { width: 1440, height: 900 }, }); const page = context.pages()[0] || await context.newPage(); try { await page.goto(PLAN_URL, { waitUntil: 'domcontentloaded', timeout: 60000 }); await page.waitForTimeout(5000); // Check for login const loginInput = await page.$('input[name="UserName"]'); if (loginInput) { console.log(JSON.stringify({ status: 'login_required', message: 'ERP session expired' })); return; } // Search by departure date 2026-08-06 // Set date range: S_chufariqi and S_chufarizhi await page.locator('input[name="riqi"][value="chufari"]').check().catch(() => {}); await page.waitForTimeout(800); await page.locator('#S_chufariqi').fill('2026-8-6'); await page.locator('#S_chufarizhi').fill('2026-8-6'); await page.waitForTimeout(300); await page.locator('#SearchButton').click(); await page.waitForTimeout(8000); // Extract all rows from the plan table const rows = await page.evaluate(() => { return Array.from(document.querySelectorAll('tr')).map((tr, idx) => { const text = tr.innerText.replace(/\s+/g, ' ').trim(); const links = Array.from(tr.querySelectorAll('a')).map(a => ({ text: a.innerText.trim(), href: a.getAttribute('href') || '', onclick: a.getAttribute('onclick') || '', })); return { idx, text, links }; }); }); const results = []; for (const target of TARGETS) { // Find rows containing this group number const candidateRows = rows.filter(r => r.text.includes(target)); if (candidateRows.length === 0) { results.push({ groupNo: target, found: false, message: '未在计划表中找到该团号', }); continue; } for (const row of candidateRows) { // Check for 拼单 link const pinDanLink = row.links.find(l => l.text === '拼单'); const chaZhangLink = row.links.find(l => l.text === '查账'); const deleteLink = row.links.find(l => l.text === '删除'); const modifyLink = row.links.find(l => l.text === '修改'); // Extract product name and planned guests from row text // Row format: [idx] [status] [groupNo] [op] [type.] [product] [date] [duration] [returnDate] [plannedGuests] ... const text = row.text; const idxMatch = text.match(/^(\d+)/); const statusMatch = text.match(/(收客中|已停止|已取消)/); const productMatch = text.match(/常规团\.\s*(.+?)\s+\d{4}-\d{1,2}-\d{1,2}/); const plannedMatch = text.match(/计划(\d+)/); results.push({ groupNo: target, found: true, rowIdx: idxMatch ? idxMatch[1] : null, status: statusMatch ? statusMatch[1] : null, product: productMatch ? productMatch[1] : null, plannedGuests: plannedMatch ? parseInt(plannedMatch[1]) : null, hasPinDan: !!pinDanLink, hasChaZhang: !!chaZhangLink, hasDelete: !!deleteLink, hasModify: !!modifyLink, allLinks: row.links.map(l => l.text).filter(Boolean), preview: text.slice(0, 400), }); } } console.log(JSON.stringify({ status: 'ok', results }, null, 2)); } catch (err) { console.log(JSON.stringify({ status: 'error', message: err.message })); } finally { await context.close(); } } main();