|
@@ -0,0 +1,699 @@
|
|
|
+<template>
|
|
|
+<<<<<<< HEAD
|
|
|
+ <div class="camera-page">
|
|
|
+ <!-- 顶部标签页 -->
|
|
|
+ <div class="camera-header" v-if="Object.values(oldTotalObj).reduce((t,c) => t+c, 0)">
|
|
|
+ <el-tabs v-model="tabActive" @tab-click="handleTabClick">
|
|
|
+ <el-tab-pane
|
|
|
+ v-for="item in tabList"
|
|
|
+ :key="item.id"
|
|
|
+ :label="`${item.name}(${totalObj[item.id]})`"
|
|
|
+ :name="item.id"
|
|
|
+ v-show="oldTotalObj[item.id]"
|
|
|
+ />
|
|
|
+ </el-tabs>
|
|
|
+
|
|
|
+ <!-- 操作栏 -->
|
|
|
+ <div class="main-list">
|
|
|
+ <div class="btns">
|
|
|
+ <!-- 全选 -->
|
|
|
+ <div v-show="isImgType" class="all-select" :class="{disable: !cameraList.length}">
|
|
|
+ <el-checkbox
|
|
|
+ v-model="selectAll"
|
|
|
+ @change="handleSelectAll"
|
|
|
+ :disabled="!cameraList.length"
|
|
|
+ >
|
|
|
+ 全选
|
|
|
+ </el-checkbox>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 协作按钮 -->
|
|
|
+ <el-button
|
|
|
+ v-if="tabActive !== 0 && selectedArr.length > 0"
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ @click="multCop"
|
|
|
+ >
|
|
|
+ 协作
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ <!-- 解绑按钮 -->
|
|
|
+ <el-button
|
|
|
+ v-if="tabActive !== 0 && selectedArr.length > 0"
|
|
|
+ type="danger"
|
|
|
+ size="small"
|
|
|
+ @click="multDel"
|
|
|
+ >
|
|
|
+ 解绑
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="rig-con">
|
|
|
+ <!-- 添加设备 -->
|
|
|
+ <el-button type="primary" size="small" @click="addDevice">
|
|
|
+ 添加设备
|
|
|
+ </el-button>
|
|
|
+
|
|
|
+ <!-- 视图切换 -->
|
|
|
+ <template v-if="tabActive !== 0">
|
|
|
+ <el-button-group class="view-toggle">
|
|
|
+ <el-button
|
|
|
+ :type="isImgType ? 'primary' : 'default'"
|
|
|
+ size="small"
|
|
|
+ @click="changeType(true)"
|
|
|
+ >
|
|
|
+ 卡片
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ :type="!isImgType ? 'primary' : 'default'"
|
|
|
+ size="small"
|
|
|
+ @click="changeType(false)"
|
|
|
+ >
|
|
|
+ 列表
|
|
|
+ </el-button>
|
|
|
+ </el-button-group>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 搜索框 -->
|
|
|
+ <el-input
|
|
|
+ v-model="searchKey"
|
|
|
+ placeholder="搜索设备ID"
|
|
|
+ class="search-input"
|
|
|
+ @keyup.enter="handleSearch"
|
|
|
+ clearable
|
|
|
+ >
|
|
|
+ <template #prepend>
|
|
|
+ <el-select v-model="selectedType" placeholder="选择类型" style="width: 100px">
|
|
|
+ <el-option
|
|
|
+ v-for="item in searchTypeList"
|
|
|
+ :key="item.value"
|
|
|
+ :label="item.name"
|
|
|
+ :value="item"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </template>
|
|
|
+ <template #append>
|
|
|
+ <el-button @click="handleSearch">
|
|
|
+ 搜索
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-input>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 内容区域 -->
|
|
|
+ <template>
|
|
|
+ <!-- 卡片视图 -->
|
|
|
+ <el-row :gutter="20" class="camera-cards" v-show="isImgType || tabActive === 0">
|
|
|
+ <template v-if="!loading">
|
|
|
+ <el-col
|
|
|
+ :span="8"
|
|
|
+ v-for="(item, index) in cameraList"
|
|
|
+ :key="index"
|
|
|
+ class="camera-item"
|
|
|
+ >
|
|
|
+ <div class="card-wrapper">
|
|
|
+ <el-checkbox
|
|
|
+ v-model="item.selected"
|
|
|
+ @change="handleItemSelect(item)"
|
|
|
+ class="item-checkbox"
|
|
|
+ />
|
|
|
+ <camera-item
|
|
|
+ :item="item"
|
|
|
+ :tabActive="tabActive"
|
|
|
+ @handleCooperation="handleCooperation"
|
|
|
+ @unbind="unbind"
|
|
|
+ @renew="handleRenew"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </template>
|
|
|
+ </el-row>
|
|
|
+
|
|
|
+ <!-- 列表视图 -->
|
|
|
+ <table-list
|
|
|
+ v-show="!(isImgType || tabActive === 0)"
|
|
|
+ ref="tableRef"
|
|
|
+ @selection-change="selectHandle"
|
|
|
+ @unbind="unbind"
|
|
|
+ @cooperation="handleCooperation"
|
|
|
+ @renew="handleRenew"
|
|
|
+ :header="tabHeader"
|
|
|
+ :selection="cameraList.length > 0"
|
|
|
+ :data="cameraList"
|
|
|
+ :show-view-toggle="false"
|
|
|
+ class="table-list"
|
|
|
+ >
|
|
|
+ <template #item="{ data, type, canclick, item }">
|
|
|
+ <template v-if="canclick">
|
|
|
+ <span
|
|
|
+ class="table-btn"
|
|
|
+ @click="handleCooperation(item)"
|
|
|
+ v-if="item.status !== 0"
|
|
|
+ >
|
|
|
+ 协作列表
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <span class="info-wrapper">
|
|
|
+ <span class="table-btn" @mouseover="showInfo = item.id" @mouseout="showInfo = null">
|
|
|
+ 详细信息
|
|
|
+ </span>
|
|
|
+ <div
|
|
|
+ v-show="showInfo === item.id"
|
|
|
+ class="info-tooltip"
|
|
|
+ >
|
|
|
+ <div class="info-content">
|
|
|
+ <span class="th">场景数量</span><span class="th">最后时间</span>
|
|
|
+ <span class="td">{{ item.sceneNum || '-' }}</span><span class="td">{{ item.lastTime || '-' }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <span v-else-if="type === 'image'" class="flex-avatar">
|
|
|
+ <span v-if="isMember(item)" class="vip-icon"></span>
|
|
|
+ <span v-else-if="isExpiredMember(item)" class="vip-icon vip-expired-icon"></span>
|
|
|
+ {{ item.snCode }}
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <span v-else-if="type === 'qingkuang'">
|
|
|
+ <span v-if="item.usedSpaceStr && item.totalSpaceStr && item.totalSpaceStr != '0B'">
|
|
|
+ {{ item.usedSpaceStr }}{{ isMember(item) ? "" : ` / ${item.totalSpaceStr}` }}
|
|
|
+ </span>
|
|
|
+ <span v-else>--</span>
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <span v-else-if="type === 'spaceEndStr'">
|
|
|
+ {{ item.spaceEndStr || "--" }}
|
|
|
+ <span v-if="isExpired(item)" class="expired-icon" @mouseover="showCtrls = item.id" @mouseout="showCtrls = null">
|
|
|
+ ⚠️
|
|
|
+ <div v-show="showCtrls === item.id" class="expired-tooltip">
|
|
|
+ <p>{{ isExpired(item) ? '会员已过期' : '会员即将过期' }}</p>
|
|
|
+ <div class="ctrls-w">
|
|
|
+ <el-button size="small" @click="showCtrls = null">取消</el-button>
|
|
|
+ <el-button size="small" type="primary" @click="handleRenew(item)">续费</el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </span>
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <span v-else>{{ data || "-" }}</span>
|
|
|
+ </template>
|
|
|
+ </table-list>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <!-- 空状态 -->
|
|
|
+ <div class="empty-state" v-if="!loading && !total">
|
|
|
+ <el-empty description="暂无数据">
|
|
|
+ <template v-if="!Object.values(oldTotalObj).reduce((t,c) => t+c, 0)">
|
|
|
+ <el-button type="primary" @click="addDevice">添加设备</el-button>
|
|
|
+ </template>
|
|
|
+ </el-empty>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 分页 -->
|
|
|
+ <div class="pagination-wrapper" v-if="total">
|
|
|
+ <el-pagination
|
|
|
+ v-model:current-page="currentPage"
|
|
|
+ v-model:page-size="pageSize"
|
|
|
+ :page-sizes="[9, 18, 36, 72]"
|
|
|
+ :total="total"
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ @size-change="handleSizeChange"
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 绑定设备弹窗 -->
|
|
|
+ <el-dialog v-model="showBinding" title="绑定设备" width="600px">
|
|
|
+ <div>绑定设备功能</div>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="showBinding = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="handleBindingSuccess">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <!-- 续费弹窗 -->
|
|
|
+ <el-dialog v-model="showRenew" title="会员续费" width="600px">
|
|
|
+ <div>会员续费功能</div>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="showRenew = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="handleRenewSuccess">确定</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+=======
|
|
|
+ <div class="pcPage">
|
|
|
+ <h-icon class="icon" type="sousuo" />
|
|
|
+>>>>>>> master
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+import { ref, computed, onMounted, watch, nextTick } from 'vue'
|
|
|
+import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
+import TableList from '@/components/tableList/index.vue'
|
|
|
+
|
|
|
+// 静态数据
|
|
|
+const tabList = ref([
|
|
|
+ { id: 0, name: '协作设备' },
|
|
|
+ { id: 4, name: '我的设备' },
|
|
|
+ { id: 10, name: '共享设备' },
|
|
|
+ { id: 11, name: '租赁设备' }
|
|
|
+])
|
|
|
+
|
|
|
+const searchTypeList = ref([
|
|
|
+ { name: '设备编号', value: 2 },
|
|
|
+ { name: '用户名', value: 1 }
|
|
|
+])
|
|
|
+
|
|
|
+// 表格头部配置
|
|
|
+const tabHeader = ref([
|
|
|
+ { key: 'snCode', name: '设备编号', type: 'image', width: 200 },
|
|
|
+ { key: 'status', name: '状态', width: 100 },
|
|
|
+ { key: 'qingkuang', name: '使用情况', type: 'qingkuang', width: 150 },
|
|
|
+ { key: 'spaceEndStr', name: '到期时间', type: 'spaceEndStr', width: 150 },
|
|
|
+ { key: 'operation', name: '操作', canclick: true, width: 200 }
|
|
|
+])
|
|
|
+
|
|
|
+// 静态设备数据
|
|
|
+const mockCameraData = ref([
|
|
|
+ {
|
|
|
+ id: 1,
|
|
|
+ snCode: 'CAM001',
|
|
|
+ status: 1,
|
|
|
+ usedSpaceStr: '2.5GB',
|
|
|
+ totalSpaceStr: '10GB',
|
|
|
+ spaceEndStr: '2024-12-31',
|
|
|
+ spaceEndTime: '2024-12-31',
|
|
|
+ userIncrementId: 'inc_001',
|
|
|
+ sceneNum: 5,
|
|
|
+ lastTime: '2024-01-15 10:30:00',
|
|
|
+ selected: false
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 2,
|
|
|
+ snCode: 'CAM002',
|
|
|
+ status: 1,
|
|
|
+ usedSpaceStr: '5.2GB',
|
|
|
+ totalSpaceStr: '20GB',
|
|
|
+ spaceEndStr: '2024-11-30',
|
|
|
+ spaceEndTime: '2024-11-30',
|
|
|
+ userIncrementId: 'inc_002',
|
|
|
+ sceneNum: 8,
|
|
|
+ lastTime: '2024-01-14 15:20:00',
|
|
|
+ selected: false
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 3,
|
|
|
+ snCode: 'CAM003',
|
|
|
+ status: 0,
|
|
|
+ usedSpaceStr: '1.8GB',
|
|
|
+ totalSpaceStr: '5GB',
|
|
|
+ spaceEndStr: '2024-10-15',
|
|
|
+ spaceEndTime: '2024-10-15',
|
|
|
+ userIncrementId: null,
|
|
|
+ sceneNum: 3,
|
|
|
+ lastTime: '2024-01-13 09:15:00',
|
|
|
+ selected: false
|
|
|
+ }
|
|
|
+])
|
|
|
+
|
|
|
+// 响应式数据
|
|
|
+const tabActive = ref(4)
|
|
|
+const currentPage = ref(1)
|
|
|
+const pageSize = ref(9)
|
|
|
+const total = ref(0)
|
|
|
+const isImgType = ref(localStorage.getItem("isImgTypeForDevice") !== "false")
|
|
|
+const searchKey = ref("")
|
|
|
+const loading = ref(false)
|
|
|
+const selectedArr = ref([])
|
|
|
+const selectAll = ref(false)
|
|
|
+const showBinding = ref(false)
|
|
|
+const showRenew = ref(false)
|
|
|
+const reNewItem = ref({})
|
|
|
+const showCtrls = ref(null)
|
|
|
+const showInfo = ref(null)
|
|
|
+const selectedType = ref({ name: '设备编号', value: 2 })
|
|
|
+
|
|
|
+// 计算属性
|
|
|
+const totalObj = ref({
|
|
|
+ 0: 0,
|
|
|
+ 4: 0,
|
|
|
+ 10: 0,
|
|
|
+ 11: 0
|
|
|
+})
|
|
|
+
|
|
|
+const oldTotalObj = ref({
|
|
|
+ 0: 0,
|
|
|
+ 4: 0,
|
|
|
+ 10: 0,
|
|
|
+ 11: 0
|
|
|
+})
|
|
|
+
|
|
|
+const cameraList = computed(() => {
|
|
|
+ let filteredData = mockCameraData.value
|
|
|
+
|
|
|
+ // 根据当前标签页过滤
|
|
|
+ if (tabActive.value !== 4) {
|
|
|
+ // 这里可以根据不同的标签页显示不同的数据
|
|
|
+ filteredData = mockCameraData.value.filter(item => {
|
|
|
+ if (tabActive.value === 0) return item.status === 0 // 协作设备
|
|
|
+ if (tabActive.value === 10) return item.id % 2 === 0 // 共享设备
|
|
|
+ if (tabActive.value === 11) return item.id % 3 === 0 // 租赁设备
|
|
|
+ return true
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 搜索过滤
|
|
|
+ if (searchKey.value) {
|
|
|
+ filteredData = filteredData.filter(item => {
|
|
|
+ if (selectedType.value.value === 2) {
|
|
|
+ return item.snCode.toLowerCase().includes(searchKey.value.toLowerCase())
|
|
|
+ }
|
|
|
+ return true
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分页
|
|
|
+ const start = (currentPage.value - 1) * pageSize.value
|
|
|
+ const end = start + pageSize.value
|
|
|
+ total.value = filteredData.length
|
|
|
+
|
|
|
+ return filteredData.slice(start, end)
|
|
|
+})
|
|
|
+
|
|
|
+// 组件引用
|
|
|
+const tableRef = ref()
|
|
|
+
|
|
|
+// 方法
|
|
|
+const handleTabClick = (tab: any) => {
|
|
|
+ tabActive.value = parseInt(tab.name)
|
|
|
+ currentPage.value = 1
|
|
|
+ updateTotalCount()
|
|
|
+}
|
|
|
+
|
|
|
+const updateTotalCount = () => {
|
|
|
+ // 更新各个标签的数量
|
|
|
+ totalObj.value[0] = mockCameraData.value.filter(item => item.status === 0).length
|
|
|
+ totalObj.value[4] = mockCameraData.value.length
|
|
|
+ totalObj.value[10] = mockCameraData.value.filter(item => item.id % 2 === 0).length
|
|
|
+ totalObj.value[11] = mockCameraData.value.filter(item => item.id % 3 === 0).length
|
|
|
+
|
|
|
+ oldTotalObj.value = { ...totalObj.value }
|
|
|
+}
|
|
|
+
|
|
|
+const changeType = (status: boolean) => {
|
|
|
+ isImgType.value = status
|
|
|
+ localStorage.setItem("isImgTypeForDevice", status.toString())
|
|
|
+}
|
|
|
+
|
|
|
+const handleSearch = () => {
|
|
|
+ currentPage.value = 1
|
|
|
+}
|
|
|
+
|
|
|
+const handleSelectAll = (val: boolean) => {
|
|
|
+ cameraList.value.forEach(item => {
|
|
|
+ item.selected = val
|
|
|
+ })
|
|
|
+ updateSelectedArr()
|
|
|
+}
|
|
|
+
|
|
|
+const handleItemSelect = (item: any) => {
|
|
|
+ updateSelectedArr()
|
|
|
+
|
|
|
+ // 更新全选状态
|
|
|
+ selectAll.value = cameraList.value.every(item => item.selected)
|
|
|
+}
|
|
|
+
|
|
|
+const updateSelectedArr = () => {
|
|
|
+ selectedArr.value = cameraList.value.filter(item => item.selected)
|
|
|
+}
|
|
|
+
|
|
|
+const selectHandle = (selection: any[]) => {
|
|
|
+ selectedArr.value = selection
|
|
|
+}
|
|
|
+
|
|
|
+const multCop = () => {
|
|
|
+ if (selectedArr.value.length === 0) {
|
|
|
+ ElMessage.warning('请至少选择一个设备')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ ElMessage.success('批量协作功能')
|
|
|
+}
|
|
|
+
|
|
|
+const multDel = async () => {
|
|
|
+ if (selectedArr.value.length === 0) {
|
|
|
+ ElMessage.warning('请至少选择一个设备')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm('确定要解绑选中的设备吗?', '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ ElMessage.success('解绑成功')
|
|
|
+ selectedArr.value = []
|
|
|
+ } catch {
|
|
|
+ // 用户取消
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleCooperation = (item: any) => {
|
|
|
+ ElMessage.success(`设备 ${item.snCode} 协作功能`)
|
|
|
+}
|
|
|
+
|
|
|
+const unbind = async (item: any) => {
|
|
|
+ try {
|
|
|
+ await ElMessageBox.confirm(`确定要解绑设备 ${item.snCode} 吗?`, '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ })
|
|
|
+ ElMessage.success('解绑成功')
|
|
|
+ } catch {
|
|
|
+ // 用户取消
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const handleRenew = (item: any) => {
|
|
|
+ reNewItem.value = item
|
|
|
+ showRenew.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const addDevice = () => {
|
|
|
+ showBinding.value = true
|
|
|
+}
|
|
|
+
|
|
|
+const handleBindingSuccess = () => {
|
|
|
+ showBinding.value = false
|
|
|
+ ElMessage.success('绑定成功')
|
|
|
+ updateTotalCount()
|
|
|
+}
|
|
|
+
|
|
|
+const handleRenewSuccess = () => {
|
|
|
+ showRenew.value = false
|
|
|
+ ElMessage.success('续费成功')
|
|
|
+}
|
|
|
+
|
|
|
+const handleSizeChange = (val: number) => {
|
|
|
+ pageSize.value = val
|
|
|
+ currentPage.value = 1
|
|
|
+}
|
|
|
+
|
|
|
+const handleCurrentChange = (val: number) => {
|
|
|
+ currentPage.value = val
|
|
|
+}
|
|
|
+
|
|
|
+// 工具方法
|
|
|
+const isMember = (item: any) => {
|
|
|
+ return item.userIncrementId && !isExpired(item)
|
|
|
+}
|
|
|
+
|
|
|
+const isExpiredMember = (item: any) => {
|
|
|
+ return item.userIncrementId && isExpired(item)
|
|
|
+}
|
|
|
+
|
|
|
+const isExpired = (item: any) => {
|
|
|
+ if (!item.spaceEndTime) return false
|
|
|
+ const expired = Math.floor((new Date(item.spaceEndTime).getTime() - new Date().getTime()) / 86400000) + 1
|
|
|
+ return expired < 0
|
|
|
+}
|
|
|
+
|
|
|
+// 生命周期
|
|
|
+onMounted(() => {
|
|
|
+ updateTotalCount()
|
|
|
+})
|
|
|
+
|
|
|
+// 监听器
|
|
|
+watch(tabActive, () => {
|
|
|
+ selectedArr.value = []
|
|
|
+ selectAll.value = false
|
|
|
+})
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="less" scoped>
|
|
|
+.camera-page {
|
|
|
+ padding: 30px;
|
|
|
+ background: #fff;
|
|
|
+ min-height: calc(100vh - 60px);
|
|
|
+}
|
|
|
+
|
|
|
+.camera-header {
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ :deep(.el-tabs__header) {
|
|
|
+ margin-bottom: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .main-list {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 10px 0;
|
|
|
+ border-bottom: 1px solid #e5e5e5;
|
|
|
+
|
|
|
+ .btns {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+
|
|
|
+ .all-select {
|
|
|
+ &.disable {
|
|
|
+ opacity: 0.5;
|
|
|
+ pointer-events: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .rig-con {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+
|
|
|
+ .view-toggle {
|
|
|
+ margin: 0 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .search-input {
|
|
|
+ width: 300px;
|
|
|
+
|
|
|
+ :deep(.el-input-group__prepend) {
|
|
|
+ padding: 0;
|
|
|
+
|
|
|
+ .el-select {
|
|
|
+ border: none;
|
|
|
+
|
|
|
+ .el-input__wrapper {
|
|
|
+ box-shadow: none;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.camera-cards {
|
|
|
+ padding: 20px 0;
|
|
|
+
|
|
|
+ .camera-item {
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ .card-wrapper {
|
|
|
+ position: relative;
|
|
|
+ background: #f7f7f7;
|
|
|
+ padding: 20px;
|
|
|
+ border-radius: 8px;
|
|
|
+ min-height: 180px;
|
|
|
+
|
|
|
+ .item-checkbox {
|
|
|
+ position: absolute;
|
|
|
+ top: 10px;
|
|
|
+ left: 10px;
|
|
|
+ z-index: 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.table-list {
|
|
|
+ margin: 20px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-state {
|
|
|
+ padding: 60px 0;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.pagination-wrapper {
|
|
|
+ margin-top: 40px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+// 工具提示样式
|
|
|
+.info-wrapper, .expired-icon {
|
|
|
+ position: relative;
|
|
|
+
|
|
|
+ .info-tooltip, .expired-tooltip {
|
|
|
+ position: absolute;
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid #e5e5e5;
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 10px;
|
|
|
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
|
|
+ z-index: 1000;
|
|
|
+ min-width: 200px;
|
|
|
+ top: 100%;
|
|
|
+ left: 0;
|
|
|
+
|
|
|
+ .info-content {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr 1fr;
|
|
|
+ gap: 5px;
|
|
|
+
|
|
|
+ .th {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #323233;
|
|
|
+ }
|
|
|
+
|
|
|
+ .td {
|
|
|
+ color: #666;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .ctrls-w {
|
|
|
+ margin-top: 10px;
|
|
|
+ text-align: right;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.table-btn {
|
|
|
+ color: #15bec8;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ text-decoration: underline;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.flex-avatar {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ .vip-icon {
|
|
|
+ width: 16px;
|
|
|
+ height: 16px;
|
|
|
+ background: url('@/assets/images/information/avatar_vip.png') no-repeat center center;
|
|
|
+ background-size: cover;
|
|
|
+ margin-right: 5px;
|
|
|
+
|
|
|
+ &.vip-expired-icon {
|
|
|
+ opacity: 0.5;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|