From cd7aa35960eb7c5d8a93d909df9bd4e169359c43 Mon Sep 17 00:00:00 2001 From: BBIT-Kai <2911862937@qq.com> Date: Mon, 29 Dec 2025 16:30:04 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E7=89=A7=E5=AE=89=E4=BA=91?= =?UTF-8?q?=E5=93=A8-=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web-antd/src/adapter/component/index.ts | 2 +- vue2/apps/web-antd/src/adapter/vxe-table.ts | 142 ++++++++++++++++++ vue2/apps/web-antd/src/api/iot/device.ts | 19 +++ vue2/apps/web-antd/src/api/iot/index.ts | 1 + vue2/apps/web-antd/src/api/sentinel/index.ts | 2 +- .../src/router/routes/modules/manager.ts | 15 +- .../playground/src/views/system/role/form.vue | 4 +- 7 files changed, 167 insertions(+), 18 deletions(-) diff --git a/vue2/apps/web-antd/src/adapter/component/index.ts b/vue2/apps/web-antd/src/adapter/component/index.ts index a62114e..4c2e5df 100644 --- a/vue2/apps/web-antd/src/adapter/component/index.ts +++ b/vue2/apps/web-antd/src/adapter/component/index.ts @@ -125,7 +125,7 @@ const withPreviewUpload = () => { ) => { const previewVisible = ref(false); - const placeholder = attrs?.placeholder || $t(`ui.placeholder.upload`); + const placeholder = attrs?.placeholder || '上传文件'; const listType = attrs?.listType || attrs?.['list-type'] || 'text'; diff --git a/vue2/apps/web-antd/src/adapter/vxe-table.ts b/vue2/apps/web-antd/src/adapter/vxe-table.ts index f5fe662..2fc6656 100644 --- a/vue2/apps/web-antd/src/adapter/vxe-table.ts +++ b/vue2/apps/web-antd/src/adapter/vxe-table.ts @@ -61,6 +61,148 @@ setupVbenVxeTable({ ); }, }); + /** + * 可扩展操作列渲染器 + * - 支持普通操作(edit) + * - 支持确认型操作(delete / 自定义) + */ + vxeUI.renderer.add('CellOperationEx', { + renderTableDefault({ attrs, options, props }, { column, row }) { + const defaultProps = { size: 'small', type: 'link', ...props }; + + /** 对齐方式 */ + let align = 'end'; + switch (column.align) { + case 'center': + align = 'center'; + break; + case 'left': + align = 'start'; + break; + default: + align = 'end'; + } + + /** 预置操作 */ + const presets: Recordable> = { + edit: { + code: 'edit', + text: $t('common.edit'), + }, + delete: { + code: 'delete', + text: $t('common.delete'), + danger: true, + confirm: true, + confirmTitle: () => + $t('ui.actionTitle.delete', [attrs?.nameTitle || '']), + confirmMessage: (row: any) => + $t('ui.actionMessage.deleteConfirm', [ + row[attrs?.nameField || 'name'], + ]), + }, + }; + + /** 生成操作配置 */ + const operations = (options || ['edit', 'delete']) + .map((opt) => { + if (typeof opt === 'string') { + return presets[opt] + ? { ...defaultProps, ...presets[opt] } + : { + ...defaultProps, + code: opt, + text: opt, + }; + } + return { + ...defaultProps, + ...presets[opt.code], + ...opt, + }; + }) + .map((opt) => { + const resolved: Recordable = {}; + Object.keys(opt).forEach((key) => { + resolved[key] = + typeof opt[key] === 'function' ? opt[key](row) : opt[key]; + }); + return resolved; + }) + .filter((opt) => opt.show !== false); + + /** 普通按钮 */ + function renderBtn(opt: Recordable, listen = true) { + return h( + Button, + { + ...opt, + icon: undefined, + onClick: listen + ? () => + attrs?.onClick?.({ + code: opt.code, + row, + }) + : undefined, + }, + { default: () => opt.text }, + ); + } + + /** 确认型按钮 */ + function renderConfirm(opt: Recordable) { + let viewportWrapper: HTMLElement | null = null; + + return h( + Popconfirm, + { + getPopupContainer(el) { + viewportWrapper = el.closest('.vxe-table--viewport-wrapper'); + return document.body; + }, + placement: 'topLeft', + title: opt.confirmTitle, + icon: undefined, + onOpenChange(open: boolean) { + if (open) { + viewportWrapper?.style.setProperty('pointer-events', 'none'); + } else { + viewportWrapper?.style.removeProperty('pointer-events'); + } + }, + onConfirm() { + attrs?.onClick?.({ + code: opt.code, + row, + }); + }, + }, + { + default: () => renderBtn(opt, false), + description: () => + opt.confirmMessage + ? h('div', { class: 'truncate' }, opt.confirmMessage) + : null, + }, + ); + } + + /** 根据是否需要确认选择渲染方式 */ + const btns = operations.map((opt) => + opt.confirm ? renderConfirm(opt) : renderBtn(opt), + ); + + return h( + 'div', + { + class: 'flex table-operations', + style: { justifyContent: align }, + }, + btns, + ); + }, + }); /** * 注册表格的操作按钮渲染器 diff --git a/vue2/apps/web-antd/src/api/iot/device.ts b/vue2/apps/web-antd/src/api/iot/device.ts index ef55d79..6ca38a9 100644 --- a/vue2/apps/web-antd/src/api/iot/device.ts +++ b/vue2/apps/web-antd/src/api/iot/device.ts @@ -71,10 +71,29 @@ async function deleteDevice(id: string) { return pyRequestClient.delete(`/iot/common/device/${id}`); } +/** + * 发送指令 + * @param data 设备数据 + */ +async function iotSendCommand( + id: string, + command: string, + project: string, + device_type: string, +) { + return pyRequestClient.post('/iot/common/device/command', { + id, + command, + project, + device_type, + }); +} + export { createDevice, deleteDevice, getDeviceList, + iotSendCommand, updateDevice, updateDevicePatch, }; diff --git a/vue2/apps/web-antd/src/api/iot/index.ts b/vue2/apps/web-antd/src/api/iot/index.ts index 0ce9c17..bd660d1 100644 --- a/vue2/apps/web-antd/src/api/iot/index.ts +++ b/vue2/apps/web-antd/src/api/iot/index.ts @@ -1 +1,2 @@ export * from './device'; +export * from './update'; diff --git a/vue2/apps/web-antd/src/api/sentinel/index.ts b/vue2/apps/web-antd/src/api/sentinel/index.ts index 0ce9c17..96bb9f9 100644 --- a/vue2/apps/web-antd/src/api/sentinel/index.ts +++ b/vue2/apps/web-antd/src/api/sentinel/index.ts @@ -1 +1 @@ -export * from './device'; +export * from './record'; diff --git a/vue2/apps/web-antd/src/router/routes/modules/manager.ts b/vue2/apps/web-antd/src/router/routes/modules/manager.ts index 4d65a18..6ff31a2 100644 --- a/vue2/apps/web-antd/src/router/routes/modules/manager.ts +++ b/vue2/apps/web-antd/src/router/routes/modules/manager.ts @@ -59,27 +59,16 @@ const routes: RouteRecordRaw[] = [ component: () => import('#/views/manager/dict/index.vue'), }, { - name: 'M-perm', + name: 'perm', path: '/manager/perm', meta: { authority: ['manager'], icon: 'mdi:menu', - title: '菜单-实验室', + title: '菜单管理', keepAlive: true, }, component: () => import('#/views/manager/menu/index.vue'), }, - { - name: 'M-perm2', - path: '/manager/perm2', - meta: { - authority: ['manager'], - icon: 'mdi:menu', - title: '菜单-大数据', - keepAlive: true, - }, - component: () => import('#/views/manager/menu/index2.vue'), - }, ], }, ]; diff --git a/vue2/playground/src/views/system/role/form.vue b/vue2/playground/src/views/system/role/form.vue index 3572cc0..77858e0 100644 --- a/vue2/playground/src/views/system/role/form.vue +++ b/vue2/playground/src/views/system/role/form.vue @@ -83,9 +83,7 @@ async function loadPermissions() { } const getDrawerTitle = computed(() => { - return formData.value?.id - ? $t('common.edit', $t('system.role.name')) - : $t('common.create', $t('system.role.name')); + return formData.value?.id ? '修改角色' : '新增角色'; }); function getNodeClass(node: Recordable) {