@befly-addon/admin 1.8.4 → 1.8.6

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.
@@ -31,7 +31,7 @@
31
31
  <TOption value="phone" label="手机号" />
32
32
  </TSelect>
33
33
  </template>
34
- <TInput v-model="$Data.formData.account" :placeholder="$Data.formData.loginType === 'username' ? '请输入用户名' : $Data.formData.loginType === 'email' ? '请输入邮箱' : '请输入手机号'" size="large" clearable @enter="$Method.apiLogin">
34
+ <TInput v-model="$Data.formData.account" :placeholder="$Data.formData.loginType === 'username' ? '请输入用户名' : $Data.formData.loginType === 'email' ? '请输入邮箱' : '请输入手机号'" size="large" clearable @enter="apiLogin">
35
35
  <template #prefix-icon>
36
36
  <ILucideUser />
37
37
  </template>
@@ -40,7 +40,7 @@
40
40
  </TFormItem>
41
41
 
42
42
  <TFormItem prop="password">
43
- <TInput v-model="$Data.formData.password" type="password" placeholder="密码" size="large" clearable @enter="$Method.apiLogin">
43
+ <TInput v-model="$Data.formData.password" type="password" placeholder="密码" size="large" clearable @enter="apiLogin">
44
44
  <template #prefix-icon>
45
45
  <ILucideLock />
46
46
  </template>
@@ -52,7 +52,7 @@
52
52
  <a href="#" class="link-text">忘记密码?</a>
53
53
  </div>
54
54
 
55
- <TButton theme="primary" class="login-btn" size="large" block :loading="$Data.loading" @click="$Method.apiLogin"> 登录 </TButton>
55
+ <TButton theme="primary" class="login-btn" size="large" block :loading="$Data.loading" @click="apiLogin"> 登录 </TButton>
56
56
  </TForm>
57
57
 
58
58
  <div class="login-footer">
@@ -94,42 +94,35 @@ const $Data = $ref({
94
94
  }
95
95
  });
96
96
 
97
- // 方法定义
98
- const $Method = {
99
- async apiLogin() {
100
- try {
101
- await $From.form.validate();
97
+ async function apiLogin(): Promise<void> {
98
+ try {
99
+ await $From.form.validate();
102
100
 
103
- $Data.loading = true;
101
+ $Data.loading = true;
104
102
 
105
- // 对密码进行 SHA-256 加密
106
- const hashedPassword = await hashPassword($Data.formData.password);
103
+ const hashedPassword = await hashPassword($Data.formData.password);
107
104
 
108
- const res = await $Http.post("/addon/admin/auth/login", {
109
- loginType: $Data.formData.loginType,
110
- account: $Data.formData.account,
111
- password: hashedPassword
112
- });
105
+ const res = await $Http.post("/addon/admin/auth/login", {
106
+ loginType: $Data.formData.loginType,
107
+ account: $Data.formData.account,
108
+ password: hashedPassword
109
+ });
113
110
 
114
- // 先保存 token
115
- $Storage.local.set("token", res.data.token);
111
+ $Storage.local.set("token", res.data.token);
116
112
 
117
- // 如果返回用户信息,也可以存储
118
- if (res.data.userInfo) {
119
- $Storage.local.set("userInfo", res.data.userInfo);
120
- }
113
+ if (res.data.userInfo) {
114
+ $Storage.local.set("userInfo", res.data.userInfo);
115
+ }
121
116
 
122
- MessagePlugin.success(res.msg || "登录成功");
117
+ MessagePlugin.success(res.msg || "登录成功");
123
118
 
124
- // 跳转到首页,路由守卫会自动加载菜单
125
- await router.push("/");
126
- } catch (error) {
127
- MessagePlugin.error("登录失败");
128
- } finally {
129
- $Data.loading = false;
130
- }
119
+ await router.push("/");
120
+ } catch (error) {
121
+ MessagePlugin.error("登录失败");
122
+ } finally {
123
+ $Data.loading = false;
131
124
  }
132
- };
125
+ }
133
126
  </script>
134
127
 
135
128
  <style scoped lang="scss">
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <TDialog v-model:visible="$Data.visible" :header="$Prop.actionType === 'upd' ? '编辑管理员' : '添加管理员'" width="600px" :append-to-body="true" :show-footer="true" :esc-closable="false" top="10vh" @close="$Method.onClose">
2
+ <PageDialog v-model="dialogVisible" :title="$Prop.actionType === 'upd' ? '编辑管理员' : '添加管理员'" :confirm-loading="$Data.submitting" @confirm="onSubmit">
3
3
  <div class="dialog-wrapper">
4
4
  <TForm :model="$Data.formData" label-width="80px" label-position="left" label-align="left" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)">
