|
|
@@ -118,7 +118,55 @@
|
|
|
</el-descriptions>
|
|
|
</el-drawer>
|
|
|
|
|
|
- <!-- 摄像头列表抽屉 -->
|
|
|
+ <!-- LSS 编辑抽屉 -->
|
|
|
+ <el-drawer
|
|
|
+ v-model="lssEditDrawerVisible"
|
|
|
+ direction="rtl"
|
|
|
+ size="500px"
|
|
|
+ :with-header="false"
|
|
|
+ destroy-on-close
|
|
|
+ class="lss-edit-drawer"
|
|
|
+ >
|
|
|
+ <div class="drawer-content">
|
|
|
+ <div class="drawer-header">LSS详情</div>
|
|
|
+ <div class="drawer-body">
|
|
|
+ <div class="lss-detail-form">
|
|
|
+ <div class="form-item">
|
|
|
+ <label class="form-label">LSS ID:</label>
|
|
|
+ <span class="form-value">{{ currentLss?.lssId }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <label class="form-label">名称:</label>
|
|
|
+ <el-input v-model="lssEditForm.lssName" placeholder="请输入名称" />
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <label class="form-label">地址:</label>
|
|
|
+ <el-input v-model="lssEditForm.address" placeholder="请输入地址" />
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <label class="form-label">IP:</label>
|
|
|
+ <span class="form-value">{{ currentLss?.publicIp || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <label class="form-label">心跳:</label>
|
|
|
+ <span class="form-value" :class="getHeartbeatClass(currentLss?.heartbeat)">
|
|
|
+ {{ formatHeartbeat(currentLss) }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div class="form-item">
|
|
|
+ <label class="form-label">ably信息:</label>
|
|
|
+ <el-input v-model="lssEditForm.ablyInfo" placeholder="请输入ably信息" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="drawer-footer">
|
|
|
+ <el-button @click="lssEditDrawerVisible = false">{{ t('取消') }}</el-button>
|
|
|
+ <el-button type="primary" :loading="lssUpdating" @click="handleUpdateLss">{{ t('更新') }}</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-drawer>
|
|
|
+
|
|
|
+ <!-- 设备列表抽屉 -->
|
|
|
<el-drawer
|
|
|
v-model="cameraDrawerVisible"
|
|
|
:title="`设备列表 - ${currentLss?.lssName || ''}`"
|
|
|
@@ -199,33 +247,28 @@
|
|
|
<!-- 摄像头编辑弹窗 -->
|
|
|
<el-dialog
|
|
|
v-model="cameraDialogVisible"
|
|
|
- :title="isEditCamera ? '编辑摄像头' : '绑定摄像头'"
|
|
|
+ :title="isEditCamera ? '编辑摄像头' : '添加摄像头'"
|
|
|
width="500px"
|
|
|
:close-on-click-modal="false"
|
|
|
>
|
|
|
<el-form ref="cameraFormRef" :model="cameraForm" :rules="cameraRules" label-width="100px">
|
|
|
- <!-- 新增时显示摄像头选择下拉 -->
|
|
|
- <el-form-item v-if="!isEditCamera" label="选择摄像头" prop="selectedCameraId">
|
|
|
+ <!-- 新增时显示厂商选择下拉 -->
|
|
|
+ <el-form-item v-if="!isEditCamera" label="选择厂商" prop="selectedVendorId">
|
|
|
<el-select
|
|
|
- v-model="cameraForm.selectedCameraId"
|
|
|
- placeholder="请选择摄像头"
|
|
|
+ v-model="cameraForm.selectedVendorId"
|
|
|
+ placeholder="请选择厂商"
|
|
|
style="width: 100%"
|
|
|
filterable
|
|
|
- @change="handleCameraSelect"
|
|
|
+ @change="handleVendorSelect"
|
|
|
>
|
|
|
- <el-option
|
|
|
- v-for="cam in availableCameras"
|
|
|
- :key="cam.id"
|
|
|
- :label="`${cam.ip} - ${cam.cameraId}`"
|
|
|
- :value="cam.id"
|
|
|
- />
|
|
|
+ <el-option v-for="vendor in availableVendors" :key="vendor.id" :label="vendor.name" :value="vendor.id" />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="IP 地址" prop="ip">
|
|
|
- <el-input v-model="cameraForm.ip" disabled placeholder="IP 地址" />
|
|
|
+ <el-input v-model="cameraForm.ip" :disabled="isEditCamera" placeholder="请输入 IP 地址" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="摄像头 ID" prop="cameraId">
|
|
|
- <el-input v-model="cameraForm.cameraId" disabled placeholder="摄像头 ID" />
|
|
|
+ <el-input v-model="cameraForm.cameraId" :disabled="isEditCamera" placeholder="请输入摄像头 ID" />
|
|
|
</el-form-item>
|
|
|
<el-form-item label="名称" prop="name">
|
|
|
<el-input v-model="cameraForm.name" placeholder="请输入名称" />
|
|
|
@@ -239,12 +282,15 @@
|
|
|
<el-form-item label="密码" prop="password">
|
|
|
<el-input v-model="cameraForm.password" type="password" show-password placeholder="请输入密码" />
|
|
|
</el-form-item>
|
|
|
- <el-form-item label="品牌" prop="brand">
|
|
|
+ <!-- 编辑时显示品牌选择 -->
|
|
|
+ <el-form-item v-if="isEditCamera" label="品牌" prop="brand">
|
|
|
<el-select v-model="cameraForm.brand" placeholder="请选择品牌" style="width: 100%">
|
|
|
- <el-option label="海康威视" value="hikvision" />
|
|
|
- <el-option label="大华" value="dahua" />
|
|
|
- <el-option label="宇视" value="uniview" />
|
|
|
- <el-option label="其他" value="other" />
|
|
|
+ <el-option
|
|
|
+ v-for="vendor in availableVendors"
|
|
|
+ :key="vendor.code"
|
|
|
+ :label="vendor.name"
|
|
|
+ :value="vendor.code"
|
|
|
+ />
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item label="能力" prop="capability">
|
|
|
@@ -295,21 +341,18 @@
|
|
|
import { ref, reactive, onMounted, computed } from 'vue'
|
|
|
import { Search, RefreshRight, Delete, View, Edit, VideoCamera, Plus } from '@element-plus/icons-vue'
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
-import { listLssNodes, deleteLssNode, setLssNodeEnabled } from '@/api/lss'
|
|
|
-import {
|
|
|
- adminListCameras,
|
|
|
- adminAddCamera,
|
|
|
- adminUpdateCamera,
|
|
|
- adminDeleteCamera,
|
|
|
- adminListAllCameras
|
|
|
-} from '@/api/camera'
|
|
|
+import { listLssNodes, deleteLssNode, setLssNodeEnabled, updateLssNode } from '@/api/lss'
|
|
|
+import { adminListCameras, adminAddCamera, adminUpdateCamera, adminDeleteCamera } from '@/api/camera'
|
|
|
+import { listCameraVendors } from '@/api/camera-vendor'
|
|
|
import type {
|
|
|
LssNodeDTO,
|
|
|
LssNodeStatus,
|
|
|
LssNodeListRequest,
|
|
|
+ LssHeartbeatStatus,
|
|
|
CameraInfoDTO,
|
|
|
CameraAddRequest,
|
|
|
- CameraUpdateRequest
|
|
|
+ CameraUpdateRequest,
|
|
|
+ CameraVendorDTO
|
|
|
} from '@/types'
|
|
|
import type { FormInstance, FormRules } from 'element-plus'
|
|
|
import dayjs from 'dayjs'
|
|
|
@@ -375,6 +418,33 @@ function formatBrand(brand: string | undefined): string {
|
|
|
return brand ? brandMap[brand] || brand.toUpperCase() : '-'
|
|
|
}
|
|
|
|
|
|
+// 格式化心跳状态
|
|
|
+function formatHeartbeat(lss: LssNodeDTO | null | undefined): string {
|
|
|
+ if (!lss) return '-'
|
|
|
+ const status = lss.heartbeat || (lss.status === 'ONLINE' ? 'active' : 'dead')
|
|
|
+ const time = lss.heartbeatTime || lss.updatedAt
|
|
|
+ if (status === 'active') {
|
|
|
+ return `active [${formatTime(time)}]`
|
|
|
+ } else if (status === 'hold') {
|
|
|
+ return `hold [${formatTime(time)}]`
|
|
|
+ } else {
|
|
|
+ return `dead (离线)`
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 获取心跳状态样式类
|
|
|
+function getHeartbeatClass(status: LssHeartbeatStatus | undefined): string {
|
|
|
+ switch (status) {
|
|
|
+ case 'active':
|
|
|
+ return 'status-active'
|
|
|
+ case 'hold':
|
|
|
+ return 'status-hold'
|
|
|
+ case 'dead':
|
|
|
+ default:
|
|
|
+ return 'status-dead'
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 查看参数配置
|
|
|
function handleViewConfig(row: CameraInfoDTO) {
|
|
|
ElMessage.info(`查看 ${row.name} 的参数配置`)
|
|
|
@@ -395,7 +465,16 @@ const tableRef = ref()
|
|
|
const detailDrawerVisible = ref(false)
|
|
|
const currentLss = ref<LssNodeDTO | null>(null)
|
|
|
|
|
|
-// 摄像头列表抽屉状态
|
|
|
+// LSS 编辑抽屉状态
|
|
|
+const lssEditDrawerVisible = ref(false)
|
|
|
+const lssUpdating = ref(false)
|
|
|
+const lssEditForm = reactive({
|
|
|
+ lssName: '',
|
|
|
+ address: '',
|
|
|
+ ablyInfo: ''
|
|
|
+})
|
|
|
+
|
|
|
+// 设备列表抽屉状态
|
|
|
const cameraDrawerVisible = ref(false)
|
|
|
const cameraLoading = ref(false)
|
|
|
const cameraList = ref<CameraInfoDTO[]>([])
|
|
|
@@ -412,11 +491,11 @@ const cameraFormRef = ref<FormInstance>()
|
|
|
const isEditCamera = ref(false)
|
|
|
const cameraSubmitting = ref(false)
|
|
|
const currentCamera = ref<CameraInfoDTO | null>(null)
|
|
|
-const availableCameras = ref<CameraInfoDTO[]>([])
|
|
|
+const availableVendors = ref<CameraVendorDTO[]>([])
|
|
|
|
|
|
// 摄像头表单
|
|
|
const cameraForm = reactive({
|
|
|
- selectedCameraId: null as number | null,
|
|
|
+ selectedVendorId: null as number | null,
|
|
|
cameraId: '',
|
|
|
name: '',
|
|
|
ip: '',
|
|
|
@@ -434,8 +513,10 @@ const cameraForm = reactive({
|
|
|
|
|
|
// 摄像头表单验证规则(动态)
|
|
|
const cameraRules = computed<FormRules>(() => ({
|
|
|
- selectedCameraId: isEditCamera.value ? [] : [{ required: true, message: '请选择摄像头', trigger: 'change' }],
|
|
|
- name: [{ required: false, message: '请输入名称', trigger: 'blur' }]
|
|
|
+ selectedVendorId: isEditCamera.value ? [] : [{ required: true, message: '请选择厂商', trigger: 'change' }],
|
|
|
+ cameraId: isEditCamera.value ? [] : [{ required: true, message: '请输入摄像头 ID', trigger: 'blur' }],
|
|
|
+ ip: isEditCamera.value ? [] : [{ required: true, message: '请输入 IP 地址', trigger: 'blur' }],
|
|
|
+ name: [{ required: true, message: '请输入名称', trigger: 'blur' }]
|
|
|
}))
|
|
|
|
|
|
// 排序状态
|
|
|
@@ -537,7 +618,11 @@ function handleViewDetail(row: LssNodeDTO) {
|
|
|
}
|
|
|
|
|
|
function handleEdit(row: LssNodeDTO) {
|
|
|
- handleCameraList(row)
|
|
|
+ currentLss.value = row
|
|
|
+ lssEditForm.lssName = row.lssName || ''
|
|
|
+ lssEditForm.address = row.address || ''
|
|
|
+ lssEditForm.ablyInfo = row.ablyInfo || ''
|
|
|
+ lssEditDrawerVisible.value = true
|
|
|
}
|
|
|
|
|
|
async function handleCameraList(row: LssNodeDTO) {
|
|
|
@@ -548,6 +633,32 @@ async function handleCameraList(row: LssNodeDTO) {
|
|
|
await loadCameraList()
|
|
|
}
|
|
|
|
|
|
+async function handleUpdateLss() {
|
|
|
+ if (!currentLss.value) return
|
|
|
+
|
|
|
+ lssUpdating.value = true
|
|
|
+ try {
|
|
|
+ const res = await updateLssNode({
|
|
|
+ lssId: currentLss.value.lssId,
|
|
|
+ lssName: lssEditForm.lssName,
|
|
|
+ address: lssEditForm.address,
|
|
|
+ ablyInfo: lssEditForm.ablyInfo
|
|
|
+ })
|
|
|
+ if (res.success) {
|
|
|
+ ElMessage.success('更新成功')
|
|
|
+ lssEditDrawerVisible.value = false
|
|
|
+ getList()
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.errMessage || '更新失败')
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('更新 LSS 失败', error)
|
|
|
+ ElMessage.error('更新失败')
|
|
|
+ } finally {
|
|
|
+ lssUpdating.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
async function loadCameraList() {
|
|
|
if (!currentLss.value) return
|
|
|
cameraLoading.value = true
|
|
|
@@ -586,7 +697,7 @@ function handleCameraReset() {
|
|
|
}
|
|
|
|
|
|
function resetCameraForm() {
|
|
|
- cameraForm.selectedCameraId = null
|
|
|
+ cameraForm.selectedVendorId = null
|
|
|
cameraForm.cameraId = ''
|
|
|
cameraForm.name = ''
|
|
|
cameraForm.ip = ''
|
|
|
@@ -603,35 +714,27 @@ function resetCameraForm() {
|
|
|
cameraFormRef.value?.clearValidate()
|
|
|
}
|
|
|
|
|
|
-async function loadAvailableCameras() {
|
|
|
+async function loadAvailableVendors() {
|
|
|
try {
|
|
|
- // 获取所有摄像头(不传 lssId 获取未绑定的)
|
|
|
- const res = await adminListAllCameras()
|
|
|
+ const res = await listCameraVendors({ enabled: true })
|
|
|
if (res.success && res.data) {
|
|
|
- // 过滤掉已绑定到当前 LSS 的摄像头
|
|
|
- availableCameras.value = res.data.filter((cam) => !cam.lssId || cam.lssId !== currentLss.value?.lssId)
|
|
|
+ availableVendors.value = res.data.list || []
|
|
|
}
|
|
|
} catch (error) {
|
|
|
- console.error('获取可用摄像头列表失败', error)
|
|
|
+ console.error('获取厂商列表失败', error)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function handleCameraSelect(cameraId: number) {
|
|
|
- const camera = availableCameras.value.find((cam) => cam.id === cameraId)
|
|
|
- if (camera) {
|
|
|
- cameraForm.cameraId = camera.cameraId
|
|
|
- cameraForm.ip = camera.ip
|
|
|
- cameraForm.name = camera.name || ''
|
|
|
- cameraForm.port = camera.port || 80
|
|
|
- cameraForm.username = camera.username || ''
|
|
|
- cameraForm.brand = camera.brand || ''
|
|
|
- cameraForm.capability = camera.capability || 'switch_only'
|
|
|
- cameraForm.rtspUrl = camera.rtspUrl || ''
|
|
|
- cameraForm.model = camera.model || ''
|
|
|
- cameraForm.channelNo = camera.channelNo || ''
|
|
|
- cameraForm.remark = camera.remark || ''
|
|
|
- cameraForm.enabled = camera.enabled
|
|
|
- currentCamera.value = camera
|
|
|
+function handleVendorSelect(vendorId: number) {
|
|
|
+ const vendor = availableVendors.value.find((v) => v.id === vendorId)
|
|
|
+ if (vendor) {
|
|
|
+ cameraForm.brand = vendor.code
|
|
|
+ // 设置厂商默认端口
|
|
|
+ if (vendor.defaultPort) {
|
|
|
+ cameraForm.port = vendor.defaultPort
|
|
|
+ }
|
|
|
+ // 根据厂商设置默认能力
|
|
|
+ cameraForm.capability = vendor.supportPtz ? 'ptz_enabled' : 'switch_only'
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -639,14 +742,14 @@ async function handleAddCamera() {
|
|
|
isEditCamera.value = false
|
|
|
currentCamera.value = null
|
|
|
resetCameraForm()
|
|
|
- await loadAvailableCameras()
|
|
|
+ await loadAvailableVendors()
|
|
|
cameraDialogVisible.value = true
|
|
|
}
|
|
|
|
|
|
-function handleEditCamera(row: CameraInfoDTO) {
|
|
|
+async function handleEditCamera(row: CameraInfoDTO) {
|
|
|
isEditCamera.value = true
|
|
|
currentCamera.value = row
|
|
|
- cameraForm.selectedCameraId = row.id
|
|
|
+ cameraForm.selectedVendorId = null
|
|
|
cameraForm.cameraId = row.cameraId
|
|
|
cameraForm.name = row.name
|
|
|
cameraForm.ip = row.ip
|
|
|
@@ -660,6 +763,7 @@ function handleEditCamera(row: CameraInfoDTO) {
|
|
|
cameraForm.channelNo = row.channelNo || ''
|
|
|
cameraForm.remark = row.remark || ''
|
|
|
cameraForm.enabled = row.enabled
|
|
|
+ await loadAvailableVendors()
|
|
|
cameraDialogVisible.value = true
|
|
|
}
|
|
|
|
|
|
@@ -671,36 +775,62 @@ async function handleSubmitCamera() {
|
|
|
|
|
|
cameraSubmitting.value = true
|
|
|
try {
|
|
|
- if (!currentCamera.value) {
|
|
|
- ElMessage.error('请选择摄像头')
|
|
|
- return
|
|
|
- }
|
|
|
-
|
|
|
- // 无论新增还是编辑,都是更新摄像头信息(绑定 lssId)
|
|
|
- const data: CameraUpdateRequest = {
|
|
|
- id: currentCamera.value.id,
|
|
|
- name: cameraForm.name,
|
|
|
- port: cameraForm.port,
|
|
|
- username: cameraForm.username,
|
|
|
- brand: cameraForm.brand,
|
|
|
- capability: cameraForm.capability,
|
|
|
- lssId: currentLss.value?.lssId,
|
|
|
- rtspUrl: cameraForm.rtspUrl,
|
|
|
- model: cameraForm.model,
|
|
|
- channelNo: cameraForm.channelNo,
|
|
|
- remark: cameraForm.remark,
|
|
|
- enabled: cameraForm.enabled
|
|
|
- }
|
|
|
- if (cameraForm.password) {
|
|
|
- data.password = cameraForm.password
|
|
|
- }
|
|
|
- const res = await adminUpdateCamera(data)
|
|
|
- if (res.success) {
|
|
|
- ElMessage.success(isEditCamera.value ? '更新成功' : '绑定成功')
|
|
|
- cameraDialogVisible.value = false
|
|
|
- loadCameraList()
|
|
|
+ if (isEditCamera.value) {
|
|
|
+ // 编辑模式:更新摄像头信息
|
|
|
+ if (!currentCamera.value) {
|
|
|
+ ElMessage.error('摄像头信息错误')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const data: CameraUpdateRequest = {
|
|
|
+ id: currentCamera.value.id,
|
|
|
+ name: cameraForm.name,
|
|
|
+ port: cameraForm.port,
|
|
|
+ username: cameraForm.username,
|
|
|
+ brand: cameraForm.brand,
|
|
|
+ capability: cameraForm.capability,
|
|
|
+ lssId: currentLss.value?.lssId,
|
|
|
+ rtspUrl: cameraForm.rtspUrl,
|
|
|
+ model: cameraForm.model,
|
|
|
+ channelNo: cameraForm.channelNo,
|
|
|
+ remark: cameraForm.remark,
|
|
|
+ enabled: cameraForm.enabled
|
|
|
+ }
|
|
|
+ if (cameraForm.password) {
|
|
|
+ data.password = cameraForm.password
|
|
|
+ }
|
|
|
+ const res = await adminUpdateCamera(data)
|
|
|
+ if (res.success) {
|
|
|
+ ElMessage.success('更新成功')
|
|
|
+ cameraDialogVisible.value = false
|
|
|
+ loadCameraList()
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.errMessage || '更新失败')
|
|
|
+ }
|
|
|
} else {
|
|
|
- ElMessage.error(res.errMessage || '操作失败')
|
|
|
+ // 新增模式:创建摄像头并绑定到当前 LSS
|
|
|
+ const data: CameraAddRequest = {
|
|
|
+ cameraId: cameraForm.cameraId,
|
|
|
+ name: cameraForm.name,
|
|
|
+ ip: cameraForm.ip,
|
|
|
+ port: cameraForm.port,
|
|
|
+ username: cameraForm.username,
|
|
|
+ password: cameraForm.password,
|
|
|
+ brand: cameraForm.brand,
|
|
|
+ capability: cameraForm.capability,
|
|
|
+ lssId: currentLss.value?.lssId,
|
|
|
+ rtspUrl: cameraForm.rtspUrl,
|
|
|
+ model: cameraForm.model,
|
|
|
+ channelNo: cameraForm.channelNo,
|
|
|
+ remark: cameraForm.remark
|
|
|
+ }
|
|
|
+ const res = await adminAddCamera(data)
|
|
|
+ if (res.success) {
|
|
|
+ ElMessage.success('添加成功')
|
|
|
+ cameraDialogVisible.value = false
|
|
|
+ loadCameraList()
|
|
|
+ } else {
|
|
|
+ ElMessage.error(res.errMessage || '添加失败')
|
|
|
+ }
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.error('保存摄像头失败', error)
|
|
|
@@ -897,6 +1027,72 @@ onMounted(() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// LSS 编辑抽屉样式
|
|
|
+.lss-edit-drawer {
|
|
|
+ :deep(.el-drawer__body) {
|
|
|
+ padding: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.drawer-content {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.drawer-header {
|
|
|
+ flex-shrink: 0;
|
|
|
+ padding: 16px 20px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #303133;
|
|
|
+ border-bottom: 1px solid #e5e7eb;
|
|
|
+}
|
|
|
+
|
|
|
+.drawer-body {
|
|
|
+ flex: 1;
|
|
|
+ overflow-y: auto;
|
|
|
+ padding: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.lss-detail-form {
|
|
|
+ .form-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ margin-bottom: 16px;
|
|
|
+
|
|
|
+ .form-label {
|
|
|
+ flex-shrink: 0;
|
|
|
+ width: 80px;
|
|
|
+ line-height: 32px;
|
|
|
+ color: #606266;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-value {
|
|
|
+ line-height: 32px;
|
|
|
+ color: #303133;
|
|
|
+ font-size: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input {
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.drawer-footer {
|
|
|
+ flex-shrink: 0;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ padding: 12px 20px;
|
|
|
+ border-top: 1px solid #e5e7eb;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+
|
|
|
// 表格样式
|
|
|
:deep(.el-table) {
|
|
|
--el-table-row-hover-bg-color: #f0f0ff;
|