@befly-addon/admin 1.2.1 → 1.2.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.
Files changed (36) hide show
  1. package/adminViews/403_1/index.vue +75 -0
  2. package/adminViews/config/dict/components/edit.vue +109 -0
  3. package/adminViews/config/dict/index.vue +266 -0
  4. package/adminViews/config/dictType/components/edit.vue +100 -0
  5. package/adminViews/config/dictType/index.vue +244 -0
  6. package/adminViews/config/index.vue +12 -0
  7. package/adminViews/config/system/components/edit.vue +171 -0
  8. package/adminViews/config/system/index.vue +286 -0
  9. package/adminViews/index/components/addonList.vue +132 -0
  10. package/adminViews/index/components/environmentInfo.vue +100 -0
  11. package/adminViews/index/components/operationLogs.vue +112 -0
  12. package/adminViews/index/components/performanceMetrics.vue +145 -0
  13. package/adminViews/index/components/quickActions.vue +30 -0
  14. package/adminViews/index/components/serviceStatus.vue +192 -0
  15. package/adminViews/index/components/systemNotifications.vue +137 -0
  16. package/adminViews/index/components/systemOverview.vue +190 -0
  17. package/adminViews/index/components/systemResources.vue +111 -0
  18. package/adminViews/index/components/userInfo.vue +204 -0
  19. package/adminViews/index/index.vue +74 -0
  20. package/adminViews/log/email/index.vue +292 -0
  21. package/adminViews/log/index.vue +12 -0
  22. package/adminViews/log/login/index.vue +187 -0
  23. package/adminViews/log/operate/index.vue +249 -0
  24. package/adminViews/login_1/index.vue +415 -0
  25. package/adminViews/people/admin/components/edit.vue +168 -0
  26. package/adminViews/people/admin/index.vue +240 -0
  27. package/adminViews/people/index.vue +12 -0
  28. package/adminViews/permission/api/index.vue +149 -0
  29. package/adminViews/permission/index.vue +12 -0
  30. package/adminViews/permission/menu/index.vue +130 -0
  31. package/adminViews/permission/role/components/api.vue +361 -0
  32. package/adminViews/permission/role/components/edit.vue +142 -0
  33. package/adminViews/permission/role/components/menu.vue +118 -0
  34. package/adminViews/permission/role/index.vue +263 -0
  35. package/package.json +12 -10
  36. package/tsconfig.json +15 -0
