befly-admin 3.15.0 → 3.15.2

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "befly-admin",
3
- "version": "3.15.0",
4
- "gitHead": "f3fd845d4fdbbf0db38a4e676162f3d710a9ce5b",
3
+ "version": "3.15.2",
4
+ "gitHead": "8d10717424ced255e301cb474d356863ab12509a",
5
5
  "private": false,
6
6
  "description": "Befly Admin - 基于 Vue3 + TDesign Vue Next 的后台管理系统",
7
7
  "files": [
@@ -28,13 +28,13 @@
28
28
  "preview": "bunx --bun befly-vite preview"
29
29
  },
30
30
  "dependencies": {
31
- "befly-admin-ui": "^1.9.0",
31
+ "befly-admin-ui": "^1.9.2",
32
32
  "befly-shared": "^2.0.6",
33
- "befly-vite": "^1.5.28",
33
+ "befly-vite": "^1.5.29",
34
34
  "pinia": "^3.0.4",
35
- "tdesign-icons-vue-next": "^0.4.0",
35
+ "tdesign-icons-vue-next": "^0.4.4",
36
36
  "tdesign-vue-next": "^1.18.6",
37
- "vue": "^3.5.31",
37
+ "vue": "^3.5.32",
38
38
  "vue-router": "^5.0.4"
39
39
  },
