befly-admin 3.12.17 → 3.12.18

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/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # Befly Admin
2
2
 
3
- 基于 Vue3 + TDesign Vue Next + TypeScript + Vite 的后台管理系统。
3
+ 基于 Vue3 + TDesign Vue Next + JavaScript + Vite 的后台管理系统。
4
4
 
5
5
  ## 技术栈
6
6
 
7
7
  - **Vue 3** - 渐进式 JavaScript 框架
8
8
  - **TDesign Vue Next** - 企业级设计体系
9
- - **TypeScript** - 类型安全
9
+ - **JavaScript** - 运行时语言
10
10
  - **Vite** - 下一代前端构建工具
11
11
  - **SCSS** - CSS 预处理器
12
12
  - **Vue Router** - 路由管理
@@ -19,7 +19,7 @@
19
19
  - ✅ 自动导入 Vue3 API(ref、reactive、computed 等)
20
20
  - ✅ 自动导入 TDesign 组件(无需手动注册)
21
21
  - ✅ 自动导入 Vue Router 和 Pinia API
22
- - ✅ TypeScript 类型安全
22
+ - ✅ JavaScript
23
23
  - ✅ SCSS 支持(全局变量 + Mixins)
24
24
  - ✅ 响应式布局
25
25
  - ✅ 路由权限控制
@@ -41,7 +41,7 @@ bun run build
41
41
  bun run preview
42
42
 
43
43
  # 类型检查
44
- bun run type-check
44
+ (已移除类型检查相关步骤)
45
45
  ```
46
46
 
47
47
  ## 项目结构
@@ -55,12 +55,12 @@ admin/
55
55
  │ │ └── dashboard/ # 仪表盘
56
56
  │ ├── router/ # 路由配置
57
57
  │ ├── styles/ # 全局样式
58
- │ ├── types/ # 类型定义
58
+ │ ├── types/ # 类型定义(如有)
59
59
  │ ├── App.vue # 根组件
60
- │ └── main.ts # 入口文件
60
+ │ └── main.js # 入口文件
61
61
  ├── index.html
62
- ├── vite.config.ts # Vite 配置
63
- ├── tsconfig.json # TypeScript 配置
62
+ ├── vite.config.js # Vite 配置
63
+ ├── jsconfig.json # JavaScript 配置
64
64
  └── package.json
65
65
  ```
66
66
 
@@ -70,7 +70,7 @@ admin/
70
70
 
71
71
  无需手动导入以下 API,直接使用即可:
72
72
 
73
- ```typescript
73
+ ```javascript
74
74
  // ❌ 不需要这样写
75
75
  import { ref, computed, onMounted } from "vue";
76
76
  import { useRouter, useRoute } from "vue-router";
@@ -94,7 +94,7 @@ TDesign 组件无需手动导入和注册:
94
94
  <t-table :data="tableData" />
95
95
  </template>
96
96
 
97
- <script setup lang="ts">
97
+ <script setup>
98
98
  // ❌ 不需要这样写
99
99
  // import { Button, Input, Table } from 'tdesign-vue-next';
100
100
  </script>
@@ -109,11 +109,9 @@ TDesign 组件无需手动导入和注册:
109
109
  - **开发服务器**: 端口 5173,自动打开浏览器
110
110
  - **代理配置**: `/api` 代理到 `http://localhost:3000`
111
111
 
112
- ### TypeScript 配置
112
+ ### JavaScript 配置
113
113
 
114
- - **严格模式**: 启用所有严格类型检查
115
114
  - **路径映射**: `@/*` 映射到 `src/*`
116
- - **自动生成类型**: `auto-imports.d.ts` 和 `components.d.ts`
117
115
 
118
116
  ## 构建
119
117
 
@@ -133,7 +131,7 @@ bun run build
133
131
 
134
132
  ## 注意事项
135
133
 
136
- 1. **自动导入的类型定义**:首次运行会生成 `src/types/auto-imports.d.ts` 和 `components.d.ts`
134
+ 1. **自动导入**:按需配置自动导入范围
137
135
  2. **登录功能**:当前为模拟登录,需要对接真实 API
138
136
  3. **Token 存储**:使用 localStorage,生产环境建议使用更安全的方式
139
137
  4. **API 代理**:开发环境 `/api` 代理到 `http://localhost:3000`
package/index.html CHANGED
@@ -8,6 +8,6 @@
8
8
  </head>
9
9
  <body>
10
10
  <div id="app"></div>
