Files
ljwx-health/ljwx-admin/src/views/device/info/modules/device-info-operate-drawer.vue
T
BrunoGaoandClaude aa41afaf00 feat: 全面优化前端界面和增强用户体验
- 新增科技风格的抽屉组件样式和主题系统,支持健康监测、设备管理、用户管理、告警配置等多个业务主题
- 优化TenantInfo组件的事件处理,修复Vue 3兼容性问题
- 重构路由器创建逻辑,提升代码可维护性和扩展性
- 统一所有抽屉弹窗的UI风格,增加操作横幅、分组布局、图标提示等现代化设计元素
- 修复customer租户管理权限控制逻辑,改进按钮状态管理和权限验证流程
- 新增批量数据上传测试工具,支持curl和Python接口测试
- 优化设备信息编辑界面,增加分组显示、帮助文本、状态指示等功能
- 创建完整的界面增强指南和自动化脚本,便于后续维护和扩展

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-22 06:40:24 +08:00

243 lines
7.8 KiB
Vue

<script setup lang="ts">
import { computed, reactive, watch } from 'vue';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import { $t } from '@/locales';
import { fetchAddDeviceInfo, fetchUpdateDeviceInfoInfo } from '@/service/api';
import { useDict } from '@/hooks/business/dict';
defineOptions({
name: 'TDeviceInfoOperateDrawer'
});
interface Props {
/** the type of operation */
operateType: NaiveUI.TableOperateType;
/** the edit row data */
rowData?: Api.Health.DeviceInfo | null;
}
const props = defineProps<Props>();
interface Emits {
(e: 'submitted'): void;
}
const emit = defineEmits<Emits>();
const visible = defineModel<boolean>('visible', {
default: false
});
const { dictOptions } = useDict();
const { formRef, validate, restoreValidation } = useNaiveForm();
const title = computed(() => {
const titles: Record<NaiveUI.TableOperateType, string> = {
add: $t('common.add'),
edit: $t('common.edit')
};
return titles[props.operateType];
});
type Model = Api.Health.DeviceInfo;
const model: Model = reactive(createDefaultModel());
function createDefaultModel(): Model {
return {
id: '',
createUser: '',
createTime: '',
updateUser: '',
updateTime: '',
systemSoftwareVersion: '',
wifiAddress: '',
bluetoothAddress: '',
ipAddress: '',
networkAccessMode: 0,
serialNumber: '',
deviceName: '',
imei: '',
createdAt: '',
batteryLevel: '',
model: '',
status: '',
wearableStatus: 0,
chargingStatus: 0,
customerId: 0
};
}
function handleInitModel() {
Object.assign(model, createDefaultModel());
if (!props.rowData) return;
if (props.operateType === 'edit' && props.rowData) {
Object.assign(model, {
...props.rowData,
networkAccessMode: Number(props.rowData.networkAccessMode) || 0,
batteryLevel: Number(props.rowData.batteryLevel) || 0
});
}
}
function closeDrawer() {
visible.value = false;
}
const isAdd = computed(() => props.operateType === 'add');
async function handleSubmit() {
await validate();
const func = isAdd.value ? fetchAddDeviceInfo : fetchUpdateDeviceInfoInfo;
const { error, data } = await func(model);
if (!error && data) {
window.$message?.success(isAdd.value ? $t('common.addSuccess') : $t('common.updateSuccess'));
closeDrawer();
emit('submitted');
}
}
watch(visible, () => {
if (visible.value) {
handleInitModel();
restoreValidation();
}
});
</script>
<template>
<NDrawer v-model:show="visible" display-directive="show" :width="420" class="enhanced-drawer device-theme">
<NDrawerContent :title="title" :native-scrollbar="false" closable>
<!-- 操作横幅 -->
<div class="operation-banner">
<div class="banner-icon">
<i class="i-material-symbols:devices" v-if="isAdd"></i>
<i class="i-material-symbols:settings" v-else></i>
</div>
<div class="banner-content">
<h3 class="banner-title">{{ isAdd ? '新增设备' : '编辑设备' }}</h3>
<p class="banner-desc">{{ isAdd ? '配置新设备的基本信息和参数' : '修改设备配置信息,确保数据准确性' }}</p>
</div>
</div>
<NForm ref="formRef" :model="model">
<!-- 基本信息 -->
<div class="form-section">
<div class="section-title">
<i class="i-material-symbols:info"></i>
基本信息
</div>
<NFormItem :label="$t('page.health.device.info.systemSoftwareVersion')" path="systemSoftwareVersion">
<NInput
v-model:value="model.systemSoftwareVersion"
:placeholder="$t('page.health.device.info.form.systemSoftwareVersion')"
:disabled="!isAdd"
>
<template #prefix>
<i class="i-material-symbols:system-update"></i>
</template>
</NInput>
<div class="help-text" v-if="!isAdd">系统版本不可修改</div>
</NFormItem>
<NFormItem :label="$t('page.health.device.info.serialNumber')" path="serialNumber">
<NInput v-model:value="model.serialNumber" :placeholder="$t('page.health.device.info.form.serialNumber')">
<template #prefix>
<i class="i-material-symbols:tag"></i>
</template>
</NInput>
</NFormItem>
<NFormItem :label="$t('page.health.device.info.model')" path="model">
<NSelect v-model:value="model.model" :options="dictOptions('device_model')">
<template #arrow>
<i class="i-material-symbols:smartphone"></i>
</template>
</NSelect>
</NFormItem>
</div>
<!-- 网络配置 -->
<div class="form-section">
<div class="section-title">
<i class="i-material-symbols:network-wifi"></i>
网络配置
</div>
<NFormItem :label="$t('page.health.device.info.networkAccessMode')" path="networkAccessMode">
<NInputNumber v-model:value="model.networkAccessMode" :placeholder="$t('page.health.device.info.form.networkAccessMode')">
<template #prefix>
<i class="i-material-symbols:router"></i>
</template>
</NInputNumber>
<div class="help-text">网络访问模式配置</div>
</NFormItem>
</div>
<!-- 设备状态 -->
<div class="form-section">
<div class="section-title">
<i class="i-material-symbols:health-and-safety"></i>
设备状态
</div>
<NFormItem :label="$t('page.health.device.info.wearableStatus')" path="wearableStatus">
<NSelect v-model:value="model.wearableStatus" :options="dictOptions('wear_status')">
<template #arrow>
<i class="i-material-symbols:watch"></i>
</template>
</NSelect>
</NFormItem>
<NFormItem :label="$t('page.health.device.info.batterylevel')" path="batteryLevel">
<NInputNumber v-model:value="model.batteryLevel" :placeholder="$t('page.health.device.info.form.batterylevel')">
<template #prefix>
<i class="i-material-symbols:battery-full"></i>
</template>
</NInputNumber>
<div class="help-text">电池电量 (0-100%)</div>
</NFormItem>
<NFormItem :label="$t('page.health.device.info.chargingStatus')" path="chargingStatus">
<NSelect v-model:value="model.chargingStatus" :options="dictOptions('charging_status')">
<template #arrow>
<i class="i-material-symbols:charging-station"></i>
</template>
</NSelect>
</NFormItem>
<NFormItem :label="$t('page.health.device.info.status')" path="status">
<NSelect v-model:value="model.status" :options="dictOptions('device_status')">
<template #arrow>
<i class="i-material-symbols:power"></i>
</template>
</NSelect>
</NFormItem>
</div>
</NForm>
<template #footer>
<div class="drawer-footer">
<NButton @click="closeDrawer" class="cancel-btn">
<template #icon>
<i class="i-material-symbols:close"></i>
</template>
{{ $t('common.cancel') }}
</NButton>
<NButton type="primary" @click="handleSubmit" class="submit-btn">
<template #icon>
<i class="i-material-symbols:check"></i>
</template>
{{ isAdd ? $t('common.add') : $t('common.update') }}
</NButton>
</div>
</template>
</NDrawerContent>
</NDrawer>
</template>
<style scoped></style>