minor fix

This commit is contained in:
2026-05-08 10:11:45 +08:00
parent eb6df01c06
commit 28a4252852
2 changed files with 49 additions and 47 deletions

View File

@@ -129,27 +129,21 @@
</form> </form>
<script type="text/javascript"> <script type="text/javascript">
const $ = (selectors, fn) => { const $ = (selectors) => {
let e = document.querySelector(selectors); return document.querySelector(selectors);
return fn && e ? fn(e) : e;
}; };
const $$ = (selectors, fn) => { const $$ = (selectors) => {
let e = document.querySelectorAll(selectors); return document.querySelectorAll(selectors);
return fn && e ? fn(e) : e;
}; };
const $$$ = (selectors, event, listener) => { const $$$ = (selectors, event, listener) => {
$(selectors).addEventListener(event, listener); $(selectors).addEventListener(event, listener);
}; };
let Profiles = new Array(); function main(profiles, args, status=null, error=null) {
let Latest = null;
let Status = null;
function main(profiles, args) {
$$$('#begin', 'click', async () => { $$$('#begin', 'click', async () => {
switch (Status) { switch (status) {
case 'READY': case 'READY':
let name = $('#name').value; let name = $('#name').value;
let options = { profile: name }; let options = { profile: name };
@@ -177,19 +171,19 @@ function main(profiles, args) {
} }
}); });
$$$('#begin', 'click', (e) => { $$$('#begin', 'click', () => {
$('#begin > span.icon').removeAttribute('hidden'); $('#begin > span.icon').removeAttribute('hidden');
$('#begin > span.text').innerText = ''; $('#begin > span.text').innerText = '';
$('#begin').classList.remove('pulse'); $('#begin').classList.remove('pulse');
$('#begin').disabled = true; $('#begin').disabled = true;
}); });
$$$('#cancel', 'click', async (e) => { $$$('#cancel', 'click', async () => {
$('#cancel').disabled = true; $('#cancel').disabled = true;
await Rpc2.invoke('cancel'); await Rpc2.invoke('cancel');
}); });
$$$('#skip', 'click', async (e) => { $$$('#skip', 'click', async () => {
$('#skip').disabled = true; $('#skip').disabled = true;
await Rpcs.invoke('skip'); await Rpcs.invoke('skip');
}); });
@@ -200,16 +194,15 @@ function main(profiles, args) {
}); });
$$$('#name', 'change', (e) => { $$$('#name', 'change', (e) => {
let p = Profiles.find(o => o.name === e.target.value); let p = profiles.find(o => o.name === e.target.value);
for (let k of Object.keys(p)) $(`#${k}`, e => e.value = p[k] ?? ''); for (let k of Object.keys(p)) $(`#${k}`)?.setAttribute('value', p[k] ?? '');
}); });
$$$('#all', 'change', (e) => { $$$('#all', 'change', (e) => {
$('#name').disabled = e.target.checked; $('#name').disabled = e.target.checked;
}); });
for (let item of JSON.parse(profiles)) { for (let item of profiles) {
Profiles.push(item);
$('#name').add(new Option(item.name, item.name)); $('#name').add(new Option(item.name, item.name));
$('#name').dispatchEvent(new Event('change')); $('#name').dispatchEvent(new Event('change'));
} }
@@ -236,17 +229,17 @@ function main(profiles, args) {
let logs = Array.from(history); let logs = Array.from(history);
for (let record of logs) { for (let record of logs) {
if (record.levelno >= 40) Latest = record; if (record.levelno >= 40) error = record;
let message = LogRecord.format(record); let message = LogRecord.format(record);
let node = document.createTextNode(new String(message).concat('\n')); let node = document.createTextNode(new String(message).concat('\n'));
$('#messages').appendChild(node); $('#messages').appendChild(node);
$('#messages').scrollTop = $('#messages').scrollHeight; $('#messages').scrollTop = $('#messages').scrollHeight;
} }
Status = await Rpc2.invoke('status'); status = await Rpc2.invoke('status');
$('#statusLabel').innerText = Status.charAt(0).toUpperCase() + Status.slice(1).toLowerCase(); $('#statusLabel').innerText = status.charAt(0).toUpperCase() + status.slice(1).toLowerCase();
switch (Status) { switch (status) {
case 'IDLE': case 'IDLE':
return; return;
case 'READY': case 'READY':
@@ -267,16 +260,13 @@ function main(profiles, args) {
let [t1, t2] = await Rpc2.invoke('uptime').catch(() => []); let [t1, t2] = await Rpc2.invoke('uptime').catch(() => []);
$('#uptimeLabel').innerText = Temporal.Duration.from({ seconds: t1 ?? 0 }).round({ largestUnit: 'hours' }).toLocaleString('en', { style: 'digital' }); $('#uptimeLabel').innerText = Temporal.Duration.from({ seconds: t1 ?? 0 }).round({ largestUnit: 'hours' }).toLocaleString('en', { style: 'digital' });
if (index && limit && t2) { let remaining = index && limit && t2 ? Math.floor((limit - index) / (index / t2)) : 0;
let rate = index / t2; $('#remainingLabel').innerHTML = remaining ? Temporal.Duration.from({ seconds: remaining }).round({ largestUnit: 'hours' }).toLocaleString('en') : '';
let remaining = Math.floor((limit - index) / rate);
$('#remainingLabel').innerHTML = Temporal.Duration.from({ seconds: remaining }).round({ largestUnit: 'hours' }).toLocaleString('en');
}
break; break;
case 'STANDBY': case 'STANDBY':
if (Latest !== null) { if (error !== null) {
alert(`(${Latest.levelname}) ${Latest.msg}\n${Latest.exc_text ?? ''}`); alert(`(${error.levelname}) ${error.msg}\n${error.exc_text ?? ''}`);
Latest = null; error = null;
} }
$('#begin > span.text').innerText = 'Resume'; $('#begin > span.text').innerText = 'Resume';
$('#begin').classList.remove('pulse'); $('#begin').classList.remove('pulse');

44
main.py
View File

@@ -63,11 +63,10 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
t1 = Timer() t1 = Timer()
t2 = Timer() t2 = Timer()
options = dict() options = dict()
profiles: list[Profile] = list()
status = Status.IDLE status = Status.IDLE
def begin(opts: dict, args: dict): def begin(opts: dict, args: dict):
nonlocal options, status nonlocal status
options.update(opts) options.update(opts)
status = Status.RUNNING status = Status.RUNNING
parameters.update(args) parameters.update(args)
@@ -94,20 +93,17 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
jsonrpc2.define('uptime', lambda: [t1.delta()]) jsonrpc2.define('uptime', lambda: [t1.delta()])
try: try:
for source, profile in zip(parameters.get('profile'), repeat(dict())): profiles = [
for key, value in map(lambda o: str.split(o, '=', 2), source): Profile(**{ k.lower().strip(): v.strip() for k, v in map(lambda o: str.split(o, '=', 2), p) })
profile[key.lower().strip()] = value.strip() for p in parameters.get('profile')
]
item = Profile(**profile)
profiles.append(item)
except Exception as e: except Exception as e:
logger.critical('Unable to load profiles', exc_info=e) logger.critical('Unable to load profiles', exc_info=e)
return 2 return 2
try: try:
manifest = json.dumps(profiles, default=vars)
driver.get(str(Path('index.html').resolve())) driver.get(str(Path('index.html').resolve()))
driver.execute_script(jsonrpc2.prelude(), manifest, parameters) driver.execute_script(jsonrpc2.prelude(), list(map(vars, profiles)), parameters)
except Exception as e: except Exception as e:
logger.critical('Unable to load starup page', exc_info=e) logger.critical('Unable to load starup page', exc_info=e)
return 3 return 3
@@ -234,7 +230,7 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
@classmethod @classmethod
def perform(cls): def perform(cls):
nonlocal status nonlocal status
statis = Status.READY status = Status.READY
driver.switch_to.window(driver.window_handles[0]) driver.switch_to.window(driver.window_handles[0])
raise cls raise cls
@@ -380,13 +376,29 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
progress['number'] = number progress['number'] = number
progress['index'] = i-1 progress['index'] = i-1
if (id := item['category_id']) not in categories: if (x := item['category_id']) not in categories:
flow.react() flow.react()
categories[id] = fetch(f'{base}/categories/{id}.json?api_token={profile.token}') response = fetch(f'{base}/categories/{x}.json?api_token={profile.token}')
if (id := item['client_id']) not in clients: if 'error' in response:
error = response['error']
code = response['code']
logger.warning("Error while fetching 'category' (code: %s, message: %s); skipping", code, error)
continue
else:
categories[x] = response
if (x := item['client_id']) not in clients:
flow.react() flow.react()
clients[id] = fetch(f'{base}/clients/{id}.json?api_token={profile.token}') response = fetch(f'{base}/clients/{x}.json?api_token={profile.token}')
if 'error' in response:
error = response['error']
code = response['code']
logger.warning("Error while fetching 'client' (code: %s, message: %s); skipping", code, error)
continue
else:
clients[x] = response
category = categories.get(item['category_id']) category = categories.get(item['category_id'])
client = clients.get(item['client_id']) client = clients.get(item['client_id'])
@@ -535,6 +547,7 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
while index < len(data): while index < len(data):
try: try:
attempts += 1
driver.switch_to.window(driver.window_handles[2]) driver.switch_to.window(driver.window_handles[2])
item = data[index] item = data[index]
kind = item['kind'] kind = item['kind']
@@ -542,7 +555,6 @@ def main(driver: WebDriver, logger = logging.getLogger('main')):
number = profile.format(item['number']) number = profile.format(item['number'])
positions = item['positions'] positions = item['positions']
opportunity = None opportunity = None
attempts += 1
if kind != 'vat': if kind != 'vat':
logger.info('[%d/%d] Skipping %s', index+1, len(data), number) logger.info('[%d/%d] Skipping %s', index+1, len(data), number)