40
40
  "engines": {
@@ -1,15 +1,15 @@
1
- import adminPackageInfo from "../../package.json";
1
+ const apiPath = import.meta.env.PROD ? "https://api.yicode.tech/api" : "http://localhost:3000/api";
2
2
 
3
3
  export const $Config = {
4
4
  appTitle: "野蜂飞舞",
5
5
  appDesc: "轻量级业务快速开发框架",
6
6
  productName: "野蜂飞舞",
7
- productCode: adminPackageInfo.name,
8
- productVersion: adminPackageInfo.version,
7
+ productCode: "beflyAdmin",
8
+ productVersion: "1.0.0",
9
9
  loginFootnote: "",
10
10
  tokenName: "befly-admin-token",
11
11
  loginPath: "/core/login",
12
12
  homePath: "/core",
13
- uploadPath: "",
14
- apiPath: import.meta.env.PROD ? "http://localhost:3000/api" : "http://localhost:3000/api"
13
+ uploadPath: `${apiPath}/core/upload/file`,
14
+ apiPath: apiPath
15
15
  };
@@ -22,7 +22,22 @@ const finalRoutes = Layouts(routes, $Config.homePath, (layoutName) => {
22
22
  */
23
23
  export const $Router = createRouter({
24
24
  history: createWebHashHistory(import.meta.env.BASE_URL),
25
- routes: finalRoutes
25
+ routes: finalRoutes,
26
+ scrollBehavior(to, _from, savedPosition) {
27
+ if (savedPosition) {
28
+ return savedPosition;
29
+ }
30
+
31
+ // 首页等场景已有自定义 hash 滚动处理,这里避免重复抢占锚点定位。
32
+ if (to.hash) {
33
+ return undefined;
34
+ }
35
+
36
+ return {
37
+ left: 0,
38
+ top: 0
39
+ };
40
+ }
26
41
  });
27
42
 
28
43
  // 路由守卫 - 基础鉴权(最小实现:public 放行;未登录跳登录;已登录访问登录页跳首页)
@@ -24,33 +24,24 @@ body {
24
24
  }
25
25
 
26
26
  /* 滚动条样式 - 更精致 */
27
- // ::-webkit-scrollbar {
28
- // width: 6px;
29
- // height: 6px;
30
- // }
31
-
32
- // ::-webkit-scrollbar-track {
33
- // background: transparent;
34
- // }
27
+ ::-webkit-scrollbar {
28
+ width: 6px;
29
+ height: 6px;
30
+ }
35
31
 
36
- // ::-webkit-scrollbar-thumb {
37
- // background: #d9d9d9;
38
- // border-radius: 3px;
39
- // transition: background var(--transition-fast);
40
- // }
32
+ ::-webkit-scrollbar-track {
33
+ background: transparent;
34
+ }
41
35
 
42
- // ::-webkit-scrollbar-thumb:hover {
43
- // background: #bfbfbf;
44
- // }
36
+ ::-webkit-scrollbar-thumb {
37
+ background: #d9d9d9;
38
+ border-radius: 3px;
39
+ transition: background var(--transition-fast);
40
+ }
45
41
 
46
- // .tiny-dialog-box {
47
- // .tiny-dialog-box__header {
48
- // .tiny-dialog-box__headerbtn {
49
- // top: 0 !important;
50
- // right: 0 !important;
51
- // }
52
- // }
53
- // }
42
+ ::-webkit-scrollbar-thumb:hover {
43
+ background: #bfbfbf;
44
+ }
54
45
 
55
46
  /* 通用工具类 */
56
47
  .text-center {
@@ -150,7 +141,7 @@ body {
150
141
  position: relative;
151
142
  height: 100%;
152
143
  // 注意:Table 固定列依赖 sticky + 滚动容器计算;page 级别的 overflow 容器可能导致 fixed 失效
153
- overflow: visible;
144
+ overflow: hidden;
154
145
 
155
146
  // 工具栏
156
147
  .main-tool {
@@ -1,123 +0,0 @@
1
- <template>
2
- <PageDialog v-model="dialogVisible" :title="$Prop.actionType === 'upd' ? '编辑角色' : '新增角色'" :confirm-loading="$Data.submitting" @confirm="onSubmit">
3
- <div class="comp-simple-role-edit">
4
- <TForm :model="$Data.formData" label-width="100px" label-position="left" :rules="$Data2.formRules" ref="formRef">
5
- <TFormItem label="角色名称" prop="name">
6
- <TInput v-model="$Data.formData.name" placeholder="请输入角色名称" />
7
- </TFormItem>
8
- <TFormItem label="角色代码" prop="code">
9
- <TInput v-model="$Data.formData.code" placeholder="请输入角色代码,如:operator" />
10
- </TFormItem>
11
- <TFormItem label="角色描述" prop="description">
12
- <TInput v-model="$Data.formData.description" placeholder="请输入角色描述" />
13
- </TFormItem>
14
- <TFormItem label="排序" prop="sort">
15
- <TInputNumber v-model="$Data.formData.sort" :min="0" :max="9999" />
16
- </TFormItem>
17
- </TForm>
18
- </div>
19
- </PageDialog>
20
- </template>
21
-
22
- <script setup>
23
- import PageDialog from "befly-admin-ui/components/pageDialog.vue";
24
- import { fieldClear } from "befly-admin-ui/utils/fieldClear";
25
-
26
- const $Prop = defineProps({
27
- modelValue: {
28
- type: Boolean,
29
- default: false
30
- },
31
- actionType: {
32
- type: String,
33
- default: "add"
34
- },
35
- rowData: {
36
- type: Object,
37
- default: {}
38
- }
39
- });
40
-
41
- const $Emit = defineEmits(["update:modelValue", "success"]);
42
- const formRef = ref(null);
43
-
44
- const $Data = reactive({
45
- submitting: false,
46
- formData: {
47
- id: 0,
48
- name: "",
49
- code: "",
50
- description: "",
51
- sort: 0
52
- }
53
- });
54
-
55
- const $Data2 = reactive({
56
- formRules: {
57
- name: [{ required: true, message: "请输入角色名称", trigger: "blur" }],
58
- code: [
59
- { required: true, message: "请输入角色代码", trigger: "blur" },
60
- { pattern: /^[a-zA-Z0-9_]+$/, message: "角色代码只能包含字母、数字和下划线", trigger: "blur" }
61
- ],
62
- sort: [{ type: "number", message: "排序必须是数字", trigger: "blur" }]
63
- }
64
- });
65
-
66
- const dialogVisible = computed({
67
- get: () => $Prop.modelValue,
68
- set: (value) => {
69
- $Emit("update:modelValue", value);
70
- }
71
- });
72
-
73
- function initData() {
74
- if ($Prop.actionType === "upd" && $Prop.rowData.id) {
75
- $Data.formData = Object.assign({}, $Prop.rowData);
76
- return;
77
- }
78
-
79
- $Data.formData.id = 0;
80
- $Data.formData.name = "";
81
- $Data.formData.code = "";
82
- $Data.formData.description = "";
83
- $Data.formData.sort = 0;
84
- }
85
-
86
- async function onSubmit(context) {
87
- try {
88
- const form = formRef.value;
89
- if (!form) {
90
- MessagePlugin.warning("表单未就绪");
91
- return;
92
- }
93
-
94
- const valid = await form.validate();
95
- if (!valid) {
96
- return;
97
- }
98
-
99
- $Data.submitting = true;
100
- const payload = $Prop.actionType === "upd" ? $Data.formData : fieldClear($Data.formData, { omitKeys: ["id"] });
101
- const response = await $Http($Prop.actionType === "upd" ? "/core/role/upd" : "/core/role/ins", payload);
102
-
103
- MessagePlugin.success(response.msg || "操作成功");
104
- $Emit("success");
105
-
106
- if (context && typeof context.close === "function") {
107
- context.close();
108
- }
109
- } catch (error) {
110
- MessagePlugin.error(error.msg || error.message || "提交失败");
111
- } finally {
112
- $Data.submitting = false;
113
- }
114
- }
115
-
116
- initData();
117
- </script>
118
-
119
- <style scoped lang="scss">
120
- .comp-simple-role-edit {
121
- padding-top: 6px;
122
- }
123
- </style>
@@ -1,127 +0,0 @@
1
- <template>
2
- <PageTableDetail class="page-simple-table page-table" :columns="$Data.columns" :endpoints="$Data.endpoints">
3
- <template #toolLeft>
4
- <TButton theme="primary" @click="onAdd">
5
- <template #icon>
6
- <AddIcon />
7
- </template>
8
- </TButton>
9
- </template>
10
-
11
- <template #toolRight="scope">
12
- <TButton shape="circle" @click="onReload(scope.reload)">
13
- <template #icon>
14
- <RefreshIcon />
15
- </template>
16
- </TButton>
17
- </template>
18
-
19
- <template #operation="{ row, deleteRow }">
20
- <TDropdown trigger="click" placement="bottom-right" @click="onDropdownAction($event, row, deleteRow)">
21
- <TButton theme="primary" size="small">
22
- 操作
23
- <template #suffix><ChevronDownIcon /></template>
24
- </TButton>
25
- <TDropdownMenu slot="dropdown">
26
- <TDropdownItem value="upd">
27
- <EditIcon />
28
- 编辑
29
- </TDropdownItem>
30
- <TDropdownItem value="del" :divider="true">
31
- <DeleteIcon style="width: 14px; height: 14px; margin-right: 6px" />
32
- 删除
33
- </TDropdownItem>
34
- </TDropdownMenu>
35
- </TDropdown>
36
- </template>
37
-
38
- <template #dialogs="scope">
39
- <EditDialog v-if="$Data.editVisible" v-model="$Data.editVisible" :action-type="$Data.actionType" :row-data="$Data.rowData" @success="onDialogSuccess(scope.reload)" />
40
- </template>
41
- </PageTableDetail>
42
- </template>
43
-
44
- <script setup>
45
- import EditDialog from "./components/edit.vue";
46
- import PageTableDetail from "befly-admin-ui/components/pageTableDetail.vue";
47
- import { withDefaultColumns } from "befly-admin-ui/utils/withDefaultColumns";
48
-
49
- const $Data = reactive({
50
- columns: withDefaultColumns([
51
- { colKey: "name", title: "角色名称" },
52
- { colKey: "code", title: "角色代码", width: 180 },
53
- { colKey: "description", title: "角色描述" },
54
- { colKey: "sort", title: "排序", width: 100 },
55
- { colKey: "operation", title: "操作" }
56
- ]),
57
- endpoints: {
58
- list: {
59
- path: "/core/role/list",
60
- dropValues: [""]
61
- },
62
- delete: {
63
- path: "/core/role/del",
64
- idKey: "id",
65
- confirm: (row) => {
66
- return {
67
- header: "确认删除",
68
- body: `确认删除角色“${row.name}”吗?`,
69
- confirmBtn: "删除",
70
- status: "warning"
71
- };
72
- }
73
- }
74
- },
75
- editVisible: false,
76
- actionType: "add",
77
- rowData: {}
78
- });
79
-
80
- function onAdd() {
81
- onAction("add", {});
82
- }
83
-
84
- function onReload(reload) {
85
- reload({ keepSelection: true });
86
- }
87
-
88
- function onDialogSuccess(reload) {
89
- reload({ keepSelection: true });
90
- }
91
-
92
- function onAction(type, row) {
93
- if (type === "add") {
94
- $Data.actionType = "add";
95
- $Data.rowData = {};
96
- $Data.editVisible = true;
97
- return;
98
- }
99
-
100
- if (type === "upd") {
101
- $Data.actionType = "upd";
102
- $Data.rowData = Object.assign({}, row);
103
- $Data.editVisible = true;
104
- }
105
- }
106
-
107
- function onDropdownAction(data, row, deleteRow) {
108
- const record = data;
109
- const rawValue = record && record["value"] ? record["value"] : "";
110
- const command = rawValue ? String(rawValue) : "";
111
- if (command === "del") {
112
- deleteRow(row);
113
- return;
114
- }
115
- onAction(command, row);
116
- }
117
- </script>
118
-
119
- <style scoped lang="scss">
120
- .page-simple-table {
121
- .main-tool .right {
122
- display: flex;
123
- gap: 8px;
124
- align-items: center;
125
- }
126
- }
127
- </style>
@@ -1,306 +0,0 @@
1
- <template>
2
- <div class="dashboard">
3
- <h1>后台数据面板</h1>
4
- </div>
5
- </template>
6
-
7
- <script setup></script>
8
-
9
- <style lang="scss" scoped>
10
- .dashboard {
11
- padding: 20px;
12
- min-height: 100vh;
13
- background-color: #f5f7fa;
14
- font-family: "Arial", sans-serif;
15
- }
16
-
17
- h1 {
18
- color: #2c3e50;
19
- font-size: 24px;
20
- margin-bottom: 20px;
21
- font-weight: 600;
22
- }
23
-
24
- .stats-grid {
25
- display: grid;
26
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
27
- gap: 20px;
28
- margin-bottom: 20px;
29
- }
30
-
31
- .stat-card {
32
- background-color: #fff;
33
- border-radius: 12px;
34
- padding: 20px;
35
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
36
- display: flex;
37
- align-items: center;
38
- transition:
39
- transform 0.2s,
40
- box-shadow 0.2s;
41
-
42
- &:hover {
43
- transform: translateY(-5px);
44
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
45
- }
46
- }
47
-
48
- .stat-icon {
49
- width: 60px;
50
- height: 60px;
51
- border-radius: 12px;
52
- display: flex;
53
- align-items: center;
54
- justify-content: center;
55
- font-size: 24px;
56
- margin-right: 20px;
57
- color: #fff;
58
-
59
- &.blue {
60
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
61
- }
62
-
63
- &.green {
64
- background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
65
- }
66
-
67
- &.purple {
68
- background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
69
- }
70
-
71
- &.orange {
72
- background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
73
- }
74
- }
75
-
76
- .stat-content {
77
- flex: 1;
78
- }
79
-
80
- .stat-number {
81
- font-size: 24px;
82
- font-weight: 700;
83
- color: #2c3e50;
84
- margin-bottom: 4px;
85
- }
86
-
87
- .stat-label {
88
- font-size: 14px;
89
- color: #90a4ae;
90
- margin-bottom: 4px;
91
- }
92
-
93
- .stat-change {
94
- font-size: 12px;
95
- font-weight: 600;
96
-
97
- &.positive {
98
- color: #4caf50;
99
- }
100
-
101
- &.negative {
102
- color: #f44336;
103
- }
104
- }
105
-
106
- .charts-section {
107
- display: grid;
108
- grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
109
- gap: 20px;
110
- margin-bottom: 20px;
111
-
112
- @media (max-width: 768px) {
113
- grid-template-columns: 1fr;
114
- }
115
- }
116
-
117
- .chart-card {
118
- background-color: #fff;
119
- border-radius: 12px;
120
- padding: 20px;
121
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
122
- }
123
-
124
- .chart-card h3 {
125
- color: #2c3e50;
126
- font-size: 18px;
127
- margin-bottom: 20px;
128
- font-weight: 600;
129
- }
130
-
131
- .chart-container {
132
- height: 250px;
133
- background-color: #fafafa;
134
- border-radius: 8px;
135
- padding: 20px;
136
- display: flex;
137
- align-items: center;
138
- justify-content: center;
139
- position: relative;
140
- overflow: hidden;
141
- }
142
-
143
- .line-chart {
144
- width: 100%;
145
- height: 100%;
146
- position: relative;
147
-
148
- .chart-grid {
149
- position: absolute;
150
- top: 0;
151
- left: 0;
152
- right: 0;
153
- bottom: 0;
154
- background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0.05) 1px, transparent 1px), linear-gradient(to right, rgba(0, 0, 0, 0.05) 1px, transparent 1px);
155
- background-size: 40px 40px;
156
- }
157
-
158
- .chart-line {
159
- position: absolute;
160
- top: 50%;
161
- left: 0;
162
- right: 0;
163
- height: 2px;
164
- background: linear-gradient(to right, #3498db, #9b59b6);
165
- animation: lineMove 3s ease-in-out infinite;
166
- }
167
-
168
- .chart-labels {
169
- position: absolute;
170
- bottom: 0;
171
- left: 0;
172
- right: 0;
173
- display: flex;
174
- justify-content: space-between;
175
- font-size: 11px;
176
- color: #90a4ae;
177
- padding: 0 10px;
178
- }
179
- }
180
-
181
- @keyframes lineMove {
182
- 0%,
183
- 100% {
184
- transform: translateY(0);
185
- }
186
- 50% {
187
- transform: translateY(-50px);
188
- }
189
- }
190
-
191
- .bar-chart {
192
- width: 100%;
193
- height: 100%;
194
- display: flex;
195
- align-items: flex-end;
196
- justify-content: center;
197
- gap: 40px;
198
- }
199
-
200
- .bar-group {
201
- display: flex;
202
- align-items: flex-end;
203
- gap: 20px;
204
- }
205
-
206
- .bar {
207
- width: 80px;
208
- border-radius: 4px 4px 0 0;
209
- display: flex;
210
- flex-direction: column;
211
- align-items: center;
212
- justify-content: flex-end;
213
- padding: 10px 0;
214
- position: relative;
215
- transition: transform 0.3s ease;
216
-
217
- &:hover {
218
- transform: scaleY(1.05);
219
- }
220
-
221
- .bar-label {
222
- font-size: 12px;
223
- color: #2c3e50;
224
- margin-bottom: 4px;
225
- font-weight: 600;
226
- }
227
-
228
- .bar-value {
229
- font-size: 14px;
230
- color: #fff;
231
- font-weight: 700;
232
- margin-bottom: 4px;
233
- }
234
- }
235
-
236
- .orders-table-card {
237
- background-color: #fff;
238
- border-radius: 12px;
239
- padding: 20px;
240
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
241
- }
242
-
243
- .orders-table-card h3 {
244
- color: #2c3e50;
245
- font-size: 18px;
246
- margin-bottom: 20px;
247
- font-weight: 600;
248
- }
249
-
250
- .table-container {
251
- overflow-x: auto;
252
- }
253
-
254
- .orders-table {
255
- width: 100%;
256
- border-collapse: collapse;
257
- }
258
-
259
- .orders-table th {
260
- background-color: #f5f7fa;
261
- color: #2c3e50;
262
- text-align: left;
263
- padding: 12px;
264
- font-weight: 600;
265
- font-size: 14px;
266
- border-bottom: 2px solid #e0e0e0;
267
- }
268
-
269
- .orders-table td {
270
- padding: 12px;
271
- font-size: 14px;
272
- color: #455a64;
273
- border-bottom: 1px solid #e0e0e0;
274
- }
275
-
276
- .orders-table tbody tr:hover {
277
- background-color: #fafafa;
278
- }
279
-
280
- .status {
281
- padding: 4px 12px;
282
- border-radius: 12px;
283
- font-size: 12px;
284
- font-weight: 600;
285
-
286
- &.completed {
287
- background-color: #e8f5e9;
288
- color: #4caf50;
289
- }
290
-
291
- &.pending {
292
- background-color: #fff3e0;
293
- color: #ff9800;
294
- }
295
-
296
- &.shipping {
297
- background-color: #e3f2fd;
298
- color: #2196f3;
299
- }
300
-
301
- &.cancelled {
302
- background-color: #ffebee;
303
- color: #f44336;
304
- }
305
- }
306
- </style>