bohui-vue 1.0.1

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.
Files changed (104) hide show
  1. package/README.md +121 -0
  2. package/bin/create-vue-template.js +565 -0
  3. package/package.json +28 -0
  4. package/templates/vue-project/.browserslistrc +3 -0
  5. package/templates/vue-project/.editorconfig +28 -0
  6. package/templates/vue-project/.env.development +2 -0
  7. package/templates/vue-project/.env.production +2 -0
  8. package/templates/vue-project/.eslintrc.cjs +76 -0
  9. package/templates/vue-project/.keep +0 -0
  10. package/templates/vue-project/.node-version +1 -0
  11. package/templates/vue-project/.prettierignore +13 -0
  12. package/templates/vue-project/.prettierrc +20 -0
  13. package/templates/vue-project/.prettierrc.txt +130 -0
  14. package/templates/vue-project/.stylelintrc.json +94 -0
  15. package/templates/vue-project/README.md +24 -0
  16. package/templates/vue-project/babel.config.js +5 -0
  17. package/templates/vue-project/index.html +34 -0
  18. package/templates/vue-project/package.json +75 -0
  19. package/templates/vue-project/public/favicon.ico +0 -0
  20. package/templates/vue-project/public/static/img/ai-default.jpg +0 -0
  21. package/templates/vue-project/public/static/img/image.png +0 -0
  22. package/templates/vue-project/public/static/img/ppt1.png +0 -0
  23. package/templates/vue-project/public/static/img/ppt2.png +0 -0
  24. package/templates/vue-project/public/static/img/ppt3.png +0 -0
  25. package/templates/vue-project/public/static/js/config.js +11 -0
  26. package/templates/vue-project/public/static/js/dataConfig.js +1143 -0
  27. package/templates/vue-project/src/App.vue +10 -0
  28. package/templates/vue-project/src/api/error-handler.ts +60 -0
  29. package/templates/vue-project/src/api/http.ts +254 -0
  30. package/templates/vue-project/src/api/services/aicebd.ts +47 -0
  31. package/templates/vue-project/src/api/services/base.ts +18 -0
  32. package/templates/vue-project/src/api/services/umse.ts +17 -0
  33. package/templates/vue-project/src/assets/font/Alibaba-PuHuiTi-Medium.otf +0 -0
  34. package/templates/vue-project/src/assets/font/Alibaba-PuHuiTi-Regular.otf +0 -0
  35. package/templates/vue-project/src/assets/font/DOUYINSANSBOLD.OTF +0 -0
  36. package/templates/vue-project/src/assets/font/Pangmen-Title.TTF +0 -0
  37. package/templates/vue-project/src/assets/font/font.css +25 -0
  38. package/templates/vue-project/src/assets/iconfont/iconfont.css +402 -0
  39. package/templates/vue-project/src/assets/iconfont/iconfont.js +66 -0
  40. package/templates/vue-project/src/assets/iconfont/iconfont.json +688 -0
  41. package/templates/vue-project/src/assets/iconfont/iconfont.ttf +0 -0
  42. package/templates/vue-project/src/assets/iconfont/iconfont.woff +0 -0
  43. package/templates/vue-project/src/assets/iconfont/iconfont.woff2 +0 -0
  44. package/templates/vue-project/src/assets/images/Click-tap.png +0 -0
  45. package/templates/vue-project/src/assets/images/Effects.png +0 -0
  46. package/templates/vue-project/src/assets/images/bg.png +0 -0
  47. package/templates/vue-project/src/assets/images/erCode.png +0 -0
  48. package/templates/vue-project/src/assets/images/header-bg.png +0 -0
  49. package/templates/vue-project/src/assets/images/logo.png +0 -0
  50. package/templates/vue-project/src/assets/scss/common.scss +530 -0
  51. package/templates/vue-project/src/assets/styles/element-overrides.css +53 -0
  52. package/templates/vue-project/src/assets/styles/reset.css +186 -0
  53. package/templates/vue-project/src/assets/styles/theme.css +100 -0
  54. package/templates/vue-project/src/components/BarChart.vue +238 -0
  55. package/templates/vue-project/src/components/echarts/EChart.vue +140 -0
  56. package/templates/vue-project/src/composables/useTheme.ts +84 -0
  57. package/templates/vue-project/src/main.ts +111 -0
  58. package/templates/vue-project/src/mocks/base.ts +37 -0
  59. package/templates/vue-project/src/mocks/umse.ts +31 -0
  60. package/templates/vue-project/src/router/index.ts +32 -0
  61. package/templates/vue-project/src/shims-vue.d.ts +19 -0
  62. package/templates/vue-project/src/store/index.ts +18 -0
  63. package/templates/vue-project/src/store/modules/user.ts +85 -0
  64. package/templates/vue-project/src/types/DTO/aicebd.d.ts +60 -0
  65. package/templates/vue-project/src/types/DTO/base.d.ts +26 -0
  66. package/templates/vue-project/src/types/DTO/global.d.ts +48 -0
  67. package/templates/vue-project/src/types/VO/teachingLog.d.ts +15 -0
  68. package/templates/vue-project/src/types/auto-imports.d.ts +73 -0
  69. package/templates/vue-project/src/types/components.d.ts +17 -0
  70. package/templates/vue-project/src/types/element-plus.d.ts +15 -0
  71. package/templates/vue-project/src/types/js-cookie.d.ts +1 -0
  72. package/templates/vue-project/src/types/unocss.d.ts +2 -0
  73. package/templates/vue-project/src/types/vite-plugins.d.ts +3 -0
  74. package/templates/vue-project/src/types/vue-router.d.ts +1 -0
  75. package/templates/vue-project/src/types/window-config.d.ts +12 -0
  76. package/templates/vue-project/src/utils/com-methods.ts +307 -0
  77. package/templates/vue-project/src/utils/echarts.ts +111 -0
  78. package/templates/vue-project/src/utils/number.ts +99 -0
  79. package/templates/vue-project/src/utils/rem.ts +82 -0
  80. package/templates/vue-project/src/utils/responsive.ts +103 -0
  81. package/templates/vue-project/src/utils/time.ts +314 -0
  82. package/templates/vue-project/src/utils/tracker.ts +527 -0
  83. package/templates/vue-project/src/utils/validators.ts +85 -0
  84. package/templates/vue-project/src/utils/window.ts +132 -0
  85. package/templates/vue-project/src/views/home/Home.vue +60 -0
  86. package/templates/vue-project/src/views/home/composables/useUserAuth.ts +13 -0
  87. package/templates/vue-project/src/views/teachingLog/TeachingLog.vue +40 -0
  88. package/templates/vue-project/src/views/teachingLog/__tests__/TeachingEffect.test.ts +96 -0
  89. package/templates/vue-project/src/views/teachingLog/__tests__/TeachingHighlight.test.ts +66 -0
  90. package/templates/vue-project/src/views/teachingLog/__tests__/TeachingLog.test.ts +34 -0
  91. package/templates/vue-project/src/views/teachingLog/components/TeachingEffect.vue +458 -0
  92. package/templates/vue-project/src/views/teachingLog/components/TeachingHighlight.vue +181 -0
  93. package/templates/vue-project/src/views/teachingLog/composables/useEffectTooltip.ts +88 -0
  94. package/templates/vue-project/src/views/teachingLog/composables/useEffectTrendChart.ts +160 -0
  95. package/templates/vue-project/tests/setup.ts +27 -0
  96. package/templates/vue-project/tsconfig.json +24 -0
  97. package/templates/vue-project/tsconfig.node.json +41 -0
  98. package/templates/vue-project/uno.config.ts +84 -0
  99. package/templates/vue-project/vite.config.ts +216 -0
  100. package/templates/vue-project/vue3_ai_prompt.md +652 -0
  101. package/templates/vue-project/vue3_ai_prompt_basic.md +722 -0
  102. package/templates/vue-project/vue3_ai_prompt_full.md +1021 -0
  103. package/templates/vue-project/vue3_ai_prompt_unocss.md +768 -0
  104. package/templates/vue-project//345/267/245/347/250/213/345/214/226/346/250/241/346/235/277/344/273/213/347/273/215.md +463 -0
