diff --git a/src/App.vue b/src/App.vue
index 4e6d0d8..738dbbb 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -28,6 +28,7 @@
const {
updateUser,
updateOnline,
+ updateDeviceBattery,
showDeviceChargingDialog,
clearSessionState,
clearDevice
@@ -74,6 +75,7 @@
const wasOnline = Boolean(online.value);
const nextOnline = Boolean(data.online);
updateOnline(nextOnline);
+ updateDeviceBattery(nextOnline ? data?.battery ?? data?.power : null);
if (!device.value.deviceId || wasOnline === nextOnline) return;
audioManager.play(nextOnline ? "设备已连接" : "设备连接已断开");
}
diff --git a/src/apis.js b/src/apis.js
index 6bf5715..837ddd2 100644
--- a/src/apis.js
+++ b/src/apis.js
@@ -281,6 +281,10 @@ export const getMyDevicesAPI = () => {
return request("GET", "/user/device/getBindings");
};
+export const getDeviceDetailAPI = (deviceId) => {
+ return request("GET", `/user/device/getDetail?deviceId=${encodeURIComponent(deviceId)}`);
+};
+
export const createPractiseAPI = (arrows, time, target) => {
return request("POST", "/user/practice/create", {
shootNumber: arrows,
diff --git a/src/components/AppBackground.vue b/src/components/AppBackground.vue
index 7feadea..94391f8 100644
--- a/src/components/AppBackground.vue
+++ b/src/components/AppBackground.vue
@@ -81,6 +81,13 @@ const props = defineProps({
src="https://static.shelingxingqiu.com/shootmini/static/app-bg9.png"
mode="widthFix"
/>
+
+
{
const goCalibration = async () => {
await laserAimAPI();
uni.navigateTo({
- url: "/pages/calibration",
+ url: "/pages/device/calibration",
});
};
diff --git a/src/pages.json b/src/pages.json
index 524b208..36393ba 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -21,9 +21,6 @@
{
"path": "pages/audio-test"
},
- {
- "path": "pages/calibration"
- },
{
"path": "pages/about-us"
},
@@ -60,12 +57,6 @@
{
"path": "pages/match-page"
},
- {
- "path": "pages/my-device"
- },
- {
- "path": "pages/device-intro"
- },
{
"path": "pages/user"
},
@@ -105,16 +96,10 @@
{
"path": "pages/melee-bow-data"
},
- {
- "path": "pages/mine-bow-data"
- },
- {
- "path": "pages/ota-wifi",
- "style": {
- "navigationStyle": "custom"
- }
- }
- ],
+ {
+ "path": "pages/mine-bow-data"
+ }
+ ],
"globalStyle": {
"backgroundColor": "@bgColor",
"backgroundColorBottom": "@bgColorBottom",
@@ -159,6 +144,27 @@
{
"root": "pages/device",
"pages": [
+ {
+ "path": "my-device"
+ },
+ {
+ "path": "device-bind-success"
+ },
+ {
+ "path": "device-bind-failure"
+ },
+ {
+ "path": "device-intro"
+ },
+ {
+ "path": "ota-wifi",
+ "style": {
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "calibration"
+ },
{
"path": "unbind-device"
}
diff --git a/src/pages/calibration.vue b/src/pages/device/calibration.vue
similarity index 100%
rename from src/pages/calibration.vue
rename to src/pages/device/calibration.vue
diff --git a/src/pages/device/composables/useDeviceBinding.js b/src/pages/device/composables/useDeviceBinding.js
new file mode 100644
index 0000000..568f555
--- /dev/null
+++ b/src/pages/device/composables/useDeviceBinding.js
@@ -0,0 +1,88 @@
+import { bindDeviceAPIV2 } from "@/apis";
+
+export function useDeviceBinding({
+ token,
+ confirmBindTip,
+ binding,
+ updateDevice,
+ deviceDetails,
+ refreshDeviceStatus,
+}) {
+ const showBindFailurePage = () => {
+ uni.hideToast();
+ uni.navigateTo({
+ url: "/pages/device/device-bind-failure",
+ fail: (error) => {
+ console.error("打开绑定失败页失败", error);
+ uni.showToast({ title: "二维码不正确,请重新扫码", icon: "none" });
+ },
+ });
+ };
+
+ const handleScan = () => {
+ uni.scanCode({
+ onlyFromCamera: true,
+ scanType: ["qrCode"],
+ success: (result) => {
+ if (!result?.result) {
+ showBindFailurePage();
+ return;
+ }
+ token.value = result.result;
+ confirmBindTip.value = true;
+ },
+ fail: (error) => {
+ const message = String(error?.errMsg || error?.message || "");
+ if (/cancel|取消/i.test(message)) return;
+ showBindFailurePage();
+ },
+ });
+ };
+
+ const confirmBind = async () => {
+ if (!token.value || binding.value) return;
+ binding.value = true;
+ try {
+ const result = await bindDeviceAPIV2(token.value);
+ confirmBindTip.value = false;
+ if (result?.binded) {
+ uni.showToast({
+ title: "设备已绑定其他账号,请解绑后再绑定",
+ icon: "none",
+ });
+ return;
+ }
+ const deviceId = String(result?.deviceId || "").trim();
+ const deviceName = String(result?.name || result?.deviceName || "").trim();
+ if (!deviceId || !deviceName) {
+ confirmBindTip.value = false;
+ token.value = "";
+ showBindFailurePage();
+ return;
+ }
+ const applyBoundDevice = () => {
+ updateDevice(deviceId, deviceName);
+ deviceDetails.value = result || {};
+ void refreshDeviceStatus();
+ };
+ uni.navigateTo({
+ url: `/pages/device/device-bind-success?deviceId=${encodeURIComponent(deviceId)}`,
+ success: applyBoundDevice,
+ fail: (navigationError) => {
+ applyBoundDevice();
+ console.error("打开绑定成功页失败", navigationError);
+ uni.showToast({ title: "绑定成功,请返回查看设备", icon: "none" });
+ },
+ });
+ } catch (error) {
+ console.error("绑定设备失败", error);
+ confirmBindTip.value = false;
+ token.value = "";
+ showBindFailurePage();
+ } finally {
+ binding.value = false;
+ }
+ };
+
+ return { confirmBind, handleScan, showBindFailurePage };
+}
diff --git a/src/pages/device/composables/useDeviceStatus.js b/src/pages/device/composables/useDeviceStatus.js
new file mode 100644
index 0000000..bea7bb2
--- /dev/null
+++ b/src/pages/device/composables/useDeviceStatus.js
@@ -0,0 +1,129 @@
+import { computed, ref } from "vue";
+import { getDeviceBatteryAPI, getMyDevicesAPI, unbindDeviceAPI } from "@/apis";
+
+export const DEVICE_NAME_STORAGE_KEY = "device_name_overrides";
+
+export function useDeviceStatus({
+ user,
+ device,
+ online,
+ updateDevice,
+ updateOnline,
+ clearDevice,
+ unbindDialogVisible,
+}) {
+ const deviceStatus = ref({});
+ const deviceDetails = ref({});
+
+ const isDeviceOnline = computed(
+ () => deviceStatus.value.online === true || online.value === true
+ );
+ const statusText = computed(() => (isDeviceOnline.value ? "已连接" : "未连接"));
+ const statusClass = computed(() =>
+ isDeviceOnline.value ? "device-status--online" : "device-status--offline"
+ );
+ const battery = computed(() => {
+ const value = Number(
+ deviceStatus.value.battery ?? deviceStatus.value.power ?? 0
+ );
+ return Number.isFinite(value) && value > 0 ? Math.min(100, value) : 0;
+ });
+ const batteryText = computed(() =>
+ battery.value ? `${battery.value}%` : "暂无数据"
+ );
+ const networkText = computed(() => {
+ const netType = String(deviceStatus.value.netType || "").toLowerCase();
+ if (netType === "wifi") return "WiFi";
+ if (netType === "4g") return "4G";
+ return isDeviceOnline.value ? "在线" : "未连接";
+ });
+ const maskedDeviceId = computed(() => {
+ const id = String(device.value.deviceId || "");
+ if (!id) return "暂无设备编号";
+ if (id.length <= 3) return id;
+ return `${"*".repeat(Math.min(5, id.length - 3))}${id.slice(-3)}`;
+ });
+ const deviceRows = computed(() => [
+ { label: "设备型号", value: deviceDetails.value.model || "射灵智能弓" },
+ { label: "当前电量", value: batteryText.value },
+ { label: "连接方式", value: networkText.value },
+ { label: "设备编号", value: maskedDeviceId.value },
+ ]);
+
+ const getDeviceNameOverrides = () => {
+ const value = uni.getStorageSync(DEVICE_NAME_STORAGE_KEY);
+ return value && typeof value === "object" ? value : {};
+ };
+
+ const refreshDeviceStatus = async () => {
+ if (!device.value.deviceId) return;
+ try {
+ const result = await getDeviceBatteryAPI();
+ deviceStatus.value = result || {};
+ updateOnline(result?.online === true);
+ } catch (error) {
+ deviceStatus.value = {};
+ console.log("获取设备状态失败", error);
+ }
+ };
+
+ const syncDeviceBinding = async () => {
+ if (!user.value.id) return;
+ try {
+ const devices = await getMyDevicesAPI();
+ if (Array.isArray(devices?.bindings) && devices.bindings.length > 0) {
+ const currentDevice = devices.bindings[0];
+ const nameOverrides = getDeviceNameOverrides();
+ deviceDetails.value = currentDevice;
+ updateDevice(
+ currentDevice.deviceId,
+ nameOverrides[currentDevice.deviceId] ||
+ currentDevice.deviceName ||
+ currentDevice.name ||
+ "我的智能弓"
+ );
+ await refreshDeviceStatus();
+ return;
+ }
+ clearDevice();
+ deviceStatus.value = {};
+ deviceDetails.value = {};
+ } catch (error) {
+ console.log("同步设备绑定失败", error);
+ }
+ };
+
+ const unbindDevice = async () => {
+ if (!device.value.deviceId) return;
+ try {
+ await unbindDeviceAPI(device.value.deviceId);
+ uni.setStorageSync("calibration", false);
+ clearDevice();
+ deviceStatus.value = {};
+ deviceDetails.value = {};
+ unbindDialogVisible.value = false;
+ uni.showToast({ title: "解绑成功", icon: "success" });
+ } catch (error) {
+ console.error("解绑设备失败", error);
+ if (error?.type === "DEVICE_BIND_INVALID") {
+ clearDevice();
+ unbindDialogVisible.value = false;
+ }
+ }
+ };
+
+ return {
+ batteryText,
+ deviceDetails,
+ deviceRows,
+ getDeviceNameOverrides,
+ isDeviceOnline,
+ maskedDeviceId,
+ networkText,
+ refreshDeviceStatus,
+ statusClass,
+ statusText,
+ syncDeviceBinding,
+ unbindDevice,
+ };
+}
diff --git a/src/pages/device/device-bind-failure.vue b/src/pages/device/device-bind-failure.vue
new file mode 100644
index 0000000..ccfcb12
--- /dev/null
+++ b/src/pages/device/device-bind-failure.vue
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ 二维码不正确,
+ 仅支持扫描射灵智能弓箭的设备二维码。
+
+
+ 重新扫码
+
+
+
+
+
+
+
+
diff --git a/src/pages/device/device-bind-success.vue b/src/pages/device/device-bind-success.vue
new file mode 100644
index 0000000..680334c
--- /dev/null
+++ b/src/pages/device/device-bind-success.vue
@@ -0,0 +1,248 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 新设备首次绑定礼包:
+ 6个月射灵会员
+ 已自动发放至本账号,有效期{{ bindRewardExpireDate }}。
+
+
+
+ 立即查看新手教程
+
+
+
+
+
+
+
+
diff --git a/src/pages/device-intro.vue b/src/pages/device/device-intro.vue
similarity index 96%
rename from src/pages/device-intro.vue
rename to src/pages/device/device-intro.vue
index f780e14..9053872 100644
--- a/src/pages/device-intro.vue
+++ b/src/pages/device/device-intro.vue
@@ -38,7 +38,7 @@ const onScrollView = (e) => {
mode="widthFix"
/>
-
+
+import { computed, onMounted, onUnmounted, ref } from "vue";
+import { onLoad, onShow } from "@dcloudio/uni-app";
+import Container from "@/components/Container.vue";
+import ScreenHint from "@/components/ScreenHint.vue";
+import ModalDialog from "@/components/ModalDialog.vue";
+import { laserAimAPI } from "@/apis";
+import useStore from "@/store";
+import { storeToRefs } from "pinia";
+import { useDeviceBinding } from "./composables/useDeviceBinding";
+import {
+ DEVICE_NAME_STORAGE_KEY,
+ useDeviceStatus,
+} from "./composables/useDeviceStatus";
+
+const store = useStore();
+const { updateDevice, updateOnline, clearDevice } = store;
+const { user, device, online } = storeToRefs(store);
+
+const showTip = ref(false);
+const confirmBindTip = ref(false);
+const unbindDialogVisible = ref(false);
+const nameEditorVisible = ref(false);
+const qrVisible = ref(false);
+const qrSaved = ref(false);
+const editingName = ref("");
+const token = ref("");
+const binding = ref(false);
+const retryScanOnShow = ref(false);
+const calibration = ref(false);
+
+const {
+ deviceDetails,
+ deviceRows,
+ getDeviceNameOverrides,
+ isDeviceOnline,
+ maskedDeviceId,
+ refreshDeviceStatus,
+ statusClass,
+ statusText,
+ syncDeviceBinding,
+ unbindDevice,
+} = useDeviceStatus({
+ user,
+ device,
+ online,
+ updateDevice,
+ updateOnline,
+ clearDevice,
+ unbindDialogVisible,
+});
+
+const { confirmBind, handleScan } = useDeviceBinding({
+ token,
+ confirmBindTip,
+ binding,
+ updateDevice,
+ deviceDetails,
+ refreshDeviceStatus,
+});
+
+const qrImageUrl = computed(
+ () =>
+ deviceDetails.value.qrCode ||
+ deviceDetails.value.qrcode ||
+ deviceDetails.value.qrUrl ||
+ "../../static/device-assets/my-device-qrcode.png"
+);
+const isScanPage = computed(() => !device.value.deviceId && !qrVisible.value);
+const containerBgType = computed(() =>
+ isScanPage.value ? 12 : 0
+);
+const containerBgColor = computed(() =>
+ containerBgType.value === 12 || containerBgType.value === -1
+ ? "transparent"
+ : "#050b19"
+);
+
+// 解绑前展示统一确认弹窗,避免误触解除绑定。
+const openUnbindDialog = () => {
+ unbindDialogVisible.value = true;
+};
+
+const closeUnbindDialog = () => {
+ unbindDialogVisible.value = false;
+};
+
+const openNameEditor = () => {
+ editingName.value = device.value.deviceName || "我的智能弓";
+ nameEditorVisible.value = true;
+};
+
+const closeNameEditor = () => {
+ nameEditorVisible.value = false;
+};
+
+// 当前接口列表没有设备改名接口,先更新页面和本地缓存,后端接口接入时可替换为请求。
+const confirmName = () => {
+ const name = String(editingName.value || "").trim();
+ if (!name) {
+ uni.showToast({ title: "请输入设备名", icon: "none" });
+ return;
+ }
+ if (name.length > 10 || !/^[\u4e00-\u9fa5A-Za-z0-9_-]+$/.test(name)) {
+ uni.showToast({ title: "设备名格式不正确", icon: "none" });
+ return;
+ }
+ updateDevice(device.value.deviceId, name);
+ deviceDetails.value = { ...deviceDetails.value, deviceName: name };
+ const nameOverrides = getDeviceNameOverrides();
+ nameOverrides[device.value.deviceId] = name;
+ uni.setStorageSync(DEVICE_NAME_STORAGE_KEY, nameOverrides);
+ nameEditorVisible.value = false;
+ uni.showToast({ title: "设备名已更新", icon: "success" });
+};
+
+const toDeviceIntroPage = () => {
+ uni.navigateTo({ url: "/pages/device/device-intro" });
+};
+
+const joinWifi = () => {
+ uni.navigateTo({ url: "/pages/device/ota-wifi" });
+};
+
+const goFirmwareUpdate = () => {
+ if (!isDeviceOnline.value) {
+ uni.showToast({ title: "请先开启智能弓", icon: "none" });
+ return;
+ }
+ uni.navigateTo({ url: "/pages/device/ota-wifi" });
+};
+
+const goCalibration = async () => {
+ try {
+ await laserAimAPI();
+ uni.navigateTo({ url: "/pages/device/calibration" });
+ } catch (error) {
+ uni.showToast({ title: "设备未连接,暂时无法调瞄", icon: "none" });
+ }
+};
+
+const copyEmail = () => {
+ uni.setClipboardData({
+ data: "shelingxingqiu@163.com",
+ success: () => uni.showToast({ title: "邮箱已复制", icon: "success" }),
+ });
+};
+
+const openQr = () => {
+ qrSaved.value = false;
+ qrVisible.value = true;
+};
+
+const closeTip = () => {
+ showTip.value = false;
+};
+
+const closeConfirmBindTip = () => {
+ confirmBindTip.value = false;
+};
+
+const closeQr = () => {
+ qrVisible.value = false;
+};
+
+// 保存二维码到相册;远程二维码先下载到临时目录,失败时保留长按保存提示。
+const saveQrCode = async () => {
+ let filePath = qrImageUrl.value;
+ try {
+ if (/^https?:\/\//.test(filePath)) {
+ filePath = await new Promise((resolve, reject) => {
+ uni.downloadFile({
+ url: filePath,
+ success: (result) =>
+ result.statusCode === 200
+ ? resolve(result.tempFilePath)
+ : reject(new Error("二维码下载失败")),
+ fail: reject,
+ });
+ });
+ }
+ await new Promise((resolve, reject) => {
+ uni.saveImageToPhotosAlbum({ success: resolve, fail: reject, filePath });
+ });
+ qrSaved.value = true;
+ uni.showToast({ title: "已保存至相册", icon: "success" });
+ } catch (error) {
+ uni.showToast({ title: "请长按二维码保存", icon: "none" });
+ }
+};
+
+onLoad((options = {}) => {
+ retryScanOnShow.value = options.retryScan === "1";
+});
+
+onMounted(() => {
+ uni.$on("device-bind-retry-scan", handleScan);
+});
+
+onUnmounted(() => {
+ uni.$off("device-bind-retry-scan", handleScan);
+});
+
+onShow(async () => {
+ calibration.value = uni.getStorageSync("calibration");
+ await syncDeviceBinding();
+ if (retryScanOnShow.value) {
+ retryScanOnShow.value = false;
+ handleScan();
+ }
+});
+
+
+
+
+
+
+
+
+
+ 射灵智能弓箭二维码
+
+ 设备ID:{{ maskedDeviceId }}
+
+ 保存至相册
+
+
+ 该二维码为当前绑定弓箭的二维码,你可以截图保存到相册,以便当二维码丢失或不在身边时,可以扫描二维码进行设备绑定。
+
+ 注:解除绑定后将无法查看该二维码。
+
+
+
+
+
+
+
+ 请扫描
+ 射灵智能弓箭
+ 设备上的二维码
+
+
+ 新设备首次绑定账号可获赠
+ 6个月射灵会员礼包
+ ,
+ 该礼包仅可使用一次,请确保当前登录账号为您本人账号。
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ device.deviceName || "我的智能弓" }}
+ {{ maskedDeviceId }}
+
+
+
+
+ {{ item.label }}
+ {{ item.value }}
+
+
+
+
+
+
+ ⌁
+ 设备介绍
+
+
+ ⌖
+ 弓箭调瞄
+
+
+ ↻
+ 固件更新
+
+
+ ◌
+ WIFI设置
+
+
+ ▦
+ 设备二维码
+
+
+ ⊗
+ 解除绑定
+
+
+
+
+ 如有场地或距离变化,请重新校准以保证智能弓射箭精准度
+ 重新校准
+
+
+
+
+
+ 扫码绑定射灵弓箭
+ 设备底部二维码样例
+
+ 【注】已被绑定的弓箭无法再次绑定。
+
+ 如有任何疑问,请随时联系:
+
+
+
+
+
+
+
+ 智能弓箭和系统账号需一一对应,你确定要将当前登录用户账号绑定这把弓箭吗?绑定后不可随意更换。
+
+
+ {{ binding ? "绑定中..." : "确认绑定" }}
+
+ 取消
+
+
+
+
+
+
+
+
+
+
+ 确定
+
+ 仅支持中文、英文、数字、下划线、减号
+
+
+
+
+
+
+
diff --git a/src/pages/ota-wifi.vue b/src/pages/device/ota-wifi.vue
similarity index 96%
rename from src/pages/ota-wifi.vue
rename to src/pages/device/ota-wifi.vue
index 9a8e9b7..245597f 100644
--- a/src/pages/ota-wifi.vue
+++ b/src/pages/device/ota-wifi.vue
@@ -1,4 +1,4 @@
-
-
-
-
-
-
-
- 射灵智能弓箭,三模传感系统与独创靶环算法,
- 毫秒级在线实时对战,让你拥有全球约战的乐趣!
-
-
-
- 扫码绑定设灵弓箭
-
- 【注】已被绑定的弓箭无法再次绑定。
-
- 如有任何疑问,请随时联系:
-
-
-
-
-
-
- 智能弓箭和系统账号需一一对应,你确定要将当前登录用户账号绑定这把弓箭吗?
- 绑定后不可随意更换。
-
- 确认绑定
- (confirmBindTip = false)">取消
-
-
-
-
-
-
-
-
- {{ device.deviceName }}
-
-
-
-
- 如有场地/距离变化,需重新校准以保证智能弓射箭精准度
-
-
-
-
-
-
-
- {{ user.nickName }}
- {{
- user.nickName
- }}
-
-
-
-
-
- 恭喜,你的弓箭和账号已成功绑定!
- 已赠送6个月射灵世界会员
-
-
-
-
- 返回首页
-
-
- 进入新手试炼
-
-
-
-
-
-
-
-
- {{ device.deviceName }}
-
-
-
-
- 首次绑定智能弓或场地/距离变化时,应进行校准以确保射箭精度
-
-
-
-
-
-
-
- {{ user.nickName }}
- {{
- user.nickName
- }}
-
-
-
-
- 解绑
-
-
- 设备连接WIFI
-
-
-
-
-
-
diff --git a/src/pages/team-battle/components/Container.vue b/src/pages/team-battle/components/Container.vue
index f6ffeda..0b6d016 100644
--- a/src/pages/team-battle/components/Container.vue
+++ b/src/pages/team-battle/components/Container.vue
@@ -111,7 +111,7 @@ const cancelMatching = async () => {
const goCalibration = async () => {
await laserAimAPI();
uni.navigateTo({
- url: "/pages/calibration",
+ url: "/pages/device/calibration",
});
};
diff --git a/src/static/device-assets/device-avatar.png b/src/static/device-assets/device-avatar.png
new file mode 100644
index 0000000..3d75f21
Binary files /dev/null and b/src/static/device-assets/device-avatar.png differ
diff --git a/src/static/device-assets/device-bind-failure-hero.png b/src/static/device-assets/device-bind-failure-hero.png
new file mode 100644
index 0000000..ca06f28
Binary files /dev/null and b/src/static/device-assets/device-bind-failure-hero.png differ
diff --git a/src/static/device-assets/device-bind-success-confetti.png b/src/static/device-assets/device-bind-success-confetti.png
new file mode 100644
index 0000000..a43543f
Binary files /dev/null and b/src/static/device-assets/device-bind-success-confetti.png differ
diff --git a/src/static/device-assets/device-bind-success-hero-first.png b/src/static/device-assets/device-bind-success-hero-first.png
new file mode 100644
index 0000000..b4d3d51
Binary files /dev/null and b/src/static/device-assets/device-bind-success-hero-first.png differ
diff --git a/src/static/device-assets/device-bind-success-hero-nonfirst.png b/src/static/device-assets/device-bind-success-hero-nonfirst.png
new file mode 100644
index 0000000..c59cce5
Binary files /dev/null and b/src/static/device-assets/device-bind-success-hero-nonfirst.png differ
diff --git a/src/static/device-assets/device-bind-success-reward-gift.png b/src/static/device-assets/device-bind-success-reward-gift.png
new file mode 100644
index 0000000..c949b62
Binary files /dev/null and b/src/static/device-assets/device-bind-success-reward-gift.png differ
diff --git a/src/static/device-assets/device-bind-success-title.png b/src/static/device-assets/device-bind-success-title.png
new file mode 100644
index 0000000..655b282
Binary files /dev/null and b/src/static/device-assets/device-bind-success-title.png differ
diff --git a/src/static/device-assets/device-help.png b/src/static/device-assets/device-help.png
new file mode 100644
index 0000000..6ce237f
Binary files /dev/null and b/src/static/device-assets/device-help.png differ
diff --git a/src/static/device-assets/device-qrcode.png b/src/static/device-assets/device-qrcode.png
new file mode 100644
index 0000000..16ccccd
Binary files /dev/null and b/src/static/device-assets/device-qrcode.png differ
diff --git a/src/static/device-assets/my-device-avatar.png b/src/static/device-assets/my-device-avatar.png
new file mode 100644
index 0000000..3d75f21
Binary files /dev/null and b/src/static/device-assets/my-device-avatar.png differ
diff --git a/src/static/device-assets/my-device-qrcode.png b/src/static/device-assets/my-device-qrcode.png
new file mode 100644
index 0000000..16ccccd
Binary files /dev/null and b/src/static/device-assets/my-device-qrcode.png differ
diff --git a/src/static/device-assets/my-device-unbound-background.png b/src/static/device-assets/my-device-unbound-background.png
new file mode 100644
index 0000000..370aa1c
Binary files /dev/null and b/src/static/device-assets/my-device-unbound-background.png differ
diff --git a/src/static/device-assets/my-device-unbound-help.png b/src/static/device-assets/my-device-unbound-help.png
new file mode 100644
index 0000000..6ce237f
Binary files /dev/null and b/src/static/device-assets/my-device-unbound-help.png differ
diff --git a/src/static/device-assets/my-device-unbound-product.png b/src/static/device-assets/my-device-unbound-product.png
new file mode 100644
index 0000000..830a936
Binary files /dev/null and b/src/static/device-assets/my-device-unbound-product.png differ
diff --git a/src/static/device-assets/my-device-unbound-qr-sample.png b/src/static/device-assets/my-device-unbound-qr-sample.png
new file mode 100644
index 0000000..d51d824
Binary files /dev/null and b/src/static/device-assets/my-device-unbound-qr-sample.png differ
diff --git a/src/static/device-assets/my-device-unbound-scan-tip.png b/src/static/device-assets/my-device-unbound-scan-tip.png
new file mode 100644
index 0000000..d5d0f65
Binary files /dev/null and b/src/static/device-assets/my-device-unbound-scan-tip.png differ
diff --git a/src/static/device-assets/my-device-unbound-scan.png b/src/static/device-assets/my-device-unbound-scan.png
new file mode 100644
index 0000000..55c0540
Binary files /dev/null and b/src/static/device-assets/my-device-unbound-scan.png differ
diff --git a/src/static/device-assets/ota-bind-success.png b/src/static/device-assets/ota-bind-success.png
new file mode 100644
index 0000000..aa95e5e
Binary files /dev/null and b/src/static/device-assets/ota-bind-success.png differ
diff --git a/src/static/device-assets/ota-bind.png b/src/static/device-assets/ota-bind.png
new file mode 100644
index 0000000..a925a26
Binary files /dev/null and b/src/static/device-assets/ota-bind.png differ
diff --git a/src/static/device-assets/ota-calibration-tip.png b/src/static/device-assets/ota-calibration-tip.png
new file mode 100644
index 0000000..d5d0f65
Binary files /dev/null and b/src/static/device-assets/ota-calibration-tip.png differ
diff --git a/src/static/device-assets/ota-device-icon.png b/src/static/device-assets/ota-device-icon.png
new file mode 100644
index 0000000..3d75f21
Binary files /dev/null and b/src/static/device-assets/ota-device-icon.png differ
diff --git a/src/static/device-assets/ota-enter-arrow-blue.png b/src/static/device-assets/ota-enter-arrow-blue.png
new file mode 100644
index 0000000..18ed17d
Binary files /dev/null and b/src/static/device-assets/ota-enter-arrow-blue.png differ
diff --git a/src/static/device-assets/ota-no-device.png b/src/static/device-assets/ota-no-device.png
new file mode 100644
index 0000000..830a936
Binary files /dev/null and b/src/static/device-assets/ota-no-device.png differ
diff --git a/src/static/device-assets/ota-scan-tip.png b/src/static/device-assets/ota-scan-tip.png
new file mode 100644
index 0000000..d5d0f65
Binary files /dev/null and b/src/static/device-assets/ota-scan-tip.png differ
diff --git a/src/static/device-assets/ota-scan.png b/src/static/device-assets/ota-scan.png
new file mode 100644
index 0000000..55c0540
Binary files /dev/null and b/src/static/device-assets/ota-scan.png differ
diff --git a/src/static/device-assets/ota-user-icon.png b/src/static/device-assets/ota-user-icon.png
new file mode 100644
index 0000000..1d4350c
Binary files /dev/null and b/src/static/device-assets/ota-user-icon.png differ
diff --git a/src/static/home-device/device-action-bg--bind.png b/src/static/home-device/device-action-bg--bind.png
new file mode 100644
index 0000000..80e0eba
Binary files /dev/null and b/src/static/home-device/device-action-bg--bind.png differ
diff --git a/src/static/home-device/device-action-bg--device.png b/src/static/home-device/device-action-bg--device.png
new file mode 100644
index 0000000..5e8da2e
Binary files /dev/null and b/src/static/home-device/device-action-bg--device.png differ
diff --git a/src/static/home-device/device-action-bind-icon.png b/src/static/home-device/device-action-bind-icon.png
new file mode 100644
index 0000000..6777f33
Binary files /dev/null and b/src/static/home-device/device-action-bind-icon.png differ
diff --git a/src/static/home-device/device-bow--offline.png b/src/static/home-device/device-bow--offline.png
new file mode 100644
index 0000000..736c36e
Binary files /dev/null and b/src/static/home-device/device-bow--offline.png differ
diff --git a/src/static/home-device/device-bow--online.png b/src/static/home-device/device-bow--online.png
new file mode 100644
index 0000000..219d280
Binary files /dev/null and b/src/static/home-device/device-bow--online.png differ
diff --git a/src/static/home-device/device-bow--unbound.png b/src/static/home-device/device-bow--unbound.png
new file mode 100644
index 0000000..e914429
Binary files /dev/null and b/src/static/home-device/device-bow--unbound.png differ
diff --git a/src/static/home-device/device-card-bg--bound.png b/src/static/home-device/device-card-bg--bound.png
new file mode 100644
index 0000000..c1c487e
Binary files /dev/null and b/src/static/home-device/device-card-bg--bound.png differ
diff --git a/src/static/home-device/device-card-bg--unbound.png b/src/static/home-device/device-card-bg--unbound.png
new file mode 100644
index 0000000..2f8eb8a
Binary files /dev/null and b/src/static/home-device/device-card-bg--unbound.png differ
diff --git a/src/static/home-device/device-state-battery.png b/src/static/home-device/device-state-battery.png
new file mode 100644
index 0000000..274b829
Binary files /dev/null and b/src/static/home-device/device-state-battery.png differ
diff --git a/src/static/home-device/device-state-dot--offline.png b/src/static/home-device/device-state-dot--offline.png
new file mode 100644
index 0000000..32e32e7
Binary files /dev/null and b/src/static/home-device/device-state-dot--offline.png differ
diff --git a/src/static/home-device/device-state-dot--online.png b/src/static/home-device/device-state-dot--online.png
new file mode 100644
index 0000000..7d69c0f
Binary files /dev/null and b/src/static/home-device/device-state-dot--online.png differ
diff --git a/src/static/home-device/device-state-refresh.png b/src/static/home-device/device-state-refresh.png
new file mode 100644
index 0000000..7957a13
Binary files /dev/null and b/src/static/home-device/device-state-refresh.png differ
diff --git a/src/store.js b/src/store.js
index a348202..6df144b 100644
--- a/src/store.js
+++ b/src/store.js
@@ -100,6 +100,8 @@ export default defineStore("store", {
ringRank: [],
},
online: false,
+ // 设备电量属于运行时状态,null 表示当前没有有效数据。
+ deviceBattery: null,
game: {
roomID: "",
inBattle: false,
@@ -136,6 +138,17 @@ export default defineStore("store", {
updateOnline(online) {
this.online = online;
},
+ updateDeviceBattery(value) {
+ if (value === null || value === undefined || value === "") {
+ this.deviceBattery = null;
+ return;
+ }
+
+ const battery = Number(value);
+ this.deviceBattery = Number.isFinite(battery)
+ ? Math.min(100, Math.max(0, battery))
+ : null;
+ },
async updateUser(user = {}) {
this.user = { ...getDefaultUser(), ...user };
this.user.lvlName = getLvlNameByScore(this.user.scores, this.config.randInfos)
@@ -151,6 +164,7 @@ export default defineStore("store", {
clearDevice() {
this.device = getDefaultDevice();
this.online = false;
+ this.deviceBattery = null;
},
async updateConfig(config) {
this.config = config;
@@ -199,6 +213,7 @@ export default defineStore("store", {
user: getDefaultUser(),
device: getDefaultDevice(),
online: false,
+ deviceBattery: null,
game: getDefaultGame(),
dailyCount: getDefaultDailyCount(),
deviceChargingDialogVisible: false,