5
5
  <TFormItem label="角色" prop="roleCode">
@@ -22,30 +22,23 @@
22
22
  </TFormItem>
23
23
  </TForm>
24
24
  </div>
25
- <template #footer>
26
- <div class="dialog-footer">
27
- <t-space>
28
- <TButton theme="default" @click="$Method.onClose">取消</TButton>
29
- <TButton theme="primary" :loading="$Data.submitting" @click="$Method.onSubmit">确定</TButton>
30
- </t-space>
31
- </div>
32
- </template>
33
- </TDialog>
25
+ </PageDialog>
34
26
  </template>
35
27
 
36
28
  <script setup lang="ts">
29
+ import { computed } from "vue";
30
+
37
31
  import {
38
32
  //
39
- Dialog as TDialog,
40
33
  Form as TForm,
41
34
  FormItem as TFormItem,
42
35
  Input as TInput,
43
36
  Select as TSelect,
44
37
  RadioGroup as TRadioGroup,
45
38
  Radio as TRadio,
46
- Button as TButton,
47
39
  MessagePlugin
48
40
  } from "tdesign-vue-next";
41
+ import PageDialog from "@/components/pageDialog.vue";
49
42
  import { $Http } from "@/plugins/http";
50
43
  import { fieldClear } from "befly-shared/utils/fieldClear";
51
44
  import { hashPassword } from "befly-shared/utils/hashPassword";
@@ -70,13 +63,23 @@ const $Emit = defineEmits<{
70
63
  (e: "success"): void;
71
64
  }>();
72
65
 
66
+ type PageDialogEventContext = {
67
+ close: () => void;
68
+ };
69
+
73
70
  // 表单引用
74
71
  const $From = $shallowRef({
75
72
  form: null
76
73
  });
77
74
 