@@ -0,0 +1,244 @@
1
+ <template>
2
+ <div class="page-dict-type page-table">
3
+ <div class="main-tool">
4
+ <div class="left">
5
+ <TButton theme="primary" @click="$Method.onAction('add', {})">
6
+ <template #icon>
7
+ <ILucidePlus />
8
+ </template>
9
+ </TButton>
10
+ </div>
11
+ <div class="right">
12
+ <TInput v-model="$Data.searchKeyword" placeholder="搜索类型名称" clearable @enter="$Method.handleSearch" @clear="$Method.handleSearch">
13
+ <template #suffix-icon>
14
+ <ILucideSearch />
15
+ </template>
16
+ </TInput>
17
+ <TButton shape="circle" @click="$Method.handleRefresh">
18
+ <template #icon>
19
+ <ILucideRotateCw />
20
+ </template>
21
+ </TButton>
22
+ </div>
23
+ </div>
24
+ <div class="main-content">
25
+ <div class="main-table">
26
+ <TTable
27
+ :data="$Data.tableData"
28
+ :columns="$Data.columns"
29
+ :loading="$Data.loading"
30
+ :active-row-keys="$Data.activeRowKeys"
31
+ row-key="id"
32
+ height="calc(100vh - var(--search-height) - var(--pagination-height) - var(--layout-gap) * 4)"
33
+ active-row-type="single"
34
+ @active-change="$Method.onActiveChange"
35
+ >
36
+ <template #operation="{ row }">
37
+ <TDropdown trigger="click" placement="bottom-right" @click="(data) => $Method.onAction(data.value, row)">
38
+ <TButton theme="primary" size="small">
39
+ 操作
40
+ <template #suffix> <ILucideChevronDown /></template>
41
+ </TButton>
42
+ <TDropdownMenu slot="dropdown">
43
+ <TDropdownItem value="upd">
44
+ <ILucidePencil />
45
+ 编辑
46
+ </TDropdownItem>
47
+ <TDropdownItem value="del" :divider="true">
48
+ <ILucideTrash2 style="width: 14px; height: 14px; margin-right: 6px" />
49
+ 删除
50
+ </TDropdownItem>
51
+ </TDropdownMenu>
52
+ </TDropdown>
53
+ </template>
54
+ </TTable>
55
+ </div>
56
+
57
+ <div class="main-detail">
58
+ <DetailPanel :data="$Data.currentRow" :fields="$Data.columns" />
59
+ </div>
60
+ </div>
61
+
62
+ <div class="main-page">
63
+ <TPagination :current-page="$Data.pagerConfig.currentPage" :page-size="$Data.pagerConfig.limit" :total="$Data.pagerConfig.total" @current-change="$Method.onPageChange" @page-size-change="$Method.handleSizeChange" />
64
+ </div>
65
+
66
+ <EditDialog v-if="$Data.editVisible" v-model="$Data.editVisible" :action-type="$Data.actionType" :row-data="$Data.rowData" @success="$Method.apiDictTypeList" />
67
+ </div>
68
+ </template>
69
+
70
+ <script setup>
71
+ import { onMounted } from "vue";
72
+
73
+ import { Button as TButton, Table as TTable, Input as TInput, Dropdown as TDropdown, DropdownMenu as TDropdownMenu, DropdownItem as TDropdownItem, Pagination as TPagination, MessagePlugin, DialogPlugin } from "tdesign-vue-next";
74
+ import ILucidePlus from "~icons/lucide/plus";
75
+ import ILucideRotateCw from "~icons/lucide/rotate-cw";
76
+ import ILucideSearch from "~icons/lucide/search";
77
+ import ILucidePencil from "~icons/lucide/pencil";
78
+ import ILucideTrash2 from "~icons/lucide/trash-2";
79
+ import ILucideChevronDown from "~icons/lucide/chevron-down";
80
+ import EditDialog from "./components/edit.vue";
81
+ import DetailPanel from "@/components/DetailPanel.vue";
82
+ import { $Http } from "@/plugins/http";
83
+ import { withDefaultColumns } from "befly-vite/utils/withDefaultColumns";
84
+
85
+ definePage({
86
+ meta: {
87
+ title: "字典类型",
88
+ order: 1
89
+ }
90
+ });
91
+
92
+ const $Data = $ref({
93
+ tableData: [],
94
+ loading: false,
95
+ activeRowKeys: [],
96
+ currentRow: null,
97
+ searchKeyword: "",
98
+ columns: withDefaultColumns([
99
+ { colKey: "id", title: "ID" },
100
+ { colKey: "code", title: "类型代码" },
101
+ { colKey: "name", title: "类型名称" },
102
+ { colKey: "description", title: "描述" },
103
+ { colKey: "sort", title: "排序" },
104
+ { colKey: "operation", title: "操作" }
105
+ ]),
106
+ pagerConfig: {
107
+ currentPage: 1,
108
+ limit: 30,
109
+ total: 0,
110
+ align: "right",
111
+ layout: "total, prev, pager, next, jumper"
112
+ },
113
+ editVisible: false,
114
+ actionType: "add",
115
+ rowData: {}
116
+ });
117
+
118
+ const $Method = {
119
+ async initData() {
120
+ await $Method.apiDictTypeList();
121
+ },
122
+ async apiDictTypeList() {
123
+ $Data.loading = true;
124
+ try {
125
+ const res = await $Http("/addon/admin/dictType/list", {
126
+ page: $Data.pagerConfig.currentPage,
127
+ limit: $Data.pagerConfig.limit,
128
+ keyword: $Data.searchKeyword
129
+ });
130
+ $Data.tableData = res.data.lists || [];
131
+ $Data.pagerConfig.total = res.data.total || 0;
132
+
133
+ if ($Data.tableData.length > 0) {
134
+ $Data.currentRow = $Data.tableData[0];
135
+ $Data.activeRowKeys = [$Data.tableData[0].id];
136
+ } else {
137
+ $Data.currentRow = null;
138
+ $Data.activeRowKeys = [];
139
+ }
140
+ } catch (error) {
141
+ MessagePlugin.error("加载数据失败");
142
+ } finally {
143
+ $Data.loading = false;
144
+ }
145
+ },
146
+ async apiDictTypeDel(row) {
147
+ let dialog = null;
148
+ let destroyed = false;
149
+
150
+ const destroy = () => {
151
+ if (destroyed) return;
152
+ destroyed = true;
153
+ if (dialog && typeof dialog.destroy === "function") {
154
+ dialog.destroy();
155
+ }
156
+ };
157
+
158
+ dialog = DialogPlugin.confirm({
159
+ header: "确认删除",
160
+ body: `确认删除类型“${row.name}”吗?`,
161
+ status: "warning",
162
+ confirmBtn: "删除",
163
+ cancelBtn: "取消",
164
+ onConfirm: async () => {
165
+ if (dialog && typeof dialog.setConfirmLoading === "function") {
166
+ dialog.setConfirmLoading(true);
167
+ }
168
+
169
+ try {
170
+ await $Http("/addon/admin/dictType/del", { id: row.id });
171
+ MessagePlugin.success("删除成功");
172
+ destroy();
173
+ await $Method.apiDictTypeList();
174
+ } catch (error) {
175
+ MessagePlugin.error("删除失败");
176
+ } finally {
177
+ if (dialog && typeof dialog.setConfirmLoading === "function") {
178
+ dialog.setConfirmLoading(false);
179
+ }
180
+ }
181
+ },
182
+ onClose: () => {
183
+ destroy();
184
+ }
185
+ });
186
+ },
187
+ handleSearch() {
188
+ $Data.pagerConfig.currentPage = 1;
189
+ $Method.apiDictTypeList();
190
+ },
191
+ handleRefresh() {
192
+ $Data.searchKeyword = "";
193
+ $Data.pagerConfig.currentPage = 1;
194
+ $Method.apiDictTypeList();
195
+ },
196
+ onPageChange({ currentPage }) {
197
+ $Data.pagerConfig.currentPage = currentPage;
198
+ $Method.apiDictTypeList();
199
+ },
200
+ handleSizeChange({ pageSize }) {
201
+ $Data.pagerConfig.limit = pageSize;
202
+ $Data.pagerConfig.currentPage = 1;
203
+ $Method.apiDictTypeList();
204
+ },
205
+ onActiveChange(value, context) {
206
+ if (value.length === 0 && $Data.activeRowKeys.length > 0) {
207
+ return;
208
+ }
209
+ $Data.activeRowKeys = value;
210
+ $Data.currentRow = context.currentRowData;
211
+ },
212
+ onAction(type, row) {
213
+ if (type === "add") {
214
+ $Data.actionType = "add";
215
+ $Data.rowData = {};
216
+ $Data.editVisible = true;
217
+ } else if (type === "upd") {
218
+ $Data.actionType = "upd";
219
+ $Data.rowData = { ...row };
220
+ $Data.editVisible = true;
221
+ } else if (type === "del") {
222
+ $Method.apiDictTypeDel(row);
223
+ }
224
+ }
225
+ };
226
+
227
+ onMounted(() => {
228
+ $Method.initData();
229
+ });
230
+ </script>
231
+
232
+ <style scoped lang="scss">
233
+ .page-dict-type {
234
+ .main-tool .right {
235
+ display: flex;
236
+ gap: 8px;
237
+ align-items: center;
238
+
239
+ .t-input {
240
+ width: 240px;
241
+ }
242
+ }
243
+ }
244
+ </style>
@@ -0,0 +1,12 @@
1
+ <template>
2
+ <RouterView />
3
+ </template>
4
+
5
+ <script setup>
6
+ definePage({
7
+ meta: {
8
+ title: "配置管理",
9
+ order: 30
10
+ }
11
+ });
12
+ </script>
@@ -0,0 +1,171 @@
1
+ <template>
2
+ <TDialog v-model:visible="$Data.visible" :title="$Prop.actionType === 'upd' ? '编辑配置' : '添加配置'" width="600px" :append-to-body="true" :show-footer="true" :esc-closable="false" top="10vh" @close="$Method.onClose">
3
+ <TForm :model="$Data.formData" label-width="120px" label-position="left" :rules="$Data2.formRules" :ref="(el) => ($Form.form = el)">
4
+ <TFormItem label="配置名称" prop="name">
5
+ <TInput v-model="$Data.formData.name" placeholder="请输入配置名称" :disabled="$Data.isSystem" />
6
+ </TFormItem>
7
+ <TFormItem label="配置代码" prop="code">
8
+ <TInput v-model="$Data.formData.code" placeholder="请输入配置代码,如:site_name" :disabled="$Prop.actionType === 'upd'" />
9
+ </TFormItem>
10
+ <TFormItem label="配置值" prop="value">
11
+ <TTextarea v-if="$Data.formData.valueType === 'json' || $Data.formData.valueType === 'text'" v-model="$Data.formData.value" placeholder="请输入配置值" :autosize="{ minRows: 3, maxRows: 8 }" />
12
+ <TInput v-else v-model="$Data.formData.value" placeholder="请输入配置值" />
13
+ </TFormItem>
14
+ <TFormItem label="值类型" prop="valueType">
15
+ <TSelect v-model="$Data.formData.valueType" :disabled="$Data.isSystem">
16
+ <TOption label="字符串" value="string" />
17
+ <TOption label="数字" value="number" />
18
+ <TOption label="布尔" value="boolean" />
19
+ <TOption label="JSON" value="json" />
20
+ </TSelect>
21
+ </TFormItem>
22
+ <TFormItem label="配置分组" prop="group">
23
+ <TSelect v-model="$Data.formData.group" placeholder="请选择分组" clearable :disabled="$Data.isSystem">
24
+ <TOption v-for="item in $Data2.groupOptions" :key="item" :label="item" :value="item" />
25
+ </TSelect>
26
+ </TFormItem>
27
+ <TFormItem label="排序" prop="sort">
28
+ <TInputNumber v-model="$Data.formData.sort" :min="0" :max="9999" :disabled="$Data.isSystem" />
29
+ </TFormItem>
30
+ <TFormItem label="描述说明" prop="description">
31
+ <TTextarea v-model="$Data.formData.description" placeholder="请输入描述说明" :autosize="{ minRows: 2, maxRows: 4 }" :disabled="$Data.isSystem" />
32
+ </TFormItem>
33
+ <TFormItem v-if="$Prop.actionType === 'upd' && !$Data.isSystem" label="状态" prop="state">
34
+ <TRadioGroup v-model="$Data.formData.state">
35
+ <TRadio :value="1">正常</TRadio>
36
+ <TRadio :value="2">禁用</TRadio>
37
+ </TRadioGroup>
38
+ </TFormItem>
39
+ </TForm>
40
+ <template #footer>
41
+ <TButton @click="$Method.onClose">取消</TButton>
42
+ <TButton theme="primary" :loading="$Data.submitting" @click="$Method.onSubmit">确定</TButton>
43
+ </template>
44
+ </TDialog>
45
+ </template>
46
+
47
+ <script setup>
48
+ import { Dialog as TDialog, Form as TForm, FormItem as TFormItem, Input as TInput, Textarea as TTextarea, InputNumber as TInputNumber, Select as TSelect, Option as TOption, RadioGroup as TRadioGroup, Radio as TRadio, Button as TButton, MessagePlugin } from "tdesign-vue-next";
49
+ import { $Http } from "@/plugins/http";
50
+
51
+ const $Prop = defineProps({
52
+ modelValue: {
53
+ type: Boolean,
54
+ default: false
55
+ },
56
+ actionType: {
57
+ type: String,
58
+ default: "add"
59
+ },
60
+ rowData: {
61
+ type: Object,
62
+ default: () => ({})
63
+ }
64
+ });
65
+
66
+ const $Emit = defineEmits(["update:modelValue", "success"]);
67
+
68
+ // 表单引用
69
+ const $Form = $shallowRef({
70
+ form: null
71
+ });
72
+
73
+ const $Data = $ref({
74
+ visible: false,
75
+ submitting: false,
76
+ isSystem: false,
77
+ formData: {
78
+ id: 0,
79
+ name: "",
80
+ code: "",
81
+ value: "",
82
+ valueType: "string",
83
+ group: "",
84
+ sort: 0,
85
+ description: "",
86
+ state: 1
87
+ }
88
+ });
89
+
90
+ const $Data2 = $shallowRef({
91
+ formRules: {
92
+ name: [{ required: true, message: "请输入配置名称", trigger: "blur" }],
93
+ code: [
94
+ { required: true, message: "请输入配置代码", trigger: "blur" },
95
+ { pattern: /^[a-zA-Z0-9_]+$/, message: "配置代码只能包含字母、数字和下划线", trigger: "blur" }
96
+ ],
97
+ value: [{ required: true, message: "请输入配置值", trigger: "blur" }],
98
+ valueType: [{ required: true, message: "请选择值类型", trigger: "change" }]
99
+ },
100
+ groupOptions: ["基础配置", "邮件配置", "存储配置", "安全配置", "其他"]
101
+ });
102
+
103
+ // 方法集合
104
+ const $Method = {
105
+ async initData() {
106
+ $Method.onShow();
107
+ },
108
+
109
+ onShow() {
110
+ $Data.visible = true;
111
+ if ($Prop.actionType === "upd" && $Prop.rowData) {
112
+ $Data.formData.id = $Prop.rowData.id || 0;
113
+ $Data.formData.name = $Prop.rowData.name || "";
114
+ $Data.formData.code = $Prop.rowData.code || "";
115
+ $Data.formData.value = $Prop.rowData.value || "";
116
+ $Data.formData.valueType = $Prop.rowData.valueType || "string";
117
+ $Data.formData.group = $Prop.rowData.group || "";
118
+ $Data.formData.sort = $Prop.rowData.sort || 0;
119
+ $Data.formData.description = $Prop.rowData.description || "";
120
+ $Data.formData.state = $Prop.rowData.state || 1;
121
+ $Data.isSystem = $Prop.rowData.isSystem === 1;
122
+ } else {
123
+ $Data.formData = {
124
+ id: 0,
125
+ name: "",
126
+ code: "",
127
+ value: "",
128
+ valueType: "string",
129
+ group: "",
130
+ sort: 0,
131
+ description: "",
132
+ state: 1
133
+ };
134
+ $Data.isSystem = false;
135
+ }
136
+ },
137
+
138
+ onClose() {
139
+ $Data.visible = false;
140
+ $Emit("update:modelValue", false);
141
+ },
142
+
143
+ async onSubmit() {
144
+ const valid = await $Form.form?.validate();
145
+ if (valid !== true) return;
146
+
147
+ $Data.submitting = true;
148
+ try {
149
+ const api = $Prop.actionType === "upd" ? "/addon/admin/sysConfig/upd" : "/addon/admin/sysConfig/ins";
150
+ const res = await $Http(api, $Data.formData);
151
+
152
+ if (res.code === 0) {
153
+ MessagePlugin.success($Prop.actionType === "upd" ? "编辑成功" : "添加成功");
154
+ $Emit("success");
155
+ $Method.onClose();
156
+ } else {
157
+ MessagePlugin.error(res.msg || "操作失败");
158
+ }
159
+ } catch (error) {
160
+ MessagePlugin.error("操作失败");
161
+ } finally {
162
+ $Data.submitting = false;
163
+ }
164
+ }
165
+ };
166
+
167
+ // 该组件由父组件 v-if 控制挂载/卸载,因此无需 watch:创建时初始化一次即可
168
+ $Method.initData();
169
+ </script>
170
+
171
+ <style scoped lang="scss"></style>