11
- <script type="module" src="/src/main.ts"></script>
11
+ <script type="module" src="/src/main.js"></script>
12
12
  </body>
13
13
  </html>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "befly-admin",
3
- "version": "3.12.17",
4
- "gitHead": "3e9154027578c8eb3ba49141eef7c6ea3b385d7f",
3
+ "version": "3.12.18",
4
+ "gitHead": "3f389979b8d565fe0476e0859df5a2c94627137c",
5
5
  "private": false,
6
6
  "description": "Befly Admin - 基于 Vue3 + TDesign Vue Next 的后台管理系统",
7
7
  "files": [
@@ -28,15 +28,14 @@
28
28
  "preview": "bunx --bun vite preview"
29
29
  },
30
30
  "dependencies": {
31
- "@befly-addon/admin": "^1.8.13",
32
- "@iconify-json/lucide": "^1.2.88",
33
- "axios": "^1.13.4",
34
- "befly-shared": "^1.4.5",
35
- "befly-vite": "^1.4.14",
31
+ "axios": "^1.13.5",
32
+ "befly-admin-ui": "1.8.14",
33
+ "befly-vite": "^1.4.15",
36
34
  "pinia": "^3.0.4",
37
- "tdesign-vue-next": "^1.18.1",
38
- "vite": "^8.0.0-beta.13",
39
- "vue": "^3.5.27",
35
+ "tdesign-icons-vue-next": "^0.4.0",
36
+ "tdesign-vue-next": "^1.18.2",
37
+ "vite": "^8.0.0-beta.15",
38
+ "vue": "^3.5.28",
40
39
  "vue-router": "^5.0.2"
41
40
  },