75
+ const dialogVisible = computed({
76
+ get: () => $Prop.modelValue,
77
+ set: (value) => {
78
+ $Emit("update:modelValue", value);
79
+ }
80
+ });
81
+
78
82
  const $Data = $ref({
79
- visible: false,
80
83
  submitting: false,
81
84
  allRoleLists: [],
82
85
  keys: {
@@ -105,71 +108,56 @@ const $Data2 = $shallowRef({
105
108
  }
106
109
  });
107
110
 
108
- // 方法集合
109
- const $Method = {
110
- async initData() {
111
- $Method.onShow();
112
- await $Method.apiRoleLists();
113
- if ($Prop.actionType === "upd" && $Prop.rowData.id) {
114
- $Data.formData = Object.assign({}, $Prop.rowData);
115
- }
116
- },
111
+ async function initData(): Promise<void> {
112
+ await apiRoleLists();
113
+ if ($Prop.actionType === "upd" && $Prop.rowData.id) {
114
+ $Data.formData = Object.assign({}, $Prop.rowData);
115
+ }
116
+ }
117
+
118
+ async function apiRoleLists(): Promise<void> {
119
+ try {
120
+ const result = await $Http.post(
121
+ "/addon/admin/role/all",
122
+ {},
123
+ {
124
+ dropValues: [""]
125
+ }
126
+ );
127
+ $Data.allRoleLists = result.data || [];
128
+ } catch (error) {
129
+ MessagePlugin.error("加载角色列表失败");
130
+ }
131
+ }
117
132
 
118
- onShow() {
119
- setTimeout(() => {
120
- $Data.visible = $Prop.modelValue;
121
- }, 100);
122
- },
133
+ async function onSubmit(context?: PageDialogEventContext): Promise<void> {
134
+ try {
135
+ const valid = await $From.form.validate();
136
+ if (!valid) return;
123
137
 
124
- onClose() {
125
- $Data.visible = false;
126
- setTimeout(() => {
127
- $Emit("update:modelValue", false);
128
- }, 300);
129
- },
138
+ $Data.submitting = true;
139
+ const formData = ($Prop.actionType === "add" ? fieldClear($Data.formData, { omitKeys: ["id", "state"] }) : fieldClear($Data.formData, { omitKeys: ["password"] })) as Record<string, unknown>;
130
140
 
131
- async apiRoleLists() {
132
- try {
133
- const result = await $Http.post(
134
- "/addon/admin/role/all",
135
- {},
136
- {
137
- dropValues: [""]
138
- }
139
- );
140
- $Data.allRoleLists = result.data || [];
141
- } catch (error) {
142
- MessagePlugin.error("加载角色列表失败");
141
+ const password = typeof formData["password"] === "string" ? String(formData["password"]) : "";
142
+ if ($Prop.actionType === "add" && password) {
143
+ formData["password"] = await hashPassword(password);
143
144
  }
144
- },
145
-
146
- async onSubmit() {
147
- try {
148
- const valid = await $From.form.validate();
149
- if (!valid) return;
150
145
 
151
- $Data.submitting = true;
152
- const formData = $Prop.actionType === "add" ? fieldClear($Data.formData, { omitKeys: ["id", "state"] }) : fieldClear($Data.formData, { omitKeys: ["password"] });
146
+ const result = await $Http.post($Prop.actionType === "upd" ? "/addon/admin/admin/upd" : "/addon/admin/admin/ins", formData);
153
147
 
154
- // 添加管理员时,对密码进行 SHA-256 加密
155
- if ($Prop.actionType === "add" && formData.password) {
156
- formData.password = await hashPassword(formData.password);
157
- }
158
-
159
- const result = await $Http.post($Prop.actionType === "upd" ? "/addon/admin/admin/upd" : "/addon/admin/admin/ins", formData);
160
-
161
- MessagePlugin.success(result.msg);
162
- $Emit("success");
163
- $Method.onClose();
164
- } catch (error) {
165
- MessagePlugin.error(error.msg || "提交失败");
166
- } finally {
167
- $Data.submitting = false;
148
+ MessagePlugin.success(result.msg);
149
+ $Emit("success");
150
+ if (context && typeof context.close === "function") {
151
+ context.close();
168
152
  }
153
+ } catch (error) {
154
+ MessagePlugin.error((error as { msg?: string }).msg || "提交失败");
155
+ } finally {
156
+ $Data.submitting = false;
169
157
  }
170
- };
158
+ }
171
159
 
172
- $Method.initData();
160
+ initData();
173
161
  </script>
174
162
 
175
163
  <style scoped lang="scss">
@@ -1,7 +1,7 @@
1
1
  <template>
2
- <PagedTableDetailPage class="page-admin" :columns="$Data.columns" :endpoints="$Data.endpoints">
2
+ <PagedTableDetail class="page-admin" :columns="$Data.columns" :endpoints="$Data.endpoints">
3
3
  <template #toolLeft>
4
- <TButton theme="primary" @click="$Method.onAdd">
4
+ <TButton theme="primary" @click="onAdd">
5
5
  <template #icon>
6
6
  <ILucidePlus />
7
7
  </template>
@@ -9,7 +9,7 @@
9
9
  </template>
10
10
 
11
11
  <template #toolRight="scope">
12
- <TButton shape="circle" @click="$Method.onReload(scope.reload)">
12
+ <TButton shape="circle" @click="onReload(scope.reload)">
13
13
  <template #icon>
14
14
  <ILucideRotateCw />
15
15
  </template>
@@ -23,7 +23,7 @@
23
23
  </template>
24
24
 
25
25
  <template #operation="{ row, deleteRow }">
26
- <TDropdown trigger="click" placement="bottom-right" @click="$Method.onDropdownAction($event, row, deleteRow)">
26
+ <TDropdown trigger="click" placement="bottom-right" @click="onDropdownAction($event, row, deleteRow)">
27
27
  <TButton theme="primary" size="small">
28
28
  操作
29
29
  <template #suffix> <ILucideChevronDown /></template>
@@ -42,9 +42,9 @@
42
42
  </template>
43
43
 
44
44
  <template #dialogs="scope">
45
- <EditDialog v-if="$Data.editVisible" v-model="$Data.editVisible" :action-type="$Data.actionType" :row-data="$Data.rowData" @success="$Method.onDialogSuccess(scope.reload)" />
45
+ <EditDialog v-if="$Data.editVisible" v-model="$Data.editVisible" :action-type="$Data.actionType" :row-data="$Data.rowData" @success="onDialogSuccess(scope.reload)" />
46
46
  </template>
47
- </PagedTableDetailPage>
47
+ </PagedTableDetail>
48
48
  </template>
49
49
 
50
50
  <script setup lang="ts">
@@ -55,7 +55,7 @@ import ILucidePencil from "~icons/lucide/pencil";
55
55
  import ILucideTrash2 from "~icons/lucide/trash-2";
56
56
  import ILucideChevronDown from "~icons/lucide/chevron-down";
57
57
  import EditDialog from "./components/edit.vue";
58
- import PagedTableDetailPage from "@/components/PagedTableDetailPage.vue";
58
+ import PagedTableDetail from "@/components/pagedTableDetail.vue";
59
59
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
60
60
 
61
61
  // 响应式数据
@@ -87,37 +87,36 @@ const $Data = $ref({
87
87
  rowData: {}
88
88
  });
89
89
 
90
- // 方法
91
- const $Method = {
92
- onAdd() {
93
- $Method.onAction("add", {});
94
- },
90
+ function onAdd(): void {
91
+ onAction("add", {});
92
+ }
95
93
 
96
- onReload(reload) {
97
- reload({ keepSelection: true });
98
- },
94
+ function onReload(reload: (options: { keepSelection?: boolean }) => void): void {
95
+ reload({ keepSelection: true });
96
+ }
99
97
 
100
- onDialogSuccess(reload) {
101
- reload({ keepSelection: true });
102
- },
98
+ function onDialogSuccess(reload: (options: { keepSelection?: boolean }) => void): void {
99
+ reload({ keepSelection: true });
100
+ }
103
101
 
104
- onAction(command, rowData) {
105
- $Data.actionType = command;
106
- $Data.rowData = rowData;
107
- if (command === "add" || command === "upd") {
108
- $Data.editVisible = true;
109
- }
110
- },
102
+ function onAction(command: string, rowData: Record<string, unknown>): void {
103
+ $Data.actionType = command;
104
+ $Data.rowData = rowData;
105
+ if (command === "add" || command === "upd") {
106
+ $Data.editVisible = true;
107
+ }
108
+ }
111
109
 
112
- onDropdownAction(data, rowData, deleteRow) {
113
- const cmd = data && data.value ? String(data.value) : "";
114
- if (cmd === "del") {
115
- deleteRow(rowData);
116
- return;
117
- }
118
- $Method.onAction(cmd, rowData);
110
+ function onDropdownAction(data: unknown, rowData: Record<string, unknown>, deleteRow: (row: Record<string, unknown>) => void): void {
111
+ const record = data as Record<string, unknown>;
112
+ const rawValue = record && record["value"] ? record["value"] : "";
113
+ const cmd = rawValue ? String(rawValue) : "";
114
+ if (cmd === "del") {
115
+ deleteRow(rowData);
116
+ return;
119
117
  }
120
- };
118
+ onAction(cmd, rowData);
119
+ }
121
120
  </script>
122
121
 
123
122
  <style scoped lang="scss">
@@ -2,7 +2,7 @@
2
2
  <div class="page-api page-table">
3
3
  <div class="main-tool">
4
4
  <div class="left">
5
- <TInput v-model="$Data.searchKeyword" placeholder="搜索接口名称或路径" clearable style="width: 300px" @enter="$Method.handleSearch" @clear="$Method.handleSearch">
5
+ <TInput v-model="$Data.searchKeyword" placeholder="搜索接口名称或路径" clearable style="width: 300px" @enter="handleSearch" @clear="handleSearch">
6
6
  <template #suffix-icon>
7
7
  <ILucideSearch />
8
8
  </template>
@@ -10,7 +10,7 @@
10
10
  <span style="margin-left: 16px; color: var(--text-secondary); font-size: 13px">共 {{ $Data.allData.length }} 个接口</span>
11
11
  </div>
12
12
  <div class="right">
13
- <TButton shape="circle" @click="$Method.handleRefresh">
13
+ <TButton shape="circle" @click="handleRefresh">
14
14
  <template #icon>
15
15
  <ILucideRotateCw />
16
16
  </template>
@@ -20,7 +20,7 @@
20
20
 
21
21
  <div class="main-content">
22
22
  <div class="main-table">
23
- <TTable :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" row-key="id" height="calc(100vh - var(--search-height) - var(--layout-gap) * 2)" active-row-type="single" @active-change="$Method.onActiveChange">
23
+ <TTable :data="$Data.tableData" :columns="$Data.columns" :loading="$Data.loading" :active-row-keys="$Data.activeRowKeys" row-key="id" height="calc(100vh - var(--search-height) - var(--layout-gap) * 2)" active-row-type="single" @active-change="onActiveChange">
24
24
  <template #method="{ row }">
25
25
  <TTag v-if="row.method === 'GET'" shape="round" theme="success" variant="light-outline">GET</TTag>
26
26
  <TTag v-else-if="row.method === 'POST'" shape="round" theme="primary" variant="light-outline">POST</TTag>
@@ -62,7 +62,7 @@
62
62
  import { Button as TButton, Table as TTable, Tag as TTag, Input as TInput, MessagePlugin } from "tdesign-vue-next";
63
63
  import ILucideRotateCw from "~icons/lucide/rotate-cw";
64
64
  import ILucideSearch from "~icons/lucide/search";
65
- import DetailPanel from "@/components/DetailPanel.vue";
65
+ import DetailPanel from "@/components/detailPanel.vue";
66
66
  import { $Http } from "@/plugins/http";
67
67
  import { withDefaultColumns } from "befly-shared/utils/withDefaultColumns";
68
68
 
@@ -83,72 +83,62 @@ const $Data = $ref({
83
83
  activeRowKeys: []
84
84
  });
85
85
 
86
- // 方法
87
- const $Method = {
88
- async initData() {
89
- await $Method.loadApiAll();
90
- },
86
+ async function initData(): Promise<void> {
87
+ await loadApiAll();
88
+ }
91
89
 
92
- // 加载全部接口
93
- async loadApiAll() {
94
- $Data.loading = true;
95
- try {
96
- const res = await $Http.post(
97
- "/addon/admin/api/all",
98
- {},
99
- {
100
- dropValues: [""]
101
- }
102
- );
103
- const list = res.data?.lists || [];
104
- $Data.allData = list;
105
- $Data.tableData = list;
106
-
107
- // 自动高亮第一行
108
- if ($Data.tableData.length > 0) {
109
- $Data.currentRow = $Data.tableData[0];
110
- $Data.activeRowKeys = [$Data.tableData[0].id];
111
- } else {
112
- $Data.currentRow = null;
113
- $Data.activeRowKeys = [];
90
+ async function loadApiAll(): Promise<void> {
91
+ $Data.loading = true;
92
+ try {
93
+ const res = await $Http.post(
94
+ "/addon/admin/api/all",
95
+ {},
96
+ {
97
+ dropValues: [""]
114
98
  }
115
- } catch (error) {
116
- MessagePlugin.error("加载数据失败");
117
- } finally {
118
- $Data.loading = false;
99
+ );
100
+ const list = res.data?.lists || [];
101
+ $Data.allData = list;
102
+ $Data.tableData = list;
103
+
104
+ if ($Data.tableData.length > 0) {
105
+ $Data.currentRow = $Data.tableData[0];
106
+ $Data.activeRowKeys = [$Data.tableData[0].id];
107
+ } else {
108
+ $Data.currentRow = null;
109
+ $Data.activeRowKeys = [];
119
110
  }
120
- },
111
+ } catch (error) {
112
+ MessagePlugin.error("加载数据失败");
113
+ } finally {
114
+ $Data.loading = false;
115
+ }
116
+ }
121
117
 
122
- // 刷新
123
- handleRefresh() {
124
- $Method.loadApiAll();
125
- },
118
+ function handleRefresh(): void {
119
+ loadApiAll();
120
+ }
126
121
 
127
- // 搜索
128
- handleSearch() {
129
- if (!$Data.searchKeyword) {
130
- $Data.tableData = $Data.allData;
131
- return;
132
- }
133
- const keyword = $Data.searchKeyword.toLowerCase();
134
- $Data.tableData = $Data.allData.filter((item) => item.name?.toLowerCase().includes(keyword) || item.path?.toLowerCase().includes(keyword));
135
- },
122
+ function handleSearch(): void {
123
+ if (!$Data.searchKeyword) {
124
+ $Data.tableData = $Data.allData;
125
+ return;
126
+ }
127
+ const keyword = String($Data.searchKeyword).toLowerCase();
128
+ $Data.tableData = $Data.allData.filter((item) => item.name?.toLowerCase().includes(keyword) || item.path?.toLowerCase().includes(keyword));
129
+ }
136
130
 
137
- // 高亮行变化
138
- onActiveChange(value, context) {
139
- // 禁止取消高亮:如果新值为空,保持当前选中
140
- if (value.length === 0 && $Data.activeRowKeys.length > 0) {
141
- return;
142
- }
143
- $Data.activeRowKeys = value;
144
- // 更新当前高亮的行数据
145
- if (context.activeRowList && context.activeRowList.length > 0) {
146
- $Data.currentRow = context.activeRowList[0].row;
147
- }
131
+ function onActiveChange(value: unknown[], context: { activeRowList?: Array<{ row: unknown }> }): void {
132
+ if (value.length === 0 && $Data.activeRowKeys.length > 0) {
133
+ return;
134
+ }
135
+ $Data.activeRowKeys = value;
136
+ if (context.activeRowList && context.activeRowList.length > 0) {
137
+ $Data.currentRow = context.activeRowList[0].row as never;
148
138
  }
149
- };
139
+ }
150
140
 
151
- $Method.initData();
141
+ initData();
152
142
  </script>
153
143
 
154
144
  <style scoped lang="scss">