web-core-tcm 0.0.24 → 0.0.25
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.
- package/.editorconfig +7 -0
- package/.github/workflows/test.yml +29 -0
- package/.prettierrc.json +5 -0
- package/.vscode/extensions.json +15 -0
- package/.vscode/settings.json +9 -0
- package/eslint.config.js +83 -0
- package/index.html +24 -0
- package/package.json +1 -4
- package/postcss.config.js +29 -0
- package/public/favicon.ico +0 -0
- package/public/icons/favicon-128x128.png +0 -0
- package/public/icons/favicon-16x16.png +0 -0
- package/public/icons/favicon-32x32.png +0 -0
- package/public/icons/favicon-96x96.png +0 -0
- package/quasar.config.ts +233 -0
- package/src/App.vue +7 -0
- package/src/api/algorithm/comprehensiveAlgorithm.ts +20 -0
- package/src/api/algorithm/index.ts +50 -0
- package/src/api/algorithm/inquiriesAlgorithm.ts +16 -0
- package/src/api/algorithm/inspectionsAlgorithm.ts +11 -0
- package/src/api/algorithm/lisemsAlgorithm.ts +16 -0
- package/src/api/algorithm/pulsationsAlgorithm.ts +8 -0
- package/src/api/authorization/alova/apiDefinitions.ts +23 -0
- package/src/api/authorization/alova/createApis.ts +114 -0
- package/src/api/authorization/alova/globals.d.ts +394 -0
- package/src/api/authorization/alova/implement/authorization.ts +14 -0
- package/src/api/authorization/alova/implement/index.ts +1 -0
- package/src/api/authorization/alova/index.ts +22 -0
- package/src/api/authorization/authorization.ts +16 -0
- package/src/api/authorization/index.ts +2 -0
- package/src/api/check/alova/apiDefinitions.ts +30 -0
- package/src/api/check/alova/createApis.ts +114 -0
- package/src/api/check/alova/globals.d.ts +1257 -0
- package/src/api/check/alova/implement/check.ts +165 -0
- package/src/api/check/alova/implement/index.ts +1 -0
- package/src/api/check/alova/index.ts +22 -0
- package/src/api/check/check.ts +217 -0
- package/src/api/check/index.ts +2 -0
- package/src/api/config/alova/index.ts +71 -0
- package/src/api/config/index.ts +132 -0
- package/src/api/device/device.js +58 -0
- package/src/api/doctor/alova/apiDefinitions.ts +28 -0
- package/src/api/doctor/alova/createApis.ts +114 -0
- package/src/api/doctor/alova/globals.d.ts +559 -0
- package/src/api/doctor/alova/implement/doctor.ts +51 -0
- package/src/api/doctor/alova/implement/index.ts +1 -0
- package/src/api/doctor/alova/index.ts +23 -0
- package/src/api/doctor/doctor.ts +53 -0
- package/src/api/doctor/index.ts +2 -0
- package/src/api/index.ts +12 -0
- package/src/api/metric/implement/index.ts +1 -0
- package/src/api/metric/implement/metric.ts +108 -0
- package/src/api/metric/index.ts +2 -0
- package/src/api/metric/metric.ts +114 -0
- package/src/api/oauth/alova/apiDefinitions.ts +26 -0
- package/src/api/oauth/alova/createApis.ts +114 -0
- package/src/api/oauth/alova/globals.d.ts +460 -0
- package/src/api/oauth/alova/implement/index.ts +1 -0
- package/src/api/oauth/alova/implement/oauth.ts +24 -0
- package/src/api/oauth/alova/index.ts +21 -0
- package/src/api/oauth/index.ts +2 -0
- package/src/api/oauth/oauth.ts +19 -0
- package/src/api/outpatient/alova/apiDefinitions.ts +27 -0
- package/src/api/outpatient/alova/createApis.ts +114 -0
- package/src/api/outpatient/alova/globals.d.ts +685 -0
- package/src/api/outpatient/alova/implement/index.ts +1 -0
- package/src/api/outpatient/alova/implement/outpatient.ts +91 -0
- package/src/api/outpatient/alova/index.ts +22 -0
- package/src/api/outpatient/index.ts +2 -0
- package/src/api/outpatient/outpatient.ts +67 -0
- package/src/api/patient/alova/apiDefinitions.ts +41 -0
- package/src/api/patient/alova/createApis.ts +114 -0
- package/src/api/patient/alova/globals.d.ts +1690 -0
- package/src/api/patient/alova/implement/index.ts +2 -0
- package/src/api/patient/alova/implement/meta.ts +517 -0
- package/src/api/patient/alova/implement/patient.ts +99 -0
- package/src/api/patient/alova/index.ts +22 -0
- package/src/api/patient/core.ts +133 -0
- package/src/api/patient/index.ts +4 -0
- package/src/api/patient/meta.ts +570 -0
- package/src/api/patient/patient.ts +98 -0
- package/src/api/prescription/alova/apiDefinitions.ts +29 -0
- package/src/api/prescription/alova/createApis.ts +114 -0
- package/src/api/prescription/alova/globals.d.ts +968 -0
- package/src/api/prescription/alova/implement/herbal.ts +68 -0
- package/src/api/prescription/alova/implement/index.ts +2 -0
- package/src/api/prescription/alova/implement/prescription.ts +62 -0
- package/src/api/prescription/alova/index.ts +22 -0
- package/src/api/prescription/herbal.ts +51 -0
- package/src/api/prescription/index.ts +3 -0
- package/src/api/prescription/prescription.ts +76 -0
- package/src/api/scientist/alova/apiDefinitions.ts +27 -0
- package/src/api/scientist/alova/createApis.ts +114 -0
- package/src/api/scientist/alova/globals.d.ts +447 -0
- package/src/api/scientist/alova/implement/index.ts +1 -0
- package/src/api/scientist/alova/implement/scientist.ts +40 -0
- package/src/api/scientist/alova/index.ts +24 -0
- package/src/api/scientist/index.ts +2 -0
- package/src/api/scientist/scientist.ts +49 -0
- package/src/assets/quasar-logo-vertical.svg +15 -0
- package/src/boot/.gitkeep +0 -0
- package/src/components/ExampleComponent.vue +37 -0
- package/src/components/models.ts +8 -0
- package/src/css/app.scss +1 -0
- package/src/css/quasar.variables.scss +25 -0
- package/src/env.d.ts +7 -0
- package/src/index.ts +3 -0
- package/src/layouts/UserLayout.vue +108 -0
- package/src/pages/LoginPage.vue +29 -0
- package/src/proto/Images.proto +7 -0
- package/src/proto/WaveMap.proto +10 -0
- package/src/proto/index.ts +2 -0
- package/src/proto/types/Images_pb.ts +48 -0
- package/src/proto/types/WaveMap_pb.ts +59 -0
- package/src/router/index.ts +37 -0
- package/src/router/routes.ts +14 -0
- package/src/util/RichTextUtil.ts +5 -0
- package/src/util/datetime.ts +43 -0
- package/src/util/export.ts +46 -0
- package/src/util/helper.ts +159 -0
- package/src/util/image.ts +28 -0
- package/src/util/number.ts +146 -0
- package/src/util/s256.js +27 -0
- package/src/util/secret.ts +60 -0
- package/src/util/string.ts +121 -0
- package/tsconfig.json +7 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<q-layout view="hHh lpR fFf">
|
|
3
|
+
<!-- 顶部导航栏 -->
|
|
4
|
+
<q-header elevated class="bg-primary text-white">
|
|
5
|
+
<q-toolbar>
|
|
6
|
+
<q-toolbar-title>用户中心</q-toolbar-title>
|
|
7
|
+
|
|
8
|
+
<!-- 顶部导航菜单 -->
|
|
9
|
+
<q-tabs
|
|
10
|
+
v-model="currentTab"
|
|
11
|
+
inline-label
|
|
12
|
+
class="bg-primary text-white"
|
|
13
|
+
active-color="white"
|
|
14
|
+
indicator-color="white"
|
|
15
|
+
>
|
|
16
|
+
<q-tab
|
|
17
|
+
v-for="tab in userTabs"
|
|
18
|
+
:key="tab.path"
|
|
19
|
+
:name="tab.path"
|
|
20
|
+
:icon="tab.icon"
|
|
21
|
+
:label="tab.label"
|
|
22
|
+
@click="navigateTo(tab.path)"
|
|
23
|
+
/>
|
|
24
|
+
</q-tabs>
|
|
25
|
+
|
|
26
|
+
<q-space />
|
|
27
|
+
|
|
28
|
+
<!-- 用户菜单 -->
|
|
29
|
+
<q-btn-dropdown flat :label="username">
|
|
30
|
+
<q-list>
|
|
31
|
+
<q-item clickable v-close-popup @click="navigateTo('/user/profile')">
|
|
32
|
+
<q-item-section avatar>
|
|
33
|
+
<q-icon name="person" />
|
|
34
|
+
</q-item-section>
|
|
35
|
+
<q-item-section>个人资料</q-item-section>
|
|
36
|
+
</q-item>
|
|
37
|
+
|
|
38
|
+
<q-separator />
|
|
39
|
+
|
|
40
|
+
<q-item clickable v-close-popup @click="logout">
|
|
41
|
+
<q-item-section avatar>
|
|
42
|
+
<q-icon name="logout" color="negative" />
|
|
43
|
+
</q-item-section>
|
|
44
|
+
<q-item-section class="text-negative">退出登录</q-item-section>
|
|
45
|
+
</q-item>
|
|
46
|
+
</q-list>
|
|
47
|
+
</q-btn-dropdown>
|
|
48
|
+
</q-toolbar>
|
|
49
|
+
</q-header>
|
|
50
|
+
|
|
51
|
+
<!-- 页面内容区域 -->
|
|
52
|
+
<q-page-container>
|
|
53
|
+
<router-view />
|
|
54
|
+
</q-page-container>
|
|
55
|
+
</q-layout>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<script setup lang="ts">
|
|
59
|
+
import { computed, ref } from 'vue';
|
|
60
|
+
import { useRouter, useRoute } from 'vue-router';
|
|
61
|
+
|
|
62
|
+
const router = useRouter();
|
|
63
|
+
const route = useRoute();
|
|
64
|
+
|
|
65
|
+
const currentTab = computed(() => route.path);
|
|
66
|
+
setInterval(() => {
|
|
67
|
+
username.value = localStorage.getItem('user')
|
|
68
|
+
? JSON.parse(localStorage.getItem('user') || '{}').username
|
|
69
|
+
: '用户';
|
|
70
|
+
}, 100);
|
|
71
|
+
const username = ref(
|
|
72
|
+
localStorage.getItem('user') ? JSON.parse(localStorage.getItem('user') || '{}').username : '用户',
|
|
73
|
+
);
|
|
74
|
+
const userTabs = [
|
|
75
|
+
{
|
|
76
|
+
label: '首页',
|
|
77
|
+
icon: 'home',
|
|
78
|
+
path: '/user/home',
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
async function navigateTo(path: string) {
|
|
83
|
+
await router.push(path);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function logout() {
|
|
87
|
+
await router.push('/login');
|
|
88
|
+
}
|
|
89
|
+
</script>
|
|
90
|
+
|
|
91
|
+
<style scoped>
|
|
92
|
+
.q-toolbar {
|
|
93
|
+
min-height: 60px;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.q-tabs {
|
|
97
|
+
background: transparent !important;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.q-tab {
|
|
101
|
+
margin: 0 4px;
|
|
102
|
+
border-radius: 8px 8px 0 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.q-tab--active {
|
|
106
|
+
background: rgba(255, 255, 255, 0.2);
|
|
107
|
+
}
|
|
108
|
+
</style>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<script setup lang="ts"></script>
|
|
2
|
+
|
|
3
|
+
<template>
|
|
4
|
+
<div class="auth-container"></div>
|
|
5
|
+
</template>
|
|
6
|
+
|
|
7
|
+
<style scoped>
|
|
8
|
+
.auth-container {
|
|
9
|
+
min-height: 100vh;
|
|
10
|
+
display: flex;
|
|
11
|
+
align-items: center;
|
|
12
|
+
justify-content: center;
|
|
13
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
14
|
+
padding: 20px;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.auth-card {
|
|
18
|
+
width: 100%;
|
|
19
|
+
max-width: 400px;
|
|
20
|
+
background: rgba(255, 255, 255, 0.95);
|
|
21
|
+
backdrop-filter: blur(10px);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@media (max-width: 480px) {
|
|
25
|
+
.auth-card {
|
|
26
|
+
max-width: 100%;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
syntax = "proto3";
|
|
2
|
+
|
|
3
|
+
message Wave {
|
|
4
|
+
repeated double values = 1; // 单个数组(对应 number[])
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
message WaveMap {
|
|
8
|
+
map<string, Wave> origin = 1; // 对应 origin: {[key: string]: number[]}
|
|
9
|
+
map<string, Wave> smooth = 2; // 对应 smooth: {[key: string]: number[]}
|
|
10
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// @generated by protoc-gen-es v2.9.0 with parameter "target=ts"
|
|
2
|
+
// @generated from file Images.proto (syntax proto3)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
import type { GenFile, GenMessage } from '@bufbuild/protobuf/codegenv2';
|
|
6
|
+
import { fileDesc, messageDesc } from '@bufbuild/protobuf/codegenv2';
|
|
7
|
+
import type { Message } from '@bufbuild/protobuf';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Describes the file Images.proto.
|
|
11
|
+
*/
|
|
12
|
+
export const file_Images: GenFile =
|
|
13
|
+
/*@__PURE__*/
|
|
14
|
+
fileDesc(
|
|
15
|
+
'CgxJbWFnZXMucHJvdG8iFgoFSW1hZ2USDQoFYnl0ZXMYASABKAwiIAoGSW1hZ2VzEhYKBmltYWdlcxgBIAMoCzIGLkltYWdlYgZwcm90bzM',
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @generated from message Image
|
|
20
|
+
*/
|
|
21
|
+
export type Image = Message<'Image'> & {
|
|
22
|
+
/**
|
|
23
|
+
* @generated from field: bytes bytes = 1;
|
|
24
|
+
*/
|
|
25
|
+
bytes: Uint8Array;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Describes the message Image.
|
|
30
|
+
* Use `create(ImageSchema)` to create a new message.
|
|
31
|
+
*/
|
|
32
|
+
export const ImageSchema: GenMessage<Image> = /*@__PURE__*/ messageDesc(file_Images, 0);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @generated from message Images
|
|
36
|
+
*/
|
|
37
|
+
export type Images = Message<'Images'> & {
|
|
38
|
+
/**
|
|
39
|
+
* @generated from field: repeated Image images = 1;
|
|
40
|
+
*/
|
|
41
|
+
images: Image[];
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Describes the message Images.
|
|
46
|
+
* Use `create(ImagesSchema)` to create a new message.
|
|
47
|
+
*/
|
|
48
|
+
export const ImagesSchema: GenMessage<Images> = /*@__PURE__*/ messageDesc(file_Images, 1);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// @generated by protoc-gen-es v2.9.0 with parameter "target=ts"
|
|
2
|
+
// @generated from file WaveMap.proto (syntax proto3)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
import type { GenFile, GenMessage } from '@bufbuild/protobuf/codegenv2';
|
|
6
|
+
import { fileDesc, messageDesc } from '@bufbuild/protobuf/codegenv2';
|
|
7
|
+
import type { Message } from '@bufbuild/protobuf';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Describes the file WaveMap.proto.
|
|
11
|
+
*/
|
|
12
|
+
export const file_WaveMap: GenFile =
|
|
13
|
+
/*@__PURE__*/
|
|
14
|
+
fileDesc(
|
|
15
|
+
'Cg1XYXZlTWFwLnByb3RvIhYKBFdhdmUSDgoGdmFsdWVzGAEgAygBIsEBCgdXYXZlTWFwEiQKBm9yaWdpbhgBIAMoCzIULldhdmVNYXAuT3JpZ2luRW50cnkSJAoGc21vb3RoGAIgAygLMhQuV2F2ZU1hcC5TbW9vdGhFbnRyeRo0CgtPcmlnaW5FbnRyeRILCgNrZXkYASABKAkSFAoFdmFsdWUYAiABKAsyBS5XYXZlOgI4ARo0CgtTbW9vdGhFbnRyeRILCgNrZXkYASABKAkSFAoFdmFsdWUYAiABKAsyBS5XYXZlOgI4AWIGcHJvdG8z',
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @generated from message Wave
|
|
20
|
+
*/
|
|
21
|
+
export type Wave = Message<'Wave'> & {
|
|
22
|
+
/**
|
|
23
|
+
* 单个数组(对应 number[])
|
|
24
|
+
*
|
|
25
|
+
* @generated from field: repeated double values = 1;
|
|
26
|
+
*/
|
|
27
|
+
values: number[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Describes the message Wave.
|
|
32
|
+
* Use `create(WaveSchema)` to create a new message.
|
|
33
|
+
*/
|
|
34
|
+
export const WaveSchema: GenMessage<Wave> = /*@__PURE__*/ messageDesc(file_WaveMap, 0);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @generated from message WaveMap
|
|
38
|
+
*/
|
|
39
|
+
export type WaveMap = Message<'WaveMap'> & {
|
|
40
|
+
/**
|
|
41
|
+
* 对应 origin: {[key: string]: number[]}
|
|
42
|
+
*
|
|
43
|
+
* @generated from field: map<string, Wave> origin = 1;
|
|
44
|
+
*/
|
|
45
|
+
origin: { [key: string]: Wave };
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 对应 smooth: {[key: string]: number[]}
|
|
49
|
+
*
|
|
50
|
+
* @generated from field: map<string, Wave> smooth = 2;
|
|
51
|
+
*/
|
|
52
|
+
smooth: { [key: string]: Wave };
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Describes the message WaveMap.
|
|
57
|
+
* Use `create(WaveMapSchema)` to create a new message.
|
|
58
|
+
*/
|
|
59
|
+
export const WaveMapSchema: GenMessage<WaveMap> = /*@__PURE__*/ messageDesc(file_WaveMap, 1);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { defineRouter } from '#q-app/wrappers';
|
|
2
|
+
import {
|
|
3
|
+
createMemoryHistory,
|
|
4
|
+
createRouter,
|
|
5
|
+
createWebHashHistory,
|
|
6
|
+
createWebHistory,
|
|
7
|
+
} from 'vue-router';
|
|
8
|
+
import routes from './routes';
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* If not building with SSR mode, you can
|
|
12
|
+
* directly export the Router instantiation;
|
|
13
|
+
*
|
|
14
|
+
* The function below can be async too; either use
|
|
15
|
+
* async/await or return a Promise which resolves
|
|
16
|
+
* with the Router instance.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export default defineRouter(function (/* { store, ssrContext } */) {
|
|
20
|
+
const createHistory = process.env.SERVER
|
|
21
|
+
? createMemoryHistory
|
|
22
|
+
: process.env.VUE_ROUTER_MODE === 'history'
|
|
23
|
+
? createWebHistory
|
|
24
|
+
: createWebHashHistory;
|
|
25
|
+
|
|
26
|
+
const Router = createRouter({
|
|
27
|
+
scrollBehavior: () => ({ left: 0, top: 0 }),
|
|
28
|
+
routes,
|
|
29
|
+
|
|
30
|
+
// Leave this as is and make changes in quasar.conf.js instead!
|
|
31
|
+
// quasar.conf.js -> build -> vueRouterMode
|
|
32
|
+
// quasar.conf.js -> build -> publicPath
|
|
33
|
+
history: createHistory(process.env.VUE_ROUTER_BASE),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return Router;
|
|
37
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export function getStartOfDay(daysAgo: number = 0): number {
|
|
2
|
+
const startOfDay = new Date();
|
|
3
|
+
startOfDay.setHours(0, 0, 0, 0);
|
|
4
|
+
return startOfDay.getTime() - daysAgo * 24 * 60 * 60 * 1000;
|
|
5
|
+
}
|
|
6
|
+
export function getTimestamp(value: string) {
|
|
7
|
+
if (value === '') return '-1';
|
|
8
|
+
const date = new Date(value);
|
|
9
|
+
return date.getTime().toString();
|
|
10
|
+
}
|
|
11
|
+
export function getDateTimeStr(timestamp: string) {
|
|
12
|
+
const date = new Date(Number.parseInt(timestamp));
|
|
13
|
+
// 获取年、月、日、时、分、秒
|
|
14
|
+
const year = date.getFullYear();
|
|
15
|
+
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,所以需要加1
|
|
16
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
17
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
18
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
19
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
20
|
+
|
|
21
|
+
// 格式化输出
|
|
22
|
+
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
|
|
23
|
+
}
|
|
24
|
+
export function getDateStr(timestamp: string) {
|
|
25
|
+
const date = new Date(Number.parseInt(timestamp));
|
|
26
|
+
// 获取年、月、日、时、分、秒
|
|
27
|
+
const year = date.getFullYear();
|
|
28
|
+
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份从0开始,所以需要加1
|
|
29
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
30
|
+
|
|
31
|
+
// 格式化输出
|
|
32
|
+
return `${year}-${month}-${day}`;
|
|
33
|
+
}
|
|
34
|
+
export function getTimeStr(timestamp: string) {
|
|
35
|
+
const date = new Date(timestamp);
|
|
36
|
+
// 获取年、月、日、时、分、秒
|
|
37
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
38
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
39
|
+
const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
40
|
+
|
|
41
|
+
// 格式化输出
|
|
42
|
+
return `${hours}:${minutes}:${seconds}`;
|
|
43
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
function pulsation2csv(data: { [key: string]: number[] }): void {
|
|
2
|
+
const keys = Object.keys(data);
|
|
3
|
+
|
|
4
|
+
const maxLength = Math.max(...keys.map((key) => data[key].length));
|
|
5
|
+
|
|
6
|
+
// 填充所有数组到最大长度,可以填充空字符串或其他默认值
|
|
7
|
+
keys.forEach((key) => {
|
|
8
|
+
while (data[key].length < maxLength) {
|
|
9
|
+
data[key].push(0); // 或者填入其他默认值
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
let csvContent = '';
|
|
14
|
+
|
|
15
|
+
// 添加自定义表头
|
|
16
|
+
csvContent += keys.join(',') + '\n';
|
|
17
|
+
|
|
18
|
+
// 遍历数据数组,将每一行转换为CSV格式
|
|
19
|
+
for (let i = 0; i < maxLength; i++) {
|
|
20
|
+
let row = '';
|
|
21
|
+
keys.forEach((key) => {
|
|
22
|
+
row += `"${data[key][i]}"`;
|
|
23
|
+
row += ',';
|
|
24
|
+
});
|
|
25
|
+
csvContent += row.slice(0, -1) + '\n'; // 去掉最后一个逗号
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 创建一个 Blob 对象
|
|
29
|
+
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
|
30
|
+
|
|
31
|
+
// 创建一个可下载的链接
|
|
32
|
+
const url = window.URL.createObjectURL(blob);
|
|
33
|
+
const link = document.createElement('a');
|
|
34
|
+
link.href = url;
|
|
35
|
+
link.setAttribute('download', 'data.csv'); // 文件名
|
|
36
|
+
document.body.appendChild(link);
|
|
37
|
+
|
|
38
|
+
// 模拟点击事件以下载文件
|
|
39
|
+
link.click();
|
|
40
|
+
|
|
41
|
+
// 清理
|
|
42
|
+
document.body.removeChild(link);
|
|
43
|
+
window.URL.revokeObjectURL(url);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export { pulsation2csv };
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/** 平台类型 */
|
|
2
|
+
type Platform = 'electron' | 'web';
|
|
3
|
+
|
|
4
|
+
/** 存储操作结果接口 */
|
|
5
|
+
interface StorageResult {
|
|
6
|
+
success: boolean;
|
|
7
|
+
error?: Error;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Token 操作助手对象 */
|
|
11
|
+
export const tokenHelper = {
|
|
12
|
+
/** 设置 token */
|
|
13
|
+
set: (val: string): StorageResult => {
|
|
14
|
+
try {
|
|
15
|
+
if (getPlatform() === 'electron') {
|
|
16
|
+
window.electronAPI.setStoreItem('token', val);
|
|
17
|
+
} else {
|
|
18
|
+
window.localStorage.setItem('token', val);
|
|
19
|
+
}
|
|
20
|
+
return { success: true };
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error('设置 token 失败:', error);
|
|
23
|
+
return { success: false, error: error as Error };
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
/** 获取 token */
|
|
28
|
+
get: (): string | null => {
|
|
29
|
+
try {
|
|
30
|
+
if (getPlatform() === 'electron') {
|
|
31
|
+
return window.electronAPI.getStoreItem('token');
|
|
32
|
+
} else {
|
|
33
|
+
return window.localStorage.getItem('token');
|
|
34
|
+
}
|
|
35
|
+
} catch (error) {
|
|
36
|
+
console.error('获取 token 失败:', error);
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
/** 移除 token */
|
|
42
|
+
remove: (): StorageResult => {
|
|
43
|
+
try {
|
|
44
|
+
if (getPlatform() === 'electron') {
|
|
45
|
+
window.electronAPI.setStoreItem('token', '');
|
|
46
|
+
} else {
|
|
47
|
+
window.localStorage.removeItem('token');
|
|
48
|
+
}
|
|
49
|
+
return { success: true };
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error('移除 token 失败:', error);
|
|
52
|
+
return { success: false, error: error as Error };
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/** 检查是否存在 token */
|
|
57
|
+
exists: (): boolean => {
|
|
58
|
+
const token = tokenHelper.get();
|
|
59
|
+
return !!token && token !== '';
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
/** 通用存储操作助手对象 */
|
|
64
|
+
export const storageHelper = {
|
|
65
|
+
/** 设置存储项 */
|
|
66
|
+
setItem: (key: string, val: string): StorageResult => {
|
|
67
|
+
try {
|
|
68
|
+
if (getPlatform() === 'electron') {
|
|
69
|
+
window.electronAPI.setStoreItem(key, val);
|
|
70
|
+
} else {
|
|
71
|
+
window.localStorage.setItem(key, val);
|
|
72
|
+
}
|
|
73
|
+
return { success: true };
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error(`设置存储项 ${key} 失败:`, error);
|
|
76
|
+
return { success: false, error: error as Error };
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
/** 获取存储项 */
|
|
81
|
+
getItem: (key: string): string | null => {
|
|
82
|
+
try {
|
|
83
|
+
if (getPlatform() === 'electron') {
|
|
84
|
+
return window.electronAPI.getStoreItem(key);
|
|
85
|
+
} else {
|
|
86
|
+
return window.localStorage.getItem(key);
|
|
87
|
+
}
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error(`获取存储项 ${key} 失败:`, error);
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
/** 移除存储项 */
|
|
95
|
+
removeItem: (key: string): StorageResult => {
|
|
96
|
+
try {
|
|
97
|
+
if (getPlatform() === 'electron') {
|
|
98
|
+
window.electronAPI.removeStoreItem(key);
|
|
99
|
+
} else {
|
|
100
|
+
window.localStorage.removeItem(key);
|
|
101
|
+
}
|
|
102
|
+
return { success: true };
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.error(`移除存储项 ${key} 失败:`, error);
|
|
105
|
+
return { success: false, error: error as Error };
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/** 清空所有存储 */
|
|
110
|
+
clear: (): StorageResult => {
|
|
111
|
+
try {
|
|
112
|
+
if (getPlatform() === 'electron') {
|
|
113
|
+
// 如果是 electron,可能需要实现清空逻辑
|
|
114
|
+
window.localStorage.clear();
|
|
115
|
+
} else {
|
|
116
|
+
window.localStorage.clear();
|
|
117
|
+
}
|
|
118
|
+
return { success: true };
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('清空存储失败:', error);
|
|
121
|
+
return { success: false, error: error as Error };
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/** 获取当前平台类型 */
|
|
127
|
+
export const getPlatform = (): Platform => {
|
|
128
|
+
// 检查是否在 Electron 环境中
|
|
129
|
+
if (typeof window !== 'undefined' && window.electronAPI?.available) {
|
|
130
|
+
try {
|
|
131
|
+
if (window.electronAPI.available()) {
|
|
132
|
+
return 'electron';
|
|
133
|
+
}
|
|
134
|
+
} catch {
|
|
135
|
+
// 忽略错误,继续检查其他环境
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 默认返回 web 环境
|
|
140
|
+
return 'web';
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
// 扩展 Window 接口,添加 electronAPI 的类型定义
|
|
144
|
+
declare global {
|
|
145
|
+
interface Window {
|
|
146
|
+
electronAPI?: {
|
|
147
|
+
available: () => boolean;
|
|
148
|
+
setStoreItem: (key: string, value: string) => void;
|
|
149
|
+
getStoreItem: (key: string) => string | null;
|
|
150
|
+
removeStoreItem: (key: string) => void;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export default {
|
|
156
|
+
tokenHelper,
|
|
157
|
+
storageHelper,
|
|
158
|
+
getPlatform,
|
|
159
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function arrayBufferToImageBase64(bytes: Uint8Array) {
|
|
2
|
+
// do anything with the byte array here
|
|
3
|
+
let binary = '';
|
|
4
|
+
const len = bytes.byteLength;
|
|
5
|
+
for (let i = 0; i < len; i++) {
|
|
6
|
+
binary += String.fromCharCode(bytes[i]);
|
|
7
|
+
}
|
|
8
|
+
return 'data:image/png;base64,' + window.btoa(binary);
|
|
9
|
+
}
|
|
10
|
+
export function base64ToArrayBuffer(base64: string): ArrayBuffer {
|
|
11
|
+
// 移除可能存在的 data URL 前缀
|
|
12
|
+
const base64WithoutPrefix = base64.replace(/^data:\w+\/\w+;base64,/, '');
|
|
13
|
+
|
|
14
|
+
// 解码 base64 字符串
|
|
15
|
+
const binaryString = window.atob(base64WithoutPrefix);
|
|
16
|
+
const len = binaryString.length;
|
|
17
|
+
|
|
18
|
+
// 创建 ArrayBuffer 和 Uint8Array
|
|
19
|
+
const buffer = new ArrayBuffer(len);
|
|
20
|
+
const bytes = new Uint8Array(buffer);
|
|
21
|
+
|
|
22
|
+
// 将字符转换为字节
|
|
23
|
+
for (let i = 0; i < len; i++) {
|
|
24
|
+
bytes[i] = binaryString.charCodeAt(i);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return buffer;
|
|
28
|
+
}
|