@befly-addon/admin 1.0.37 → 1.0.39

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 (57) hide show
  1. package/apis/admin/del.ts +1 -5
  2. package/apis/admin/ins.ts +2 -6
  3. package/apis/admin/list.ts +5 -0
  4. package/apis/admin/roleDetail.ts +1 -5
  5. package/apis/admin/roleSave.ts +1 -5
  6. package/apis/admin/upd.ts +1 -6
  7. package/apis/api/all.ts +1 -6
  8. package/apis/auth/login.ts +1 -5
  9. package/apis/auth/logout.ts +1 -5
  10. package/apis/auth/register.ts +1 -5
  11. package/apis/auth/sendSmsCode.ts +1 -5
  12. package/apis/dashboard/changelog.ts +1 -5
  13. package/apis/dashboard/configStatus.ts +1 -5
  14. package/apis/dashboard/environmentInfo.ts +1 -5
  15. package/apis/dashboard/performanceMetrics.ts +1 -5
  16. package/apis/dashboard/permissionStats.ts +1 -5
  17. package/apis/dashboard/serviceStatus.ts +1 -5
  18. package/apis/dashboard/systemInfo.ts +1 -5
  19. package/apis/dashboard/systemOverview.ts +1 -5
  20. package/apis/dashboard/systemResources.ts +1 -5
  21. package/apis/dict/all.ts +0 -3
  22. package/apis/menu/del.ts +1 -5
  23. package/apis/role/all.ts +18 -0
  24. package/apis/role/apiDetail.ts +1 -5
  25. package/apis/role/apiSave.ts +1 -5
  26. package/apis/role/del.ts +1 -5
  27. package/apis/role/detail.ts +1 -5
  28. package/apis/role/ins.ts +0 -3
  29. package/apis/role/list.ts +5 -0
  30. package/apis/role/menuDetail.ts +1 -5
  31. package/apis/role/menuSave.ts +1 -5
  32. package/apis/role/save.ts +1 -5
  33. package/package.json +5 -3
  34. package/styles/variables.scss +87 -0
  35. package/tables/admin.json +2 -8
  36. package/views/403/index.vue +20 -30
  37. package/views/admin/components/edit.vue +73 -48
  38. package/views/admin/index.vue +128 -48
  39. package/views/dict/index.vue +0 -2
  40. package/views/index/components/addonList.vue +20 -14
  41. package/views/index/components/environmentInfo.vue +6 -6
  42. package/views/index/components/operationLogs.vue +9 -9
  43. package/views/index/components/performanceMetrics.vue +22 -32
  44. package/views/index/components/serviceStatus.vue +14 -14
  45. package/views/index/components/systemNotifications.vue +21 -21
  46. package/views/index/components/systemOverview.vue +24 -24
  47. package/views/index/components/systemResources.vue +4 -4
  48. package/views/index/components/userInfo.vue +7 -7
  49. package/views/index/index.vue +0 -2
  50. package/views/login/components/emailLoginForm.vue +46 -46
  51. package/views/login/index_1.vue +158 -121
  52. package/views/role/components/api.vue +11 -9
  53. package/views/role/components/edit.vue +13 -2
  54. package/views/role/index.vue +0 -2
  55. package/utils/scanBeflyAddonViews.js +0 -43
  56. package/views/admin/components/role.vue +0 -138
  57. /package/apis/admin/{info.ts → detail.ts} +0 -0