42
41
  "engines": {
package/src/App.vue CHANGED
@@ -6,7 +6,7 @@
6
6
  </t-config-provider>
7
7
  </template>
8
8
 
9
- <script setup lang="ts">
9
+ <script setup>
10
10
  const globalConfig = {
11
11
  dialog: {
12
12
  closeOnOverlayClick: false
@@ -30,20 +30,8 @@
30
30
  </div>
31
31
  </template>
32
32
 
33
- <script setup lang="ts">
34
- type DetailPanelFieldInput = {
35
- colKey?: string;
36
- title?: string;
37
- default?: string;
38
- formatter?: (value: unknown) => unknown;
39
- };
40
-
41
- type DetailPanelFieldNormalized = {
42
- colKey: string;
43
- title: string;
44
- default?: string;
45
- formatter?: (value: unknown) => unknown;
46
- };
33
+ <script setup>
34
+ import { isString } from "../utils/is.js";
47
35
 
48
36
  const props = defineProps({
49
37
  /**
@@ -83,19 +71,19 @@ const props = defineProps({
83
71
  * 所以这里必须暴露为顶层 computed,避免 v-for 误迭代 computed 对象本身。
84
72
  */
85
73
  const normalizedFields = computed(() => {
86
- const row = props.data as Record<string, unknown> | null;
74
+ const row = props.data && typeof props.data === "object" ? props.data : null;
87
75
  const dataId = row && Object.hasOwn(row, "id") ? row.id : undefined;
88
76
 
89
- const rawFields = props.fields as unknown;
77
+ const rawFields = props.fields;
90
78
  const inputFields = Array.isArray(rawFields) ? rawFields : [];
91
- const excludeKeys = props.excludeKeys as Array<string>;
79
+ const excludeKeys = Array.isArray(props.excludeKeys) ? props.excludeKeys : [];
92
80
 
93
81
  const fields = inputFields
94
- .filter((item): item is DetailPanelFieldInput => {
82
+ .filter((item) => {
95
83
  return Boolean(item) && typeof item === "object";
96
84
  })
97
- .map((item): DetailPanelFieldNormalized | null => {
98
- const colKey = typeof item.colKey === "string" ? item.colKey : "";
85
+ .map((item) => {
86
+ const colKey = isString(item.colKey) ? item.colKey : "";
99
87
  if (colKey.length === 0) {
100
88
  return null;
101
89
  }
@@ -104,7 +92,7 @@ const normalizedFields = computed(() => {
104
92
  }
105
93
 
106
94
  const titleRaw = item.title;
107
- const title = typeof titleRaw === "string" && titleRaw.length > 0 ? titleRaw : colKey;
95
+ const title = isString(titleRaw) && titleRaw.length > 0 ? titleRaw : colKey;
108
96
 
109
97
  return {
110
98
  colKey: colKey,
@@ -113,7 +101,7 @@ const normalizedFields = computed(() => {
113
101
  formatter: item.formatter
114
102
  };
115
103
  })
116
- .filter((item): item is DetailPanelFieldNormalized => {
104
+ .filter((item) => {
117
105
  return Boolean(item);
118
106
  });
119
107
 
@@ -131,23 +119,23 @@ const normalizedFields = computed(() => {
131
119
  if (!item || typeof item !== "object") {
132
120
  return false;
133
121
  }
134
- const record = item as unknown as Record<string, unknown>;
122
+ const record = item;
135
123
  const colKey = record["colKey"];
136
- return typeof colKey === "string" && colKey.length > 0;
124
+ return isString(colKey) && colKey.length > 0;
137
125
  });
138
126
 
139
127
  return safeFields;
140
128
  });
141
129
 
142
- function formatValue(value: unknown, field: DetailPanelFieldNormalized) {
130
+ function formatValue(value, field) {
143
131
  if (value === null || value === undefined || value === "") {
144
132
  return field.default || "-";
145
133
  }
146
134
  if (field.formatter) {
147
135
  const result = field.formatter(value);
148
- return typeof result === "string" ? result : String(result);
136
+ return isString(result) ? result : String(result);
149
137
  }
150
- return typeof value === "string" ? value : String(value);
138
+ return isString(value) ? value : String(value);
151
139
  }
152
140
  </script>
153
141
 
@@ -1,19 +1,5 @@
1
1
  <template>
2
- <TDialog
3
- v-model:visible="innerVisible"
4
- :header="props.title === '' ? true : props.title"
5
- :width="props.width"
6
- placement="center"
7
- attach="body"
8
- :close-btn="false"
9
- :footer="true"
10
- :confirm-loading="props.confirmLoading"
11
- :close-on-overlay-click="false"
12
- :close-on-esc-keydown="false"
13
- @close="onDialogClose"
14
- @confirm="onDialogConfirm"
15
- @cancel="onDialogCancel"
16
- >
2
+ <TDialog v-model:visible="innerVisible" :header="props.title === '' ? true : props.title" :width="props.width" placement="center" attach="body" :close-btn="false" :footer="true" :confirm-loading="props.confirmLoading" :close-on-overlay-click="false" :close-on-esc-keydown="false" @close="onDialogClose" @confirm="onDialogConfirm" @cancel="onDialogCancel">
17
3
  <template #footer>
18
4
  <div class="dialog-footer">
19
5
  <TButton variant="outline" @click="onFooterClose">关闭</TButton>
@@ -28,7 +14,7 @@
28
14
  </TDialog>
29
15
  </template>
30
16
 
31
- <script setup lang="ts">
17
+ <script setup>
32
18
  import { onBeforeUnmount, onMounted, ref, watch } from "vue";
33
19
 
34
20
  import { Button as TButton, Dialog as TDialog, Popconfirm as TPopconfirm } from "tdesign-vue-next";
@@ -37,48 +23,38 @@ defineOptions({
37
23
  inheritAttrs: false
38
24
  });
39
25
 
40
- type DialogTrigger = "close" | "confirm" | "cancel";
41
-
42
- type PageDialogEventContext = {
43
- trigger: DialogTrigger;
44
- visible: boolean;
45
- open: () => void;
46
- close: () => void;
47
- toggle: () => void;
48
- getVisible: () => boolean;
49
- };
50
-
51
26
  const openDelay = 100;
52
27
  const closeDelay = 300;
53
28
 
54
- const props = withDefaults(
55
- defineProps<{
56
- // 受控模式:传 v-model / modelValue 时由上层控制;组件会帮你处理关闭时的 update
57
- modelValue?: boolean;
58
- title?: string;
59
- width?: string;
60
- confirmLoading?: boolean;
61
- isConfirm?: boolean;
62
- }>(),
63
- {
64
- title: "",
65
- width: "600px",
66
- confirmLoading: false,
67
- isConfirm: true
29
+ const props = defineProps({
30
+ modelValue: {
31
+ type: Boolean,
32
+ default: undefined
33
+ },
34
+ title: {
35
+ type: String,
36
+ default: ""
37
+ },
38
+ width: {
39
+ type: String,
40
+ default: "600px"
41
+ },
42
+ confirmLoading: {
43
+ type: Boolean,
44
+ default: false
45
+ },
46
+ isConfirm: {
47
+ type: Boolean,
48
+ default: true
68
49
  }
69
- );
50
+ });
70
51
 
71
- const emit = defineEmits<{
72
- (e: "update:modelValue", value: boolean): void;
73
- (e: "close", context: PageDialogEventContext): void;
74
- (e: "confirm", context: PageDialogEventContext): void;
75
- (e: "cancel", context: PageDialogEventContext): void;
76
- }>();
52
+ const emit = defineEmits(["update:modelValue", "close", "confirm", "cancel"]);
77
53
 
78
- let openDelayTimer: ReturnType<typeof setTimeout> | null = null;
79
- let closeDelayTimer: ReturnType<typeof setTimeout> | null = null;
54
+ let openDelayTimer = null;
55
+ let closeDelayTimer = null;
80
56
 
81
- function clearTimer(timer: ReturnType<typeof setTimeout> | null): null {
57
+ function clearTimer(timer) {
82
58
  if (timer) {
83
59
  clearTimeout(timer);
84
60
  }
@@ -86,13 +62,13 @@ function clearTimer(timer: ReturnType<typeof setTimeout> | null): null {
86
62
  }
87
63
 
88
64
  // 所有弹框约定:始终使用 v-if + v-model(modelValue)
89
- const innerVisible = ref<boolean>(false);
65
+ const innerVisible = ref(false);
90
66
 
91
- function open(): void {
67
+ function open() {
92
68
  emit("update:modelValue", true);
93
69
  }
94
70
 
95
- function close(): void {
71
+ function close() {
96
72
  openDelayTimer = clearTimer(openDelayTimer);
97
73
  closeDelayTimer = clearTimer(closeDelayTimer);
98
74
 
@@ -104,7 +80,7 @@ function close(): void {
104
80
  }, closeDelay);
105
81
  }
106
82
 
107
- function toggle(): void {
83
+ function toggle() {
108
84
  if (innerVisible.value) {
109
85
  close();
110
86
  return;
@@ -112,7 +88,7 @@ function toggle(): void {
112
88
  open();
113
89
  }
114
90
 
115
- function createEventContext(trigger: DialogTrigger): PageDialogEventContext {
91
+ function createEventContext(trigger) {
116
92
  return {
117
93
  trigger: trigger,
118
94
  visible: innerVisible.value,
@@ -123,7 +99,7 @@ function createEventContext(trigger: DialogTrigger): PageDialogEventContext {
123
99
  };
124
100
  }
125
101
 
126
- function applyModelValue(value: boolean): void {
102
+ function applyModelValue(value) {
127
103
  if (value) {
128
104
  // 关键点:先渲染为 false,再延迟 true,保证 v-if + 初次 visible=true 时也能触发进入动画
129
105
  openDelayTimer = clearTimer(openDelayTimer);
@@ -162,7 +138,7 @@ watch(
162
138
  { immediate: false }
163
139
  );
164
140
 
165
- function closeByTrigger(trigger: DialogTrigger): void {
141
+ function closeByTrigger(trigger) {
166
142
  // 固定交互:confirm 不自动关闭(等待异步提交成功后由调用侧 context.close() 决定关闭)
167
143
  if (trigger === "confirm") {
168
144
  return;
@@ -171,31 +147,31 @@ function closeByTrigger(trigger: DialogTrigger): void {
171
147
  close();
172
148
  }
173
149
 
174
- function onDialogClose(): void {
150
+ function onDialogClose() {
175
151
  const context = createEventContext("close");
176
152
  closeByTrigger("close");
177
153
  emit("close", context);
178
154
  }
179
155
 
180
- function onDialogConfirm(): void {
156
+ function onDialogConfirm() {
181
157
  const context = createEventContext("confirm");
182
158
  emit("confirm", context);
183
159
  closeByTrigger("confirm");
184
160
  }
185
161
 
186
- function onDialogCancel(): void {
162
+ function onDialogCancel() {
187
163
  const context = createEventContext("cancel");
188
164
  emit("cancel", context);
189
165
  closeByTrigger("cancel");
190
166
  }
191
167
 
192
- function onFooterConfirm(): void {
168
+ function onFooterConfirm() {
193
169
  const context = createEventContext("confirm");
194
170
  emit("confirm", context);
195
171
  closeByTrigger("confirm");
196
172
  }
197
173
 
198
- function onFooterClose(): void {
174
+ function onFooterClose() {
199
175
  const context = createEventContext("cancel");
200
176
  emit("cancel", context);
201
177
  closeByTrigger("cancel");