@@ -0,0 +1,2 @@
1
+ declare module "uno.css";
2
+ declare module "@unocss/reset/tailwind.css";
@@ -0,0 +1,3 @@
1
+ declare module "unplugin-auto-import/vite";
2
+ declare module "unplugin-vue-components/vite";
3
+ declare module "unplugin-vue-components/resolvers";
@@ -0,0 +1 @@
1
+ declare module "vue-router";
@@ -0,0 +1,12 @@
1
+ declare interface ConfigInfo {
2
+ baseUrl: string;
3
+ }
4
+
5
+ declare global {
6
+ interface Window {
7
+ ConfigInfo: ConfigInfo;
8
+ DataConfig: any;
9
+ }
10
+ }
11
+
12
+ export {};
@@ -0,0 +1,307 @@
1
+ import { onBeforeUnmount, onMounted, ref, type Ref } from "vue";
2
+
3
+ export type ResizeSize = { width: number; height: number };
4
+
5
+ /**
6
+ * 监听 window resize,并更新一个响应式 size。
7
+ * - 若传入 targetRef,则优先使用容器 clientWidth/clientHeight;否则使用 window.innerWidth/innerHeight
8
+ * - 通过 setTimeout 延迟更新,避免频繁 resize 触发时抖动
9
+ */
10
+ export type UseResizeTriggerOptions = {
11
+ targetRef?: Ref<HTMLElement | null>;
12
+ delay?: number;
13
+ immediate?: boolean;
14
+ };
15
+ export function useResizeTrigger(options: UseResizeTriggerOptions = {}) {
16
+ const { targetRef, delay = 300, immediate = false } = options;
17
+ const windowSize = ref<ResizeSize>({ width: 0, height: 0 });
18
+
19
+ const resizeHandler = () => {
20
+ const update = () => {
21
+ const el = targetRef?.value ?? null;
22
+ windowSize.value = {
23
+ width: el?.clientWidth ?? window.innerWidth,
24
+ height: el?.clientHeight ?? window.innerHeight,
25
+ };
26
+ };
27
+ if (delay > 0) {
28
+ setTimeout(update, delay);
29
+ return;
30
+ }
31
+ update();
32
+ };
33
+
34
+ onMounted(() => {
35
+ if (immediate) resizeHandler();
36
+ window.addEventListener("resize", resizeHandler);
37
+ });
38
+
39
+ onBeforeUnmount(() => {
40
+ window.removeEventListener("resize", resizeHandler);
41
+ });
42
+
43
+ return { windowSize, resizeHandler };
44
+ }
45
+
46
+ /**
47
+ * 规范化文本:非字符串返回空串;字符串会 trim 去除首尾空白。
48
+ */
49
+ export function normalizeText(v: unknown) {
50
+ return typeof v === "string" ? v.trim() : "";
51
+ }
52
+
53
+ /**
54
+ * 解析颜色字符串:为空/非字符串时返回 fallback;否则返回 trim 后的颜色值。
55
+ */
56
+ export function resolveColor(input: unknown, fallback: string) {
57
+ if (typeof input !== "string") return fallback;
58
+ const trimmed = input.trim();
59
+ return trimmed ? trimmed : fallback;
60
+ }
61
+
62
+ /**
63
+ * 将未知类型转换为数字:不可转换(NaN/Infinity)时返回 fallback。
64
+ */
65
+ export function toNumber(v: unknown, fallback = 0) {
66
+ const n = typeof v === "number" ? v : Number(v);
67
+ return Number.isFinite(n) ? n : fallback;
68
+ }
69
+
70
+ /**
71
+ * 将数值限制在指定范围内。
72
+ */
73
+ export function clamp(n: number, min: number, max: number) {
74
+ return Math.max(min, Math.min(max, n));
75
+ }
76
+
77
+ /**
78
+ * 将未知类型转换为数值并钳制到指定范围:不可转换(NaN/Infinity)时返回 min。
79
+ */
80
+ export function clampNumber(v: unknown, min: number, max: number) {
81
+ const n = typeof v === "number" ? v : Number(v);
82
+ if (!Number.isFinite(n)) return min;
83
+ return Math.max(min, Math.min(max, n));
84
+ }
85
+
86
+ /**
87
+ * 向上取整到最近的倍数。
88
+ */
89
+ export function roundUp(n: number, step: number) {
90
+ if (step <= 0) return n;
91
+ return Math.ceil(n / step) * step;
92
+ }
93
+
94
+ /**
95
+ * 将 {x,y,width,height} 转为矩形边界,并做边界保护(不会超出 maxWidth/maxHeight)。
96
+ */
97
+ export type RectBox = { left: number; top: number; right: number; bottom: number };
98
+ export function rectFromXYWH(
99
+ e: { x: number; y: number; width: number; height: number },
100
+ maxWidth: number,
101
+ maxHeight: number
102
+ ): RectBox {
103
+ const left = clamp(e.x, 0, maxWidth);
104
+ const top = clamp(e.y, 0, maxHeight);
105
+ const width = clamp(e.width, 1, maxWidth - left);
106
+ const height = clamp(e.height, 1, maxHeight - top);
107
+ return { left, top, right: left + width, bottom: top + height };
108
+ }
109
+
110
+ /**
111
+ * 同步 Canvas 像素尺寸(按容器尺寸 + DPR),并将 ctx 坐标系缩放到 CSS 像素单位。
112
+ * - DOM 看到的尺寸:canvas style width/height
113
+ * - 实际绘制的像素尺寸:canvas width/height(乘 dpr,避免高分屏模糊)
114
+ */
115
+ export type SyncCanvasSizeResult = {
116
+ width: number;
117
+ height: number;
118
+ dpr: number;
119
+ ctx: CanvasRenderingContext2D | null;
120
+ };
121
+ export function syncCanvasSizeToElement(
122
+ containerEl: HTMLElement,
123
+ canvasEl: HTMLCanvasElement
124
+ ): SyncCanvasSizeResult {
125
+ const rect = containerEl.getBoundingClientRect();
126
+ const dpr = window.devicePixelRatio || 1;
127
+ const width = Math.max(1, Math.round(rect.width));
128
+ const height = Math.max(1, Math.round(rect.height));
129
+
130
+ canvasEl.width = Math.round(width * dpr);
131
+ canvasEl.height = Math.round(height * dpr);
132
+ canvasEl.style.width = `${width}px`;
133
+ canvasEl.style.height = `${height}px`;
134
+
135
+ const ctx = canvasEl.getContext("2d");
136
+ ctx?.setTransform(dpr, 0, 0, dpr, 0, 0);
137
+
138
+ return { width, height, dpr, ctx };
139
+ }
140
+
141
+ /**
142
+ * 监听元素尺寸变化并在变化时执行回调,返回清理函数。
143
+ * - 优先使用 ResizeObserver;不可用时回退到 window.resize
144
+ */
145
+ export function observeElementResize(targetEl: Element, onResize: () => void) {
146
+ if (typeof ResizeObserver !== "undefined") {
147
+ const ro = new ResizeObserver(() => onResize());
148
+ ro.observe(targetEl);
149
+ return () => ro.disconnect();
150
+ }
151
+ if (typeof window === "undefined") return () => {};
152
+ window.addEventListener("resize", onResize);
153
+ return () => window.removeEventListener("resize", onResize);
154
+ }
155
+
156
+ /**
157
+ * 包装标签文本:限制每行字符数与最大行数,超出部分以省略号结尾。
158
+ */
159
+ export function wrapLabel(text: string, maxCharsPerLine: number, maxLines: number) {
160
+ const normalized = String(text ?? "");
161
+ if (!normalized) return "";
162
+
163
+ const chunks: string[] = [];
164
+ for (let i = 0; i < normalized.length; i += maxCharsPerLine) {
165
+ chunks.push(normalized.slice(i, i + maxCharsPerLine));
166
+ }
167
+
168
+ if (chunks.length <= maxLines) return chunks.join("\n");
169
+
170
+ const kept = chunks.slice(0, maxLines);
171
+ const lastIndex = kept.length - 1;
172
+ kept[lastIndex] = `${kept[lastIndex]}…`;
173
+ return kept.join("\n");
174
+ }
175
+
176
+ /**
177
+ * 截断字符串:最多显示 maxChars 个字符,超出部分用 ... 表示。
178
+ */
179
+ export function truncateLabel(text: string, maxChars: number) {
180
+ const normalized = String(text ?? "");
181
+ if (normalized.length <= maxChars) return normalized;
182
+ return `${normalized.slice(0, Math.max(0, maxChars - 3))}...`;
183
+ }
184
+
185
+ /**
186
+ * 从对象上安全读取字符串属性;不存在或非字符串返回空串。
187
+ */
188
+ export function getObjectString(obj: unknown, key: string) {
189
+ if (!obj || typeof obj !== "object") return "";
190
+ if (!(key in obj)) return "";
191
+ const v = (obj as Record<string, unknown>)[key];
192
+ return typeof v === "string" ? v : "";
193
+ }
194
+
195
+ /**
196
+ * 从对象上安全读取字符串/数字属性,并转换为字符串;不存在返回空串。
197
+ */
198
+ export function getObjectStringOrNumber(obj: unknown, key: string) {
199
+ if (!obj || typeof obj !== "object") return "";
200
+ if (!(key in obj)) return "";
201
+ const v = (obj as Record<string, unknown>)[key];
202
+ return typeof v === "string" || typeof v === "number" ? String(v) : "";
203
+ }
204
+
205
+ /**
206
+ * 从对象上安全读取数值属性(支持 number 与可转数字的 string);不可用时返回 0。
207
+ */
208
+ export function getObjectNumber(obj: unknown, key: string) {
209
+ if (!obj || typeof obj !== "object") return 0;
210
+ if (!(key in obj)) return 0;
211
+ return toNumber((obj as Record<string, unknown>)[key]);
212
+ }
213
+
214
+ /**
215
+ * 将十六进制颜色字符串转换为 RGB 对象。
216
+ * 支持 #RGB 与 #RRGGBB。
217
+ */
218
+ export function hexToRgb(hex: string): { r: number; g: number; b: number } {
219
+ const cleaned = String(hex ?? "")
220
+ .replace("#", "")
221
+ .trim();
222
+ const full =
223
+ cleaned.length === 3
224
+ ? cleaned
225
+ .split("")
226
+ .map((c) => c + c)
227
+ .join("")
228
+ : cleaned;
229
+ const n = parseInt(full, 16);
230
+ return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
231
+ }
232
+
233
+ /**
234
+ * 将 RGB 值转换为十六进制颜色字符串(#RRGGBB)。
235
+ */
236
+ export function rgbToHex(r: number, g: number, b: number) {
237
+ const to = (n: number) =>
238
+ Math.max(0, Math.min(255, Math.round(n)))
239
+ .toString(16)
240
+ .padStart(2, "0");
241
+ return `#${to(r)}${to(g)}${to(b)}`;
242
+ }
243
+
244
+ /**
245
+ * 将十六进制颜色变暗(amount:0~1,越大越暗)。
246
+ */
247
+ export function darkenHex(hex: string, amount: number) {
248
+ const { r, g, b } = hexToRgb(hex);
249
+ const k = Math.max(0, Math.min(1, 1 - amount));
250
+ return rgbToHex(r * k, g * k, b * k);
251
+ }
252
+
253
+ /**
254
+ * 将十六进制颜色转换为 rgba(alpha) 字符串。
255
+ * 支持 #RGB 与 #RRGGBB。
256
+ */
257
+ export function hexToRgba(hex: string, alpha: number) {
258
+ const cleaned = String(hex ?? "")
259
+ .replace("#", "")
260
+ .trim();
261
+ const full =
262
+ cleaned.length === 3
263
+ ? cleaned
264
+ .split("")
265
+ .map((c) => c + c)
266
+ .join("")
267
+ : cleaned;
268
+ const r = parseInt(full.slice(0, 2), 16);
269
+ const g = parseInt(full.slice(2, 4), 16);
270
+ const b = parseInt(full.slice(4, 6), 16);
271
+ const a = clampNumber(alpha, 0, 1);
272
+ return `rgba(${Number.isFinite(r) ? r : 0},${Number.isFinite(g) ? g : 0},${
273
+ Number.isFinite(b) ? b : 0
274
+ },${a})`;
275
+ }
276
+
277
+ /**
278
+ * 获取文本像素宽度。
279
+ * - estimate:按字符类型粗略估算(ASCII 0.6,其它 1)
280
+ * - canvas:使用 canvas.measureText 精确测量(无 document 或无法获取 ctx 时回退为估算)
281
+ */
282
+ export type TextWidthStrategy = "estimate" | "canvas";
283
+ let measureCanvas: HTMLCanvasElement | null = null;
284
+ export function getTextWidth(
285
+ text: string,
286
+ fontSizePx: number,
287
+ strategy: TextWidthStrategy = "estimate"
288
+ ) {
289
+ const str = String(text ?? "");
290
+
291
+ if (strategy === "canvas") {
292
+ if (typeof document === "undefined") {
293
+ return str.length * fontSizePx;
294
+ }
295
+ measureCanvas ??= document.createElement("canvas");
296
+ const ctx = measureCanvas.getContext("2d");
297
+ if (!ctx) return str.length * fontSizePx;
298
+ ctx.font = `${fontSizePx}px sans-serif`;
299
+ return ctx.measureText(str).width;
300
+ }
301
+
302
+ let units = 0;
303
+ for (const ch of str) {
304
+ units += ch.charCodeAt(0) <= 0x007f ? 0.6 : 1;
305
+ }
306
+ return units * fontSizePx;
307
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * ECharts 按需引入配置
3
+ * 只引入项目中使用的图表类型,减小打包体积
4
+ */
5
+
6
+ // 引入 echarts 核心模块
7
+ import * as echarts from "echarts/core";
8
+
9
+ // 引入图表类型
10
+ import {
11
+ BarChart,
12
+ PictorialBarChart,
13
+ LineChart,
14
+ PieChart,
15
+ RadarChart,
16
+ MapChart,
17
+ ScatterChart,
18
+ CustomChart,
19
+ } from "echarts/charts";
20
+
21
+ // 引入组件
22
+ import {
23
+ TitleComponent,
24
+ TooltipComponent,
25
+ GridComponent,
26
+ LegendComponent,
27
+ DatasetComponent,
28
+ TransformComponent,
29
+ GeoComponent,
30
+ VisualMapComponent,
31
+ MarkLineComponent,
32
+ MarkPointComponent,
33
+ GraphicComponent,
34
+ } from "echarts/components";
35
+
36
+ // 引入渲染器(必须)
37
+ import { LabelLayout, UniversalTransition } from "echarts/features";
38
+ import { CanvasRenderer } from "echarts/renderers";
39
+
40
+ // 注册必须的组件
41
+ echarts.use([
42
+ // 图表类型
43
+ BarChart,
44
+ PictorialBarChart,
45
+ LineChart,
46
+ PieChart,
47
+ RadarChart,
48
+ MapChart,
49
+ ScatterChart,
50
+ CustomChart,
51
+
52
+ // 组件
53
+ TitleComponent,
54
+ TooltipComponent,
55
+ GridComponent,
56
+ LegendComponent,
57
+ DatasetComponent,
58
+ TransformComponent,
59
+ GeoComponent,
60
+ VisualMapComponent,
61
+ MarkLineComponent,
62
+ MarkPointComponent,
63
+ GraphicComponent,
64
+
65
+ // 功能
66
+ LabelLayout,
67
+ UniversalTransition,
68
+
69
+ // 渲染器
70
+ CanvasRenderer,
71
+ ]);
72
+
73
+ // 导出配置好的 echarts
74
+ export { echarts };
75
+
76
+ /**
77
+ * 使用说明:
78
+ *
79
+ * 如果需要添加新的图表类型,按照以下步骤:
80
+ *
81
+ * 1. 从 'echarts/charts' 引入对应的图表
82
+ * 例如:import { GaugeChart } from 'echarts/charts'
83
+ *
84
+ * 2. 在 echarts.use([...]) 中注册
85
+ * 例如:echarts.use([..., GaugeChart])
86
+ *
87
+ * 常用图表类型:
88
+ * - BarChart 柱状图/条形图
89
+ * - LineChart 折线图/面积图
90
+ * - PieChart 饼图/环形图
91
+ * - ScatterChart 散点图/气泡图
92
+ * - CustomChart 自定义图表
93
+ * - RadarChart 雷达图
94
+ * - MapChart 地图
95
+ * - TreeChart 树图
96
+ * - TreemapChart 矩形树图
97
+ * - GraphChart 关系图
98
+ * - GaugeChart 仪表盘
99
+ * - FunnelChart 漏斗图
100
+ * - ParallelChart 平行坐标系
101
+ * - SankeyChart 桑基图
102
+ * - BoxplotChart 箱线图
103
+ * - CandlestickChart K线图
104
+ * - EffectScatterChart 涟漪特效散点图
105
+ * - LinesChart 线图
106
+ * - HeatmapChart 热力图
107
+ * - PictorialBarChart 象形柱图
108
+ * - ThemeRiverChart 主题河流图
109
+ * - SunburstChart 旭日图
110
+ * - CustomChart 自定义图
111
+ */
@@ -0,0 +1,99 @@
1
+ /**
2
+ * 数值单位转换工具函数
3
+ */
4
+
5
+ export type NumberUnit = "个" | "百" | "千" | "万" | "十万" | "百万" | "千万" | "亿";
6
+
7
+ export interface NumberUnitConversionResult {
8
+ value: number;
9
+ unit: NumberUnit;
10
+ displayText: string; // 格式化后的显示文本,如 "1.2万"
11
+ }
12
+
13
+ /**
14
+ * 将数值转换为带单位的显示格式
15
+ * @param value 原始数值
16
+ * @param minUnit 最小转换单位,小于此单位的值不进行转换(默认:"个")
17
+ * @param precision 小数位数(默认:1)
18
+ * @returns 转换后的数值、单位和显示文本
19
+ */
20
+ export function convertNumberUnit(
21
+ value: number,
22
+ minUnit: NumberUnit = "万",
23
+ precision = 1
24
+ ): NumberUnitConversionResult {
25
+ if (value === 0) {
26
+ return {
27
+ value: 0,
28
+ unit: "个",
29
+ displayText: "0",
30
+ };
31
+ }
32
+
33
+ const absValue = Math.abs(value);
34
+ const sign = value < 0 ? "-" : "";
35
+
36
+ // 定义单位转换规则(去掉十万,仅保留:个 / 百 / 千 / 万 / 百万 / 千万 / 亿)
37
+ const unitRules: Array<{ threshold: number; unit: NumberUnit }> = [
38
+ { threshold: 100000000, unit: "亿" }, // >= 1亿
39
+ { threshold: 10000000, unit: "千万" }, // >= 1千万 且 < 1亿
40
+ { threshold: 1000000, unit: "百万" }, // >= 1百万 且 < 1千万
41
+ { threshold: 10000, unit: "万" }, // >= 1万 且 < 1百万
42
+ { threshold: 1000, unit: "千" }, // >= 1千 且 < 1万
43
+ { threshold: 100, unit: "百" }, // >= 1百 且 < 1千
44
+ { threshold: 0, unit: "个" }, // 个位
45
+ ];
46
+
47
+ // 确定最小转换单位的阈值
48
+ const minUnitThreshold = unitRules.find((rule) => rule.unit === minUnit)?.threshold ?? 0;
49
+
50
+ // 找到合适的转换单位
51
+ let selectedRule = unitRules.find(
52
+ (rule) => absValue >= rule.threshold && rule.threshold >= minUnitThreshold
53
+ );
54
+
55
+ // 如果没有找到合适的单位(值小于最小单位),使用"个"
56
+ if (!selectedRule) {
57
+ selectedRule = { threshold: 0, unit: "个" };
58
+ }
59
+
60
+ // 计算转换后的数值
61
+ let convertedValue = absValue;
62
+ if (selectedRule.threshold > 0) {
63
+ convertedValue = absValue / selectedRule.threshold;
64
+ }
65
+
66
+ // 格式化数值(保留指定位数的小数)
67
+ const multiplier = Math.pow(10, precision);
68
+ const roundedValue = Math.round(convertedValue * multiplier) / multiplier;
69
+
70
+ // 生成显示文本
71
+ let displayText = "";
72
+ if (selectedRule.unit === "个") {
73
+ displayText = `${sign}${Math.round(absValue)}`;
74
+ } else {
75
+ // 如果小数部分为0,显示整数
76
+ if (roundedValue % 1 === 0) {
77
+ displayText = `${sign}${Math.round(roundedValue)}${selectedRule.unit}`;
78
+ } else {
79
+ displayText = `${sign}${roundedValue.toFixed(precision)}${selectedRule.unit}`;
80
+ }
81
+ }
82
+
83
+ return {
84
+ value: sign === "-" ? -roundedValue : roundedValue,
85
+ unit: selectedRule.unit,
86
+ displayText,
87
+ };
88
+ }
89
+
90
+ /**
91
+ * 将数值拆分为单个数字数组(用于数字展示组件)
92
+ * @param value 数值
93
+ * @returns 数字数组,如 1234 => [1, 2, 3, 4]
94
+ */
95
+ export function splitNumberToDigits(value: number): number[] {
96
+ return String(Math.abs(Math.round(value)))
97
+ .split("")
98
+ .map(Number);
99
+ }
@@ -0,0 +1,82 @@
1
+ /*
2
+ * @Description: 小于等于1920分辨率下的响应式方案
3
+ * @Version: 1.0
4
+ * @Autor: zhaozhenzhuo
5
+ * @Date: 2025-10-21 16:53:30
6
+ * @LastEditors: zhaozhenzhuo
7
+ * @LastEditTime: 2025-10-21 16:53:30
8
+ */
9
+ /* eslint-disable */
10
+ (function (designWidth: number, maxWidth: number, minWidth: number) {
11
+ const doc = document;
12
+ const win = window;
13
+ const docEl = document.documentElement;
14
+ let tid: NodeJS.Timeout;
15
+ let rootItem: HTMLElement | HTMLStyleElement | null;
16
+ let rootStyle;
17
+
18
+ function refreshRem() {
19
+ let width = document.getElementById("app")?.getBoundingClientRect().width;
20
+ let rem;
21
+ if (!maxWidth) {
22
+ maxWidth = 1920;
23
+ }
24
+ if (!minWidth) {
25
+ minWidth = 1366;
26
+ }
27
+ if (width && width > maxWidth) {
28
+ if (width <= 2560) {
29
+ rem = 11;
30
+ } else {
31
+ rem = 12;
32
+ }
33
+ } else if (width && width < minWidth) {
34
+ rem = (minWidth * 11) / designWidth;
35
+ } else {
36
+ // 与淘宝做法不同,直接采用简单的rem换算方法1rem=10px
37
+ rem = ((width && width > 0 ? width : 1920) * 10) / designWidth;
38
+ }
39
+
40
+ // 兼容UC开始
41
+ rootStyle = `html{font-size:${rem}px !important}`;
42
+ rootItem = document.getElementById("rootsize") || document.createElement("style");
43
+ if (!document.getElementById("rootsize")) {
44
+ document.getElementsByTagName("head")[0].appendChild(rootItem);
45
+ rootItem.id = "rootsize";
46
+ }
47
+ if (rootItem && (rootItem as any).styleSheet) {
48
+ (rootItem as any).styleSheet.disabled ||
49
+ ((rootItem as any).styleSheet.cssText = rootStyle);
50
+ } else {
51
+ try {
52
+ rootItem.innerHTML = rootStyle;
53
+ } catch (f) {
54
+ rootItem.innerText = rootStyle;
55
+ }
56
+ }
57
+ // 兼容UC结束
58
+ docEl.style.fontSize = `${rem}px`;
59
+ }
60
+ refreshRem();
61
+
62
+ win.addEventListener(
63
+ "resize",
64
+ function () {
65
+ clearTimeout(tid); // 防止执行两次
66
+ tid = setTimeout(refreshRem, 300);
67
+ },
68
+ false
69
+ );
70
+
71
+ win.addEventListener(
72
+ "pageshow",
73
+ function (e) {
74
+ if (e.persisted) {
75
+ // 浏览器后退的时候重新计算
76
+ clearTimeout(tid);
77
+ tid = setTimeout(refreshRem, 300);
78
+ }
79
+ },
80
+ false
81
+ );
82
+ })(1920, 1920, 1366);