@@ -1,41 +1,59 @@
1
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) => ($From.form = el)">
4
- <TFormItem label="用户名" prop="username">
5
- <TInput v-model="$Data.formData.username" placeholder="请输入用户名" :disabled="$Prop.actionType === 'upd'" />
6
- </TFormItem>
7
- <TFormItem label="邮箱" prop="email">
8
- <TInput v-model="$Data.formData.email" placeholder="请输入邮箱" />
9
- </TFormItem>
10
- <TFormItem v-if="$Prop.actionType === 'add'" label="密码" prop="password">
11
- <TInput v-model="$Data.formData.password" type="password" placeholder="请输入密码,至少6位" />
12
- </TFormItem>
13
- <TFormItem label="姓名" prop="name">
14
- <TInput v-model="$Data.formData.name" placeholder="请输入姓名" />
15
- </TFormItem>
16
- <TFormItem label="昵称" prop="nickname">
17
- <TInput v-model="$Data.formData.nickname" placeholder="请输入昵称" />
18
- </TFormItem>
19
- <TFormItem label="手机号" prop="phone">
20
- <TInput v-model="$Data.formData.phone" placeholder="请输入手机号" />
21
- </TFormItem>
22
- <TFormItem v-if="$Prop.actionType === 'upd'" label="状态" prop="state">
23
- <TRadioGroup v-model="$Data.formData.state">
24
- <TRadio :label="1">正常</TRadio>
25
- <TRadio :label="2">禁用</TRadio>
26
- </TRadioGroup>
27
- </TFormItem>
28
- </TForm>
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">
3
+ <div class="dialog-wrapper">
4
+ <TForm :model="$Data.formData" label-width="80px" label-position="left" label-align="left" :rules="$Data2.formRules" :ref="(el) => ($From.form = el)">
5
+ <TFormItem label="角色" prop="roleId">
6
+ <TSelect v-model="$Data.formData.roleId" :options="$Data.roleOptions" placeholder="请选择角色" />
7
+ </TFormItem>
8
+ <TFormItem label="用户名" prop="username">
9
+ <TInput v-model="$Data.formData.username" placeholder="请输入用户名" :disabled="$Prop.actionType === 'upd'" />
10
+ </TFormItem>
11
+ <TFormItem label="邮箱" prop="email">
12
+ <TInput v-model="$Data.formData.email" placeholder="请输入邮箱" />
13
+ </TFormItem>
14
+ <TFormItem v-if="$Prop.actionType === 'add'" label="密码" prop="password">
15
+ <TInput v-model="$Data.formData.password" type="password" placeholder="请输入密码,至少6位" />
16
+ </TFormItem>
17
+ <TFormItem label="昵称" prop="nickname">
18
+ <TInput v-model="$Data.formData.nickname" placeholder="请输入昵称" />
19
+ </TFormItem>
20
+ <TFormItem label="手机号" prop="phone">
21
+ <TInput v-model="$Data.formData.phone" placeholder="请输入手机号" />
22
+ </TFormItem>
23
+ <TFormItem v-if="$Prop.actionType === 'upd'" label="状态" prop="state">
24
+ <TRadioGroup v-model="$Data.formData.state">
25
+ <TRadio :label="1">正常</TRadio>
26
+ <TRadio :label="2">禁用</TRadio>
27
+ </TRadioGroup>
28
+ </TFormItem>
29
+ </TForm>
30
+ </div>
29
31
  <template #footer>
30
- <TButton @click="$Method.onClose">取消</TButton>
31
- <TButton theme="primary" @click="$Method.onSubmit">确定</TButton>
32
+ <div class="dialog-footer">
33
+ <t-space>
34
+ <TButton theme="default" @click="$Method.onClose">取消</TButton>
35
+ <TButton theme="primary" @click="$Method.onSubmit">确定</TButton>
36
+ </t-space>
37
+ </div>
32
38
  </template>
33
39
  </TDialog>
34
40
  </template>
35
41
 
36
42
  <script setup>
37
- import { Dialog as TDialog, Form as TForm, FormItem as TFormItem, Input as TInput, RadioGroup as TRadioGroup, Radio as TRadio, Button as TButton, MessagePlugin } from 'tdesign-vue-next';
43
+ import {
44
+ //
45
+ Dialog as TDialog,
46
+ Form as TForm,
47
+ FormItem as TFormItem,
48
+ Input as TInput,
49
+ Select as TSelect,
50
+ RadioGroup as TRadioGroup,
51
+ Radio as TRadio,
52
+ Button as TButton,
53
+ MessagePlugin
54
+ } from 'tdesign-vue-next';
38
55
  import { $Http } from '@/plugins/http';
56
+ import { fieldClear } from 'befly-util/fieldClear';
39
57
 
40
58
  const $Prop = defineProps({
41
59
  modelValue: {
@@ -61,6 +79,7 @@ const $From = $shallowRef({
61
79
 
62
80
  const $Data = $ref({
63
81
  visible: false,
82
+ roleOptions: [],
64
83
  formData: {
65
84
  id: 0,
66
85
  username: '',
@@ -69,6 +88,7 @@ const $Data = $ref({
69
88
  name: '',
70
89
  nickname: '',
71
90
  phone: '',
91
+ roleId: 0,
72
92
  state: 1
73
93
  }
74
94
  });
@@ -84,6 +104,7 @@ const $Data2 = $shallowRef({
84
104
  { required: true, message: '请输入密码', trigger: 'blur' },
85
105
  { min: 6, message: '密码至少6位', trigger: 'blur' }
86
106
  ],
107
+ roleId: [{ required: true, message: '请选择角色', trigger: 'change' }],
87
108
  name: [{ min: 2, max: 50, message: '姓名长度在 2 到 50 个字符', trigger: 'blur' }],
88
109
  nickname: [{ min: 2, max: 50, message: '昵称长度在 2 到 50 个字符', trigger: 'blur' }],
89
110
  phone: [{ pattern: /^1[3-9]\d{9}$/, message: '手机号格式不正确', trigger: 'blur' }]
@@ -94,15 +115,10 @@ const $Data2 = $shallowRef({
94
115
  const $Method = {
95
116
  async initData() {
96
117
  $Method.onShow();
118
+ await $Method.loadRoles();
97
119
  if ($Prop.actionType === 'upd' && $Prop.rowData.id) {
98
- // 编辑模式:复制数据
99
- $Data.formData.id = $Prop.rowData.id || 0;
100
- $Data.formData.username = $Prop.rowData.username || '';
101
- $Data.formData.email = $Prop.rowData.email || '';
102
- $Data.formData.name = $Prop.rowData.name || '';
103
- $Data.formData.nickname = $Prop.rowData.nickname || '';
104
- $Data.formData.phone = $Prop.rowData.phone || '';
105
- $Data.formData.state = $Prop.rowData.state ?? 1;
120
+ // 编辑模式:直接赋值
121
+ $Data.formData = { ...$Prop.rowData };
106
122
  }
107
123
  },
108
124
 
@@ -119,25 +135,34 @@ const $Method = {
119
135
  }, 300);
120
136
  },
121
137
 
138
+ async loadRoles() {
139
+ try {
140
+ const result = await $Http('/addon/admin/role/all');
141
+ $Data.roleOptions = result
142
+ .filter((role) => role.state === 1)
143
+ .map((role) => ({
144
+ label: role.name,
145
+ value: role.id
146
+ }));
147
+ } catch (error) {
148
+ MessagePlugin.error(error.msg || '加载角色列表失败');
149
+ }
150
+ },
151
+
122
152
  async onSubmit() {
123
153
  try {
124
154
  const valid = await $From.form.validate();
125
155
  if (!valid) return;
126
156
 
127
- const res = await $Http($Prop.actionType === 'upd' ? '/addon/admin/admin/upd' : '/addon/admin/admin/ins', $Data.formData);
157
+ const submitData = $Prop.actionType === 'add' ? fieldClear($Data.formData, { omitKeys: ['id', 'state'] }) : fieldClear($Data.formData, { omitKeys: ['password'] });
158
+
159
+ await $Http($Prop.actionType === 'upd' ? '/addon/admin/admin/upd' : '/addon/admin/admin/ins', submitData);
128
160
 
129
- MessagePlugin.info({
130
- message: $Prop.actionType === 'upd' ? '编辑成功' : '添加成功',
131
- status: 'success'
132
- });
161
+ MessagePlugin.success($Prop.actionType === 'upd' ? '编辑成功' : '添加成功');
133
162
  $Emit('success');
134
163
  $Method.onClose();
135
164
  } catch (error) {
136
- console.error('提交失败:', error);
137
- MessagePlugin.info({
138
- message: '提交失败',
139
- status: 'error'
140
- });
165
+ MessagePlugin.error(error.msg || '提交失败');
141
166
  }
142
167
  }
143
168
  };
@@ -6,53 +6,79 @@
6
6
  <template #icon>
7
7
  <ILucidePlus />
8
8
  </template>
9
- 添加管理员
10
9
  </TButton>
11
10
  </div>
12
11
  <div class="right">
13
- <TButton @click="$Method.handleRefresh">
12
+ <TButton shape="circle" @click="$Method.handleRefresh">
14
13
  <template #icon>
15
14
  <ILucideRotateCw />
16
15
  </template>
17
16
  </TButton>
18
17
  </div>
19
- <div class="right">
20
- <TButton @click="$Method.handleRefresh">
21
- <template #icon>
22
- <ILucideRotateCw />
18
+ </div>
19
+
20
+ <div class="main-content">
21
+ <div class="main-table">
22
+ <TTable :data="$Data.tableData" :columns="$Data.columns" row-key="id" :selected-row-keys="$Data.selectedRowKeys" active-row-type="single" :active-row-keys="$Data.activeRowKeys" @select-change="$Method.onSelectChange" @active-change="$Method.onActiveChange">
23
+ <template #state="{ row }">
24
+ <TTag v-if="row.state === 1" shape="round" theme="success" variant="light-outline">正常</TTag>
25
+ <TTag v-else-if="row.state === 2" shape="round" theme="warning" variant="light-outline">禁用</TTag>
26
+ <TTag v-else-if="row.state === 0" shape="round" theme="danger" variant="light-outline">删除</TTag>
23
27
  </template>
24
- 刷新
25
- </TButton>
28
+ <template #operation="{ row }">
29
+ <TDropdown trigger="click" placement="bottom-right" @click="(data) => $Method.onAction(data.value, row)">
30
+ <TButton theme="primary" size="small">操作</TButton>
31
+ <TDropdownMenu slot="dropdown">
32
+ <TDropdownItem value="upd">
33
+ <ILucidePencil />
34
+ 编辑
35
+ </TDropdownItem>
36
+ <TDropdownItem value="del" :divider="true">
37
+ <ILucideTrash2 />
38
+ 删除
39
+ </TDropdownItem>
40
+ </TDropdownMenu>
41
+ </TDropdown>
42
+ </template>
43
+ </TTable>
26
44
  </div>
27
- </div>
28
45
 
29
- <div class="main-table">
30
- <TTable :data="$Data.tableData" :columns="$Data.columns" header-cell-class-name="custom-table-cell-class" size="small" height="100%" row-key="id">
31
- <template #state="{ row }">
32
- <TTag v-if="row.state === 1" theme="success">正常</TTag>
33
- <TTag v-else-if="row.state === 2" theme="warning">禁用</TTag>
34
- <TTag v-else theme="danger">已删除</TTag>
35
- </template>
36
- <template #operation="{ row }">
37
- <TDropdown trigger="click" min-column-width="120" @click="(data) => $Method.onAction(data.value, row)">
38
- <TButton variant="text" size="small">操作</TButton>
39
- <TDropdownMenu slot="dropdown">
40
- <TDropdownItem value="role">
41
- <ILucideUser />
42
- 分配角色
43
- </TDropdownItem>
44
- <TDropdownItem value="upd">
45
- <ILucidePencil />
46
- 编辑
47
- </TDropdownItem>
48
- <TDropdownItem value="del" :divider="true">
49
- <ILucideTrash2 style="width: 14px; height: 14px; margin-right: 6px" />
50
- 删除
51
- </TDropdownItem>
52
- </TDropdownMenu>
53
- </TDropdown>
54
- </template>
55
- </TTable>
46
+ <div class="main-detail">
47
+ <div class="detail-content">
48
+ <div v-if="$Data.currentRow">
49
+ <div style="margin-bottom: 16px">
50
+ <div style="color: var(--text-secondary); margin-bottom: 4px">ID</div>
51
+ <div>{{ $Data.currentRow.id }}</div>
52
+ </div>
53
+ <div style="margin-bottom: 16px">
54
+ <div style="color: var(--text-secondary); margin-bottom: 4px">用户名</div>
55
+ <div>{{ $Data.currentRow.username }}</div>
56
+ </div>
57
+ <div style="margin-bottom: 16px">
58
+ <div style="color: var(--text-secondary); margin-bottom: 4px">邮箱</div>
59
+ <div>{{ $Data.currentRow.email }}</div>
60
+ </div>
61
+ <div style="margin-bottom: 16px">
62
+ <div style="color: var(--text-secondary); margin-bottom: 4px">昵称</div>
63
+ <div>{{ $Data.currentRow.nickname || '-' }}</div>
64
+ </div>
65
+ <div style="margin-bottom: 16px">
66
+ <div style="color: var(--text-secondary); margin-bottom: 4px">角色</div>
67
+ <div>{{ $Data.currentRow.roleCode || '-' }}</div>
68
+ </div>
69
+ <div style="margin-bottom: 16px">
70
+ <div style="color: var(--text-secondary); margin-bottom: 4px">状态</div>
71
+ <TTag v-if="$Data.currentRow.state === 1" shape="round" theme="success" variant="light-outline">正常</TTag>
72
+ <TTag v-else-if="$Data.currentRow.state === 2" shape="round" theme="warning" variant="light-outline">禁用</TTag>
73
+ <TTag v-else-if="$Data.currentRow.state === 0" shape="round" theme="danger" variant="light-outline">已删除</TTag>
74
+ </div>
75
+ </div>
76
+ <div v-else style="text-align: center; padding: 48px 0; color: var(--text-placeholder)">
77
+ <div style="font-size: 48px; margin-bottom: 8px">📋</div>
78
+ <div>暂无数据</div>
79
+ </div>
80
+ </div>
81
+ </div>
56
82
  </div>
57
83
 
58
84
  <div class="main-page">
@@ -61,9 +87,6 @@
61
87
 
62
88
  <!-- 编辑对话框组件 -->
63
89
  <EditDialog v-if="$Data.editVisible" v-model="$Data.editVisible" :action-type="$Data.actionType" :row-data="$Data.rowData" @success="$Method.apiAdminList" />
64
-
65
- <!-- 角色分配对话框组件 -->
66
- <RoleDialog v-if="$Data.roleVisible" v-model="$Data.roleVisible" :row-data="$Data.rowData" @success="$Method.apiAdminList" />
67
90
  </div>
68
91
  </template>
69
92
 
@@ -71,24 +94,29 @@
71
94
  import { Button as TButton, Table as TTable, Tag as TTag, Dropdown as TDropdown, DropdownMenu as TDropdownMenu, DropdownItem as TDropdownItem, Pagination as TPagination, MessagePlugin, DialogPlugin } from 'tdesign-vue-next';
72
95
  import ILucidePlus from '~icons/lucide/plus';
73
96
  import ILucideRotateCw from '~icons/lucide/rotate-cw';
74
- import ILucideUser from '~icons/lucide/user';
75
97
  import ILucidePencil from '~icons/lucide/pencil';
76
98
  import ILucideTrash2 from '~icons/lucide/trash-2';
77
99
  import EditDialog from './components/edit.vue';
78
- import RoleDialog from './components/role.vue';
79
100
  import { $Http } from '@/plugins/http';
80
101
 
81
102
  // 响应式数据
82
103
  const $Data = $ref({
83
104
  tableData: [],
84
105
  columns: [
85
- { colKey: 'index', title: '序号', width: 60, align: 'center' },
86
- { colKey: 'username', title: '用户名' },
106
+ {
107
+ colKey: 'row-select',
108
+ type: 'single',
109
+ width: 50,
110
+ fixed: 'left',
111
+ checkProps: { allowUncheck: true }
112
+ },
113
+ { colKey: 'username', title: '用户名', width: 150, fixed: 'left' },
114
+ { colKey: 'id', title: '序号', width: 150, align: 'center' },
87
115
  { colKey: 'email', title: '邮箱', width: 200 },
88
116
  { colKey: 'nickname', title: '昵称', width: 150 },
89
117
  { colKey: 'roleCode', title: '角色', width: 120 },
90
118
  { colKey: 'state', title: '状态', width: 100 },
91
- { colKey: 'operation', title: '操作', width: 120, align: 'right' }
119
+ { colKey: 'operation', title: '操作', width: 80, align: 'center', fixed: 'right' }
92
120
  ],
93
121
  pagerConfig: {
94
122
  currentPage: 1,
@@ -98,9 +126,11 @@ const $Data = $ref({
98
126
  layout: 'total, prev, pager, next, jumper'
99
127
  },
100
128
  editVisible: false,
101
- roleVisible: false,
102
129
  actionType: 'add',
103
- rowData: {}
130
+ rowData: {},
131
+ currentRow: null,
132
+ selectedRowKeys: [],
133
+ activeRowKeys: []
104
134
  });
105
135
 
106
136
  // 方法
@@ -118,6 +148,17 @@ const $Method = {
118
148
  });
119
149
  $Data.tableData = res.data.lists || [];
120
150
  $Data.pagerConfig.total = res.data.total || 0;
151
+
152
+ // 自动选中并高亮第一行
153
+ if ($Data.tableData.length > 0) {
154
+ $Data.currentRow = $Data.tableData[0];
155
+ $Data.selectedRowKeys = [$Data.tableData[0].id];
156
+ $Data.activeRowKeys = [$Data.tableData[0].id];
157
+ } else {
158
+ $Data.currentRow = null;
159
+ $Data.selectedRowKeys = [];
160
+ $Data.activeRowKeys = [];
161
+ }
121
162
  } catch (error) {
122
163
  console.error('加载管理员列表失败:', error);
123
164
  MessagePlugin.info({
@@ -160,14 +201,53 @@ const $Method = {
160
201
  $Method.apiAdminList();
161
202
  },
162
203
 
204
+ // 每页条数改变
205
+ handleSizeChange({ pageSize }) {
206
+ $Data.pagerConfig.pageSize = pageSize;
207
+ $Data.pagerConfig.currentPage = 1;
208
+ $Method.apiAdminList();
209
+ },
210
+
211
+ // 单选变化
212
+ onSelectChange(value, { selectedRowData }) {
213
+ $Data.selectedRowKeys = value;
214
+ $Data.activeRowKeys = value;
215
+ // 更新当前选中的行数据
216
+ if (selectedRowData && selectedRowData.length > 0) {
217
+ $Data.currentRow = selectedRowData[0];
218
+ } else if ($Data.tableData.length > 0) {
219
+ // 如果取消选中,默认显示第一行
220
+ $Data.currentRow = $Data.tableData[0];
221
+ $Data.selectedRowKeys = [$Data.tableData[0].id];
222
+ $Data.activeRowKeys = [$Data.tableData[0].id];
223
+ } else {
224
+ $Data.currentRow = null;
225
+ }
226
+ },
227
+
228
+ // 高亮行变化
229
+ onActiveChange(value, { activeRowData }) {
230
+ $Data.activeRowKeys = value;
231
+ $Data.selectedRowKeys = value;
232
+ // 更新当前高亮的行数据
233
+ if (activeRowData && activeRowData.length > 0) {
234
+ $Data.currentRow = activeRowData[0];
235
+ } else if ($Data.tableData.length > 0) {
236
+ // 如果取消高亮,默认显示第一行
237
+ $Data.currentRow = $Data.tableData[0];
238
+ $Data.selectedRowKeys = [$Data.tableData[0].id];
239
+ $Data.activeRowKeys = [$Data.tableData[0].id];
240
+ } else {
241
+ $Data.currentRow = null;
242
+ }
243
+ },
244
+
163
245
  // 操作菜单点击
164
246
  onAction(command, rowData) {
165
247
  $Data.actionType = command;
166
248
  $Data.rowData = rowData;
167
249
  if (command === 'add' || command === 'upd') {
168
250
  $Data.editVisible = true;
169
- } else if (command === 'role') {
170
- $Data.roleVisible = true;
171
251
  } else if (command === 'del') {
172
252
  $Method.apiAdminDel(rowData);
173
253
  }
@@ -6,7 +6,6 @@
6
6
  <template #icon>
7
7
  <ILucidePlus />
8
8
  </template>
9
- 添加字典
10
9
  </TButton>
11
10
  </div>
12
11
  <div class="right">
@@ -14,7 +13,6 @@
14
13
  <template #icon>
15
14
  <ILucideRotateCw />
16
15
  </template>
17
- 刷新
18
16
  </TButton>
19
17
  </div>
20
18
  </div>
@@ -50,10 +50,10 @@ fetchData();
50
50
 
51
51
  .addon-item {
52
52
  position: relative;
53
- background: $bg-color-container;
54
- border: 1px solid $border-color;
55
- border-left: 3px solid $primary-color;
56
- border-radius: $border-radius-small;
53
+ background: var(--bg-color-container);
54
+ border: 1px solid var(--border-color);
55
+ border-left: 3px solid var(--primary-color);
56
+ border-radius: var(--border-radius-small);
57
57
  padding: 10px 12px;
58
58
  display: flex;
59
59
  align-items: center;
@@ -61,7 +61,7 @@ fetchData();
61
61
  transition: all 0.3s;
62
62
 
63
63
  &:hover {
64
- border-left-color: $success-color;
64
+ border-left-color: var(--success-color);
65
65
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
66
66
  transform: translateY(-2px);
67
67
  }
@@ -73,20 +73,26 @@ fetchData();
73
73
  width: 8px;
74
74
  height: 8px;
75
75
  border-radius: 50%;
76
- background: $text-disabled;
76
+ background: var(--text-disabled);
77
77
  transition: all 0.3s;
78
78
 
79
- &.active {
80
- background: $success-color;
81
- box-shadow: 0 0 0 2px rgba($success-color, 0.2);
82
- }
79
+ &::after {
80
+ content: '';
81
+ position: absolute;
82
+ top: -2px;
83
+ right: -2px;
84
+ width: 8px;
85
+ height: 8px;
86
+ border-radius: 50%;
87
+ background: var(--success-color);
88
+ box-shadow: 0 0 0 2px rgba(var(--success-color-rgb), 0.2);
83
89
  }
84
90
 
85
91
  .addon-icon {
86
92
  width: 32px;
87
93
  height: 32px;
88
- background: linear-gradient(135deg, $primary-color, #764ba2);
89
- border-radius: $border-radius-small;
94
+ background: linear-gradient(135deg, var(--primary-color), #764ba2);
95
+ border-radius: var(--border-radius-small);
90
96
  display: flex;
91
97
  align-items: center;
92
98
  justify-content: center;
@@ -108,13 +114,13 @@ fetchData();
108
114
  .addon-name {
109
115
  font-size: 14px;
110
116
  font-weight: 600;
111
- color: $text-primary;
117
+ color: var(--text-primary);
112
118
  }
113
119
  }
114
120
 
115
121
  .addon-desc {
116
122
  font-size: 14px;
117
- color: $text-secondary;
123
+ color: var(--text-secondary);
118
124
  line-height: 1.3;
119
125
  overflow: hidden;
120
126
  text-overflow: ellipsis;
@@ -73,25 +73,25 @@ fetchData();
73
73
  justify-content: space-between;
74
74
  align-items: center;
75
75
  padding: 10px 12px;
76
- background: $bg-color-container;
76
+ background: var(--bg-color-container);
77
77
  border-radius: 6px;
78
- border: 1px solid $border-color;
78
+ border: 1px solid var(--border-color);
79
79
  transition: all 0.2s ease;
80
80
 
81
81
  &:hover {
82
- background: rgba($primary-color, 0.03);
83
- border-color: rgba($primary-color, 0.2);
82
+ background: rgba(var(--primary-color-rgb), 0.03);
83
+ border-color: rgba(var(--primary-color-rgb), 0.2);
84
84
  }
85
85
 
86
86
  .env-label {
87
87
  font-size: 14px;
88
- color: $text-secondary;
88
+ color: var(--text-secondary);
89
89
  font-weight: 500;
90
90
  }
91
91
 
92
92
  .env-value {
93
93
  font-size: 14px;
94
- color: $text-primary;
94
+ color: var(--text-primary);
95
95
  font-weight: 600;
96
96
  text-align: right;
97
97
  }
@@ -65,11 +65,11 @@ const formatTime = (timestamp) => {
65
65
 
66
66
  .operation-header {
67
67
  padding: 10px 12px;
68
- background: linear-gradient(135deg, rgba($primary-color, 0.05) 0%, rgba($primary-color, 0.02) 100%);
68
+ background: linear-gradient(135deg, rgba(var(--primary-color-rgb), 0.05) 0%, rgba(var(--primary-color-rgb), 0.02) 100%);
69
69
  border-radius: 6px;
70
70
  font-size: 14px;
71
71
  font-weight: 600;
72
- color: $text-secondary;
72
+ color: var(--text-secondary);
73
73
  margin-bottom: 6px;
74
74
  }
75
75
 
@@ -80,20 +80,20 @@ const formatTime = (timestamp) => {
80
80
  }
81
81
 
82
82
  .operation-row {
83
- padding: 10px 12px;
84
- background: $bg-color-container;
83
+ padding: 6px 12px;
84
+ background: var(--bg-color-container);
85
85
  border-radius: 6px;
86
- border: 1px solid $border-color;
86
+ border: 1px solid var(--border-color);
87
87
  font-size: 14px;
88
88
  transition: all 0.2s ease;
89
89
 
90
90
  &:hover {
91
- background: rgba($primary-color, 0.02);
92
- border-color: rgba($primary-color, 0.2);
91
+ background: rgba(var(--primary-color-rgb), 0.02);
92
+ border-color: rgba(var(--primary-color-rgb), 0.2);
93
93
  }
94
94
 
95
95
  .col-time {
96
- color: $text-secondary;
96
+ color: var(--text-secondary);
97
97
  font-size: 14px;
98
98
  }
99
99
 
@@ -101,7 +101,7 @@ const formatTime = (timestamp) => {
101
101
  .col-action,
102
102
  .col-module,
103
103
  .col-ip {
104
- color: $text-primary;
104
+ color: var(--text-primary);
105
105
  }
106
106
 
107
107
  .col-action {