@7365admin1/layer-common 4.97.1-staging.605 → 4.97.1-staging.606
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -255,6 +255,11 @@
|
|
|
255
255
|
<v-select v-model="jobOpts.levelFlag" :items="CLEAN_POWER_CHOICES" label="Power" density="compact" hide-details class="mb-2" />
|
|
256
256
|
<v-select v-model="jobOpts.cleanTimes" :items="CLEAN_TIMES_CHOICES" label="Times to clean" density="compact" hide-details class="mb-2" />
|
|
257
257
|
</template>
|
|
258
|
+
<!-- A brand with its own named modes (VIGGO): the robot's list + times. -->
|
|
259
|
+
<template v-if="offered.modes">
|
|
260
|
+
<v-select v-model="jobOpts.cleanModeId" :items="robotModeChoices(robotModes)" label="Cleaning mode" density="compact" hide-details class="mb-2" />
|
|
261
|
+
<v-select v-model="jobOpts.cleanTimes" :items="CLEAN_TIMES_CHOICES" label="Times to clean" density="compact" hide-details class="mb-2" />
|
|
262
|
+
</template>
|
|
258
263
|
<v-select v-if="offered.rounds" v-model="jobOpts.rounds" :items="PATROL_ROUND_CHOICES" label="Rounds" density="compact" hide-details class="mb-2" />
|
|
259
264
|
<div class="hero-dialog__body">{{ confirming.text.body }}</div>
|
|
260
265
|
<div v-if="optionsLine" class="hero-dialog__body">{{ optionsLine }}</div>
|
|
@@ -390,8 +395,10 @@ import {
|
|
|
390
395
|
PATROL_ROUND_CHOICES,
|
|
391
396
|
jobOptionsLine,
|
|
392
397
|
jobOptionsOffered,
|
|
398
|
+
robotModeChoices,
|
|
393
399
|
withJobOptions,
|
|
394
400
|
type TJobOptions,
|
|
401
|
+
type TRobotCleanMode,
|
|
395
402
|
} from "../../utils/robot-display";
|
|
396
403
|
|
|
397
404
|
const props = withDefaults(
|
|
@@ -431,6 +438,7 @@ const {
|
|
|
431
438
|
resolveRobotAlerts,
|
|
432
439
|
getPatrolHistory,
|
|
433
440
|
getSiteFaults,
|
|
441
|
+
getRobotRecords,
|
|
434
442
|
} = useRobots();
|
|
435
443
|
|
|
436
444
|
const record = ref<Record<string, any> | null>(null);
|
|
@@ -824,10 +832,21 @@ function pickRoute(id: unknown) {
|
|
|
824
832
|
}
|
|
825
833
|
/* Job options on a start: reset each time the confirm opens. */
|
|
826
834
|
const jobOpts = ref<TJobOptions>({ ...JOB_OPTION_DEFAULTS });
|
|
827
|
-
|
|
828
|
-
const
|
|
829
|
-
|
|
830
|
-
|
|
835
|
+
/** The robot's own cleaning modes (VIGGO reports them in its records), read when a start is confirmed. */
|
|
836
|
+
const robotModes = ref<TRobotCleanMode[]>([]);
|
|
837
|
+
const offered = computed(() => jobOptionsOffered(confirming.value?.kind, robotType.value, caps.value, robotModes.value));
|
|
838
|
+
const optionsLine = computed(() => jobOptionsLine(offered.value, jobOpts.value, robotModes.value));
|
|
839
|
+
watch(confirmOpen, async (open) => {
|
|
840
|
+
if (!open) return;
|
|
841
|
+
jobOpts.value = { ...JOB_OPTION_DEFAULTS };
|
|
842
|
+
const kind = confirming.value?.kind;
|
|
843
|
+
if (record.value?.brand !== "viggo" || (kind !== "full" && kind !== "area")) return;
|
|
844
|
+
try {
|
|
845
|
+
const rec = await getRobotRecords(props.robotId);
|
|
846
|
+
robotModes.value = Array.isArray(rec?.cleanModes) ? rec.cleanModes : [];
|
|
847
|
+
} catch {
|
|
848
|
+
robotModes.value = []; // the job still goes, in the robot's default mode
|
|
849
|
+
}
|
|
831
850
|
});
|
|
832
851
|
function confirmSend(stayHere = false) {
|
|
833
852
|
const c = confirming.value;
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@7365admin1/layer-common",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "4.97.1-staging.
|
|
5
|
+
"version": "4.97.1-staging.606",
|
|
6
6
|
"author": "7365admin1",
|
|
7
7
|
"main": "./nuxt.config.ts",
|
|
8
8
|
"//files": "What a consumer extending this layer actually loads. Without this npm ships the whole working tree - the changesets, the CI workflows, the render harness in tools/ and any scratch directory that happened to exist at publish time. Nuxt resolves a layer by directory, so every runtime directory below has to stay listed; adding a new top-level runtime directory means adding it here too.",
|
|
@@ -16,6 +16,8 @@ export function credentialLabels(brand: unknown): { key: string; token: string }
|
|
|
16
16
|
if (brand === "demo") return { key: "App key (any value)", token: "Token (any value)" };
|
|
17
17
|
// OneWay (Anbot RMS): one API key per company; the second field is the RMS server's address.
|
|
18
18
|
if (brand === "oneway") return { key: "API key", token: "Server address" };
|
|
19
|
+
// VIGGO (Velobotics): an OAuth access token; its API has no robot list, so the robots' VIN numbers are the second field.
|
|
20
|
+
if (brand === "viggo") return { key: "Access token", token: "Robot VIN numbers (comma separated)" };
|
|
19
21
|
return { key: "App key", token: "Token" };
|
|
20
22
|
}
|
|
21
23
|
|
|
@@ -29,12 +31,12 @@ export function credentialTokenDefault(brand: unknown): string {
|
|
|
29
31
|
|
|
30
32
|
/** False when the second field is not a secret (OneWay's server address): shown as plain text. */
|
|
31
33
|
export function credentialTokenIsSecret(brand: unknown): boolean {
|
|
32
|
-
return brand !== "oneway";
|
|
34
|
+
return brand !== "oneway" && brand !== "viggo";
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
/** Brands whose one company credential lists its robots, so Add robot picks the serial (Find robots). */
|
|
36
38
|
export function credentialDiscoverable(brand: unknown): boolean {
|
|
37
|
-
return brand === "ounitech" || brand === "padbot" || brand === "oneway";
|
|
39
|
+
return brand === "ounitech" || brand === "padbot" || brand === "oneway" || brand === "viggo";
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
/** "Enter the AppID and the Secret ..." - `credentialPatch`'s refusal, in the brand's words. */
|
package/utils/robot-display.ts
CHANGED
|
@@ -1968,33 +1968,51 @@ export const PATROL_ROUND_CHOICES = [
|
|
|
1968
1968
|
{ title: "Until stopped", value: 0 },
|
|
1969
1969
|
];
|
|
1970
1970
|
|
|
1971
|
-
export type TJobOptions = { modeFlag: number; subModeFlag: number; levelFlag: number; cleanTimes: number; rounds: number };
|
|
1972
|
-
export const JOB_OPTION_DEFAULTS: TJobOptions = { modeFlag: 1, subModeFlag: 0, levelFlag: 1, cleanTimes: 1, rounds: 1 };
|
|
1971
|
+
export type TJobOptions = { modeFlag: number; subModeFlag: number; levelFlag: number; cleanTimes: number; rounds: number; cleanModeId: number | null };
|
|
1972
|
+
export const JOB_OPTION_DEFAULTS: TJobOptions = { modeFlag: 1, subModeFlag: 0, levelFlag: 1, cleanTimes: 1, rounds: 1, cleanModeId: null };
|
|
1973
|
+
|
|
1974
|
+
/** A cleaning mode from the robot's OWN list (VIGGO 1.1 clean_mode, via records `cleanModes`). */
|
|
1975
|
+
export type TRobotCleanMode = { id: number; name: string };
|
|
1976
|
+
|
|
1977
|
+
/** The robot's own modes as picker choices, its default first (null = whatever the robot uses). */
|
|
1978
|
+
export function robotModeChoices(modes: TRobotCleanMode[] | null | undefined) {
|
|
1979
|
+
const list = (Array.isArray(modes) ? modes : []).filter((m) => Number.isInteger(m?.id) && typeof m?.name === "string" && m.name.trim());
|
|
1980
|
+
return [{ title: "The robot's default", value: null as number | null }, ...list.map((m) => ({ title: m.name.trim(), value: m.id as number | null }))];
|
|
1981
|
+
}
|
|
1973
1982
|
|
|
1974
1983
|
/**
|
|
1975
1984
|
* Which job options the confirm offers: clean options for a cleaning robot whose
|
|
1976
1985
|
* brand declares `cleanOptions`, rounds for a security robot whose brand declares
|
|
1977
1986
|
* `patrolRounds` - only on a start (full / area), never on any other command.
|
|
1978
1987
|
*/
|
|
1979
|
-
export function jobOptionsOffered(
|
|
1988
|
+
export function jobOptionsOffered(
|
|
1989
|
+
kind: unknown,
|
|
1990
|
+
type: unknown,
|
|
1991
|
+
capabilities: Record<string, unknown> | null | undefined,
|
|
1992
|
+
/** The robot's own mode list (a brand without our fixed three, e.g. VIGGO): mode + times are offered from it. */
|
|
1993
|
+
robotModes?: TRobotCleanMode[] | null,
|
|
1994
|
+
) {
|
|
1980
1995
|
const start = kind === "full" || kind === "area";
|
|
1996
|
+
const clean = start && type !== "security" && capabilities?.cleanOptions === true;
|
|
1981
1997
|
return {
|
|
1982
|
-
clean
|
|
1998
|
+
clean,
|
|
1983
1999
|
rounds: start && type === "security" && capabilities?.patrolRounds === true,
|
|
2000
|
+
modes: start && type !== "security" && !clean && robotModeChoices(robotModes).length > 1,
|
|
1984
2001
|
};
|
|
1985
2002
|
}
|
|
1986
2003
|
|
|
1987
2004
|
/** The command body with the picked options (only the offered ones; vacuum-while-washing only for wash). */
|
|
1988
|
-
export function withJobOptions(body: Record<string, unknown>, offered: { clean: boolean; rounds: boolean }, o: TJobOptions) {
|
|
2005
|
+
export function withJobOptions(body: Record<string, unknown>, offered: { clean: boolean; rounds: boolean; modes?: boolean }, o: TJobOptions) {
|
|
1989
2006
|
if (offered.clean) {
|
|
1990
2007
|
return { ...body, modeFlag: o.modeFlag, subModeFlag: o.modeFlag === 2 ? o.subModeFlag : 0, levelFlag: o.levelFlag, cleanTimes: o.cleanTimes };
|
|
1991
2008
|
}
|
|
1992
2009
|
if (offered.rounds) return { ...body, cleanTimes: o.rounds };
|
|
2010
|
+
if (offered.modes) return { ...body, cleanTimes: o.cleanTimes, ...(o.cleanModeId !== null ? { cleanModeId: o.cleanModeId } : {}) };
|
|
1993
2011
|
return body;
|
|
1994
2012
|
}
|
|
1995
2013
|
|
|
1996
2014
|
/** One line under the confirm saying what the options mean for this job. */
|
|
1997
|
-
export function jobOptionsLine(offered: { clean: boolean; rounds: boolean }, o: TJobOptions): string {
|
|
2015
|
+
export function jobOptionsLine(offered: { clean: boolean; rounds: boolean; modes?: boolean }, o: TJobOptions, robotModes?: TRobotCleanMode[] | null): string {
|
|
1998
2016
|
if (offered.clean) {
|
|
1999
2017
|
const mode = CLEAN_MODE_CHOICES.find((c) => c.value === o.modeFlag)?.title ?? "Vacuum";
|
|
2000
2018
|
const power = CLEAN_POWER_CHOICES.find((c) => c.value === o.levelFlag)?.title ?? "Standard";
|
|
@@ -2002,5 +2020,9 @@ export function jobOptionsLine(offered: { clean: boolean; rounds: boolean }, o:
|
|
|
2002
2020
|
return `${mode}, ${power.toLowerCase()} power, ${o.cleanTimes === 1 ? "once" : `${o.cleanTimes} times`}${wet}.`;
|
|
2003
2021
|
}
|
|
2004
2022
|
if (offered.rounds) return o.rounds === 0 ? "It keeps patrolling until someone presses Cancel." : `It patrols the route ${o.rounds === 1 ? "once" : `${o.rounds} times`}.`;
|
|
2023
|
+
if (offered.modes) {
|
|
2024
|
+
const mode = robotModeChoices(robotModes).find((c) => c.value === o.cleanModeId)?.title ?? "The robot's default";
|
|
2025
|
+
return `${mode} mode, ${o.cleanTimes === 1 ? "once" : `${o.cleanTimes} times`}.`;
|
|
2026
|
+
}
|
|
2005
2027
|
return "";
|
|
2006
2028
|
}
|
package/utils/robot-setup.ts
CHANGED
|
@@ -89,6 +89,7 @@ export function offlineReason(robot: Record<string, any>, state: Record<string,
|
|
|
89
89
|
if (robot?.brand === "ounitech") return `${name}: the Ounitech cloud did not answer${why}. Ask Ounitech to link this robot's serial to our account.`;
|
|
90
90
|
if (robot?.brand === "padbot") return `${name}: the PadBot cloud did not answer${why}. Check the robot's key and token.`;
|
|
91
91
|
if (robot?.brand === "oneway") return `${name}: OneWay's RMS did not answer${why}. Check the robot's API key and server address, and ask OneWay to put this robot under our company key.`;
|
|
92
|
+
if (robot?.brand === "viggo") return `${name}: VIGGO's cloud did not answer${why}. Check the robot's access token (it may have expired) and that its VIN is in the saved VIN list.`;
|
|
92
93
|
return `${name}: its cloud did not answer${why}.`;
|
|
93
94
|
}
|
|
94
95
|
return `${name}: its cloud says it is offline - switched off, charging dock unplugged or out of Wi-Fi.`;
|