| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="设备名称"> |
| | | <el-input |
| | | v-model="filters.deviceName" |
| | | style="width: 200px" |
| | | placeholder="请输入设备名称" |
| | | clearable |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="规格型号"> |
| | | <el-input |
| | | v-model="filters.deviceModel" |
| | | style="width: 200px" |
| | | placeholder="请输入规格型号" |
| | | clearable |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="供应商"> |
| | | <el-input |
| | | v-model="filters.supplierName" |
| | | style="width: 200px" |
| | | placeholder="请输入供应商" |
| | | clearable |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="录入日期:"> |
| | | <el-date-picker v-model="filters.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" |
| | | placeholder="请选择" clearable @change="changeDaterange" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">搜索</el-button> |
| | | <el-button @click="resetFilters">重置</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button type="primary" @click="add" icon="Plus"> 新增 </el-button> |
| | | <el-button type="info" @click="handleImport" icon="Upload">导入</el-button> |
| | | <el-button @click="handleOut" icon="download">导出</el-button> |
| | | <el-button |
| | | type="danger" |
| | | icon="Delete" |
| | | :disabled="multipleList.length <= 0" |
| | | @click="deleteRow(multipleList.map((item) => item.id))" |
| | | > |
| | | 批量删除 |
| | | <div class="area-view"> |
| | | <!-- 左侧区域树 --> |
| | | <div class="area-left"> |
| | | <div class="area-left-header"> |
| | | <el-button type="primary" @click="openAreaDialog('add')" icon="Plus"> |
| | | 新增区域 |
| | | </el-button> |
| | | </div> |
| | | <div |
| | | class="all-device-node" |
| | | :class="{ active: currentAreaId === null }" |
| | | @click="handleAllDeviceClick" |
| | | > |
| | | 全部设备 |
| | | </div> |
| | | <el-tree |
| | | ref="areaTreeRef" |
| | | v-loading="areaTreeLoading" |
| | | :data="areaTree" |
| | | node-key="id" |
| | | :props="{ label: 'label', children: 'children' }" |
| | | :expand-on-click-node="false" |
| | | default-expand-all |
| | | draggable |
| | | highlight-current |
| | | :current-node-key="currentAreaId" |
| | | @node-click="handleAreaNodeClick" |
| | | @node-drop="handleAreaNodeDrop" |
| | | > |
| | | <template #default="{ node, data }"> |
| | | <div class="area-tree-node"> |
| | | <span class="area-node-label">{{ data.label }}</span> |
| | | <span class="area-node-count">{{ data.deviceCount ?? 0 }}</span> |
| | | <span class="area-node-actions"> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | size="small" |
| | | @click.stop="openAreaDialog('addChild', data)" |
| | | > |
| | | 子级 |
| | | </el-button> |
| | | <el-button |
| | | link |
| | | type="primary" |
| | | size="small" |
| | | @click.stop="openAreaDialog('edit', data)" |
| | | > |
| | | 编辑 |
| | | </el-button> |
| | | <el-button |
| | | link |
| | | type="danger" |
| | | size="small" |
| | | @click.stop="handleAreaDelete(node, data)" |
| | | > |
| | | 删除 |
| | | </el-button> |
| | | </span> |
| | | </div> |
| | | </template> |
| | | </el-tree> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | isSelection |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="changePage" |
| | | > |
| | | </PIMTable> |
| | | |
| | | <!-- 右侧设备列表 --> |
| | | <div class="area-right"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form-item label="设备名称"> |
| | | <el-input |
| | | v-model="filters.deviceName" |
| | | style="width: 200px" |
| | | placeholder="请输入设备名称" |
| | | clearable |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="规格型号"> |
| | | <el-input |
| | | v-model="filters.deviceModel" |
| | | style="width: 200px" |
| | | placeholder="请输入规格型号" |
| | | clearable |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="供应商"> |
| | | <el-input |
| | | v-model="filters.supplierName" |
| | | style="width: 200px" |
| | | placeholder="请输入供应商" |
| | | clearable |
| | | @change="getTableData" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="录入日期:"> |
| | | <el-date-picker |
| | | v-model="filters.entryDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | placeholder="请选择" |
| | | clearable |
| | | @change="changeDaterange" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">搜索</el-button> |
| | | <el-button @click="handleReset">重置</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button type="primary" @click="add" icon="Plus"> 新增 </el-button> |
| | | <el-button type="info" @click="handleImport" icon="Upload">导入</el-button> |
| | | <el-button @click="handleOut" icon="download">导出</el-button> |
| | | <el-button |
| | | type="danger" |
| | | icon="Delete" |
| | | :disabled="multipleList.length <= 0" |
| | | @click="deleteRow(multipleList.map((item) => item.id))" |
| | | > |
| | | 批量删除 |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | isSelection |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="changePage" |
| | | > |
| | | </PIMTable> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <Modal ref="modalRef" @success="getTableData"></Modal> |
| | | <el-dialog v-model="qrDialogVisible" title="二维码" width="300px" draggable> |
| | | <div style="text-align:center;"> |
| | | <img :src="qrCodeUrl" alt="二维码" style="width:200px;height:200px;" /> |
| | | <div style="margin:10px 0;"> |
| | | <div style="text-align: center"> |
| | | <img :src="qrCodeUrl" alt="二维码" style="width: 200px; height: 200px" /> |
| | | <div style="margin: 10px 0"> |
| | | <el-button type="primary" @click="downloadQRCode">下载二维码图片</el-button> |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | | |
| | | |
| | | <!-- 导入对话框 --> |
| | | <el-dialog :title="upload.title" v-model="upload.open" width="400px" append-to-body> |
| | | <el-upload |
| | |
| | | <template #tip> |
| | | <div class="el-upload__tip text-center"> |
| | | <span>仅允许导入xls、xlsx格式文件。</span> |
| | | <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline; margin-left: 5px;" @click="importTemplate">下载模板</el-link> |
| | | <el-link |
| | | type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline; margin-left: 5px" |
| | | @click="importTemplate" |
| | | > |
| | | 下载模板 |
| | | </el-link> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | |
| | | <el-descriptions-item label="设备品牌">{{ detailData.deviceBrand }}</el-descriptions-item> |
| | | <el-descriptions-item label="设备类型">{{ detailData.type }}</el-descriptions-item> |
| | | <el-descriptions-item label="供应商">{{ detailData.supplierName }}</el-descriptions-item> |
| | | <el-descriptions-item label="所属区域">{{ detailData.areaName }}</el-descriptions-item> |
| | | <el-descriptions-item label="存放位置">{{ detailData.storageLocation }}</el-descriptions-item> |
| | | <el-descriptions-item label="单位">{{ detailData.unit }}</el-descriptions-item> |
| | | <el-descriptions-item label="数量">{{ detailData.number }}</el-descriptions-item> |
| | |
| | | <el-descriptions-item label="税率(%)">{{ detailData.taxRate }}</el-descriptions-item> |
| | | <el-descriptions-item label="不含税总价">{{ detailData.unTaxIncludingPriceTotal }}</el-descriptions-item> |
| | | <el-descriptions-item label="录入日期">{{ detailData.createTime }}</el-descriptions-item> |
| | | <el-descriptions-item label="预计运行时间">{{ detailData.planRuntimeTime ? dayjs(detailData.planRuntimeTime).format('YYYY-MM-DD') : '' }}</el-descriptions-item> |
| | | <el-descriptions-item label="预计运行时间">{{ |
| | | detailData.planRuntimeTime ? dayjs(detailData.planRuntimeTime).format('YYYY-MM-DD') : '' |
| | | }}</el-descriptions-item> |
| | | <el-descriptions-item label="设备图片" :span="2"> |
| | | <div v-if="detailData.storageBlobVOs && detailData.storageBlobVOs.length > 0" style="display: flex; gap: 10px; flex-wrap: wrap;"> |
| | | <el-image |
| | | v-for="(file, index) in detailData.storageBlobVOs" |
| | | :key="index" |
| | | :src="file.previewURL || file.url" |
| | | :preview-src-list="detailData.storageBlobVOs.map(u => u.previewURL || u.url)" |
| | | <div |
| | | v-if="detailData.storageBlobVOs && detailData.storageBlobVOs.length > 0" |
| | | style="display: flex; gap: 10px; flex-wrap: wrap" |
| | | > |
| | | <el-image |
| | | v-for="(file, index) in detailData.storageBlobVOs" |
| | | :key="index" |
| | | :src="file.previewURL || file.url" |
| | | :preview-src-list="detailData.storageBlobVOs.map((u) => u.previewURL || u.url)" |
| | | :initial-index="index" |
| | | style="width: 100px; height: 100px" |
| | | fit="cover" |
| | | style="width: 100px; height: 100px" |
| | | fit="cover" |
| | | /> |
| | | </div> |
| | | <span v-else>无图片</span> |
| | |
| | | <el-button @click="detailDialogVisible = false">关闭</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- 区域新增/编辑弹窗 --> |
| | | <el-dialog |
| | | v-model="areaDialogVisible" |
| | | :title="areaDialogTitle" |
| | | width="420px" |
| | | draggable |
| | | @closed="areaFormRef && areaFormRef.resetFields()" |
| | | > |
| | | <el-form :model="areaForm" :rules="areaRules" ref="areaFormRef" label-width="90px"> |
| | | <el-form-item label="上级区域" prop="parentId"> |
| | | <el-tree-select |
| | | v-model="areaForm.parentId" |
| | | :data="areaTree" |
| | | node-key="id" |
| | | :props="{ label: 'label', children: 'children' }" |
| | | check-strictly |
| | | clearable |
| | | placeholder="不选则为根区域" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="区域名称" prop="name"> |
| | | <el-input v-model="areaForm.name" placeholder="请输入区域/车间/位置名称" clearable /> |
| | | </el-form-item> |
| | | <el-form-item label="排序" prop="sort"> |
| | | <el-input-number v-model="areaForm.sort" :min="0" style="width: 100%" placeholder="可选" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button type="primary" @click="submitAreaForm">确定</el-button> |
| | | <el-button @click="areaDialogVisible = false">取消</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { usePaginationApi } from "@/hooks/usePaginationApi"; |
| | | // import { Search } from "@element-plus/icons-vue"; |
| | | import { getLedgerPage, delLedger, getLedgerById } from "@/api/equipmentManagement/ledger"; |
| | | import { onMounted, getCurrentInstance, ref, reactive } from "vue"; |
| | | import { |
| | | getLedgerPage, |
| | | delLedger, |
| | | getLedgerById, |
| | | } from "@/api/equipmentManagement/ledger"; |
| | | import { |
| | | getDeviceAreaTree, |
| | | addDeviceArea, |
| | | editDeviceArea, |
| | | delDeviceArea, |
| | | } from "@/api/equipmentManagement/area"; |
| | | import { onMounted, getCurrentInstance, ref, reactive, computed } from "vue"; |
| | | import Modal from "./Modal.vue"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import { UploadFilled } from "@element-plus/icons-vue"; |
| | |
| | | const detailDialogVisible = ref(false); |
| | | const detailData = ref({}); |
| | | |
| | | // 区域相关 |
| | | const areaTree = ref([]); |
| | | const areaTreeLoading = ref(false); |
| | | const areaTreeRef = ref(); |
| | | const currentAreaId = ref(null); |
| | | const areaDialogVisible = ref(false); |
| | | const areaDialogType = ref("add"); |
| | | const areaFormRef = ref(); |
| | | const areaForm = reactive({ |
| | | id: undefined, |
| | | name: "", |
| | | parentId: null, |
| | | sort: 0, |
| | | }); |
| | | const areaRules = { |
| | | name: [{ required: true, message: "请输入区域名称", trigger: "blur" }], |
| | | }; |
| | | const areaDialogTitle = computed(() => { |
| | | if (areaDialogType.value === "edit") return "编辑区域"; |
| | | if (areaDialogType.value === "addChild") return "新增子区域"; |
| | | return "新增区域"; |
| | | }); |
| | | |
| | | // 导入相关 |
| | | const uploadRef = ref(null) |
| | | const uploadRef = ref(null); |
| | | const upload = reactive({ |
| | | // 是否显示弹出层 |
| | | open: false, |
| | | // 弹出层标题 |
| | | title: "", |
| | | // 是否禁用上传 |
| | | isUploading: false, |
| | | // 设置上传的请求头部 |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // 上传的地址 |
| | | url: import.meta.env.VITE_APP_BASE_API + "/device/ledger/import" |
| | | }) |
| | | url: import.meta.env.VITE_APP_BASE_API + "/device/ledger/import", |
| | | }); |
| | | |
| | | const { |
| | | filters, |
| | |
| | | supplierName: undefined, |
| | | entryDateStart: undefined, |
| | | entryDateEnd: undefined, |
| | | areaId: undefined, |
| | | }, |
| | | [ |
| | | { |
| | |
| | | { |
| | | label: "设备类型", |
| | | prop: "type", |
| | | }, |
| | | { |
| | | label: "所属区域", |
| | | prop: "areaName", |
| | | }, |
| | | { |
| | | label: "供应商", |
| | |
| | | label: "录入日期", |
| | | prop: "createTime", |
| | | formatData: (v) => { |
| | | if (!v) return ''; |
| | | // 如果包含时分秒,只取日期部分 |
| | | if (v.includes(' ')) { |
| | | return v.split(' ')[0]; |
| | | if (!v) return ""; |
| | | if (v.includes(" ")) { |
| | | return v.split(" ")[0]; |
| | | } |
| | | return v; |
| | | }, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "操作", |
| | | align: "center", |
| | | fixed: 'right', |
| | | width: 180, |
| | | operation: [ |
| | | { |
| | | dataType: "action", |
| | | label: "操作", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 180, |
| | | operation: [ |
| | | { |
| | | name: "详情", |
| | | clickFun: (row) => { |
| | | handleDetail(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "编辑", |
| | | clickFun: (row) => { |
| | | edit(row.id) |
| | | }, |
| | | }, |
| | | { |
| | | name: "二维码", |
| | | clickFun: (row) => { |
| | | showQRCode(row) |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | name: "编辑", |
| | | clickFun: (row) => { |
| | | edit(row.id); |
| | | }, |
| | | }, |
| | | { |
| | | name: "二维码", |
| | | clickFun: (row) => { |
| | | showQRCode(row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ] |
| | | ); |
| | | |
| | | // 加载区域树 |
| | | const getAreaTree = () => { |
| | | areaTreeLoading.value = true; |
| | | getDeviceAreaTree() |
| | | .then((res) => { |
| | | areaTree.value = res.data || []; |
| | | }) |
| | | .finally(() => { |
| | | areaTreeLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | // 重置搜索与区域筛选 |
| | | const handleReset = () => { |
| | | currentAreaId.value = null; |
| | | resetFilters(); |
| | | }; |
| | | |
| | | // 点击"全部设备" |
| | | const handleAllDeviceClick = () => { |
| | | currentAreaId.value = null; |
| | | filters.areaId = undefined; |
| | | getTableData(); |
| | | }; |
| | | |
| | | // 点击区域节点 |
| | | const handleAreaNodeClick = (data) => { |
| | | currentAreaId.value = data.id; |
| | | filters.areaId = data.id; |
| | | getTableData(); |
| | | }; |
| | | |
| | | // 拖拽调整父子关系 |
| | | const handleAreaNodeDrop = (draggingNode, dropNode, dropType) => { |
| | | const node = draggingNode.data; |
| | | let parentId = null; |
| | | if (dropNode && dropType === "inner") { |
| | | parentId = dropNode.data.id; |
| | | } else if (dropNode) { |
| | | parentId = dropNode.data.parentId ?? null; |
| | | } else { |
| | | parentId = null; |
| | | } |
| | | if (parentId === node.id) { |
| | | proxy.$modal.msgWarning("不能将区域挂载到自身"); |
| | | getAreaTree(); |
| | | return; |
| | | } |
| | | editDeviceArea({ |
| | | id: node.id, |
| | | name: node.label, |
| | | parentId, |
| | | sort: node.sort, |
| | | }) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("调整成功"); |
| | | getAreaTree(); |
| | | }) |
| | | .catch(() => { |
| | | getAreaTree(); |
| | | }); |
| | | }; |
| | | |
| | | // 打开区域弹窗 |
| | | const openAreaDialog = (type, data) => { |
| | | areaDialogType.value = type; |
| | | areaForm.id = undefined; |
| | | areaForm.name = ""; |
| | | areaForm.parentId = null; |
| | | areaForm.sort = 0; |
| | | if (type === "addChild" && data) { |
| | | areaForm.parentId = data.id; |
| | | } else if (type === "edit" && data) { |
| | | areaForm.id = data.id; |
| | | areaForm.name = data.label; |
| | | areaForm.parentId = data.parentId ?? null; |
| | | areaForm.sort = data.sort ?? 0; |
| | | } |
| | | areaDialogVisible.value = true; |
| | | }; |
| | | |
| | | // 提交区域表单 |
| | | const submitAreaForm = () => { |
| | | if (!areaFormRef.value) return; |
| | | areaFormRef.value.validate((valid) => { |
| | | if (!valid) return; |
| | | const payload = { |
| | | name: areaForm.name, |
| | | parentId: areaForm.parentId ?? null, |
| | | sort: areaForm.sort ?? 0, |
| | | }; |
| | | const api = |
| | | areaDialogType.value === "edit" |
| | | ? editDeviceArea({ ...payload, id: areaForm.id }) |
| | | : addDeviceArea(payload); |
| | | api |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("操作成功"); |
| | | areaDialogVisible.value = false; |
| | | getAreaTree(); |
| | | }) |
| | | .catch(() => {}); |
| | | }); |
| | | }; |
| | | |
| | | // 删除区域 |
| | | const handleAreaDelete = (node, data) => { |
| | | ElMessageBox.confirm("确认删除该区域吗?", "提示", { |
| | | confirmButtonText: "确定", |
| | | cancelButtonText: "取消", |
| | | type: "warning", |
| | | }) |
| | | .then(() => delDeviceArea(data.id)) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("删除成功"); |
| | | if (currentAreaId.value === data.id) { |
| | | currentAreaId.value = null; |
| | | filters.areaId = undefined; |
| | | } |
| | | getAreaTree(); |
| | | getTableData(); |
| | | }) |
| | | .catch(() => {}); |
| | | }; |
| | | |
| | | // 多选后做什么 |
| | | const handleSelectionChange = (selectionList) => { |
| | |
| | | }; |
| | | const changePage = ({ page, limit }) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | | pagination.pageSize = limit; |
| | | onCurrentChange(page); |
| | | }; |
| | | const deleteRow = (id) => { |
| | |
| | | }; |
| | | |
| | | const showQRCode = async (row) => { |
| | | // 直接使用URL,不要用JSON.stringify包装 |
| | | const qrContent = proxy.javaApi + '/device-info?deviceId=' + row.id; |
| | | const qrContent = proxy.javaApi + "/device-info?deviceId=" + row.id; |
| | | const qrDataUrl = await QRCode.toDataURL(qrContent, { width: 200, margin: 2 }); |
| | | |
| | | // 创建canvas合成带名称的二维码图片 |
| | | const canvas = document.createElement('canvas'); |
| | | const ctx = canvas.getContext('2d'); |
| | | |
| | | const canvas = document.createElement("canvas"); |
| | | const ctx = canvas.getContext("2d"); |
| | | const qrSize = 200; |
| | | const textHeight = 30; |
| | | const padding = 10; |
| | | canvas.width = qrSize + padding * 2; |
| | | canvas.height = qrSize + textHeight + padding * 2; |
| | | |
| | | // 填充白色背景 |
| | | ctx.fillStyle = '#ffffff'; |
| | | |
| | | ctx.fillStyle = "#ffffff"; |
| | | ctx.fillRect(0, 0, canvas.width, canvas.height); |
| | | |
| | | // 绘制二维码 |
| | | |
| | | const qrImg = new Image(); |
| | | qrImg.src = qrDataUrl; |
| | | await new Promise((resolve) => { qrImg.onload = resolve; }); |
| | | await new Promise((resolve) => { |
| | | qrImg.onload = resolve; |
| | | }); |
| | | ctx.drawImage(qrImg, padding, padding, qrSize, qrSize); |
| | | |
| | | // 绘制设备名称 |
| | | ctx.fillStyle = '#333333'; |
| | | ctx.font = 'bold 14px Arial'; |
| | | ctx.textAlign = 'center'; |
| | | ctx.fillText(row.deviceName || '', canvas.width / 2, qrSize + padding + 20); |
| | | |
| | | qrCodeUrl.value = canvas.toDataURL('image/png'); |
| | | |
| | | ctx.fillStyle = "#333333"; |
| | | ctx.font = "bold 14px Arial"; |
| | | ctx.textAlign = "center"; |
| | | ctx.fillText(row.deviceName || "", canvas.width / 2, qrSize + padding + 20); |
| | | |
| | | qrCodeUrl.value = canvas.toDataURL("image/png"); |
| | | qrRowData.value = row; |
| | | qrDialogVisible.value = true; |
| | | }; |
| | |
| | | a.click(); |
| | | }; |
| | | |
| | | // 导入按钮操作 |
| | | const handleImport = () => { |
| | | upload.title = "设备台账导入" |
| | | upload.open = true |
| | | } |
| | | upload.title = "设备台账导入"; |
| | | upload.open = true; |
| | | }; |
| | | |
| | | // 下载模板操作 |
| | | const importTemplate = () => { |
| | | proxy.download("/device/ledger/downloadTemplate", {}, `设备台账导入模板_${new Date().getTime()}.xlsx`) |
| | | } |
| | | proxy.download( |
| | | "/device/ledger/downloadTemplate", |
| | | {}, |
| | | `设备台账导入模板_${new Date().getTime()}.xlsx` |
| | | ); |
| | | }; |
| | | |
| | | // 文件上传中处理 |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true |
| | | } |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | // 文件上传成功处理 |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.open = false |
| | | upload.isUploading = false |
| | | proxy.$refs["uploadRef"].handleRemove(file) |
| | | proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true }) |
| | | getTableData() |
| | | } |
| | | upload.open = false; |
| | | upload.isUploading = false; |
| | | proxy.$refs["uploadRef"].handleRemove(file); |
| | | proxy.$alert( |
| | | "<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + |
| | | response.msg + |
| | | "</div>", |
| | | "导入结果", |
| | | { dangerouslyUseHTMLString: true } |
| | | ); |
| | | getTableData(); |
| | | }; |
| | | |
| | | // 提交上传文件 |
| | | const submitFileForm = () => { |
| | | proxy.$refs["uploadRef"].submit() |
| | | } |
| | | proxy.$refs["uploadRef"].submit(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getAreaTree(); |
| | | getTableData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .area-view { |
| | | display: flex; |
| | | } |
| | | .area-left { |
| | | width: 320px; |
| | | flex-shrink: 0; |
| | | padding: 16px; |
| | | background: #ffffff; |
| | | margin-right: 16px; |
| | | } |
| | | .area-left-header { |
| | | margin-bottom: 10px; |
| | | } |
| | | .all-device-node { |
| | | padding: 8px 12px; |
| | | cursor: pointer; |
| | | font-size: 14px; |
| | | border-radius: 4px; |
| | | margin-bottom: 8px; |
| | | } |
| | | .all-device-node:hover { |
| | | background: #f5f7fa; |
| | | } |
| | | .all-device-node.active { |
| | | background: #ecf5ff; |
| | | color: #409eff; |
| | | } |
| | | .area-tree-node { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | font-size: 14px; |
| | | padding-right: 4px; |
| | | } |
| | | .area-node-count { |
| | | color: #909399; |
| | | font-size: 12px; |
| | | margin-left: 6px; |
| | | } |
| | | .area-node-actions { |
| | | display: none; |
| | | } |
| | | .area-tree-node:hover .area-node-actions { |
| | | display: inline-flex; |
| | | } |
| | | .area-right { |
| | | flex: 1; |
| | | min-width: 0; |
| | | padding: 16px; |
| | | background: #ffffff; |
| | | } |
| | | .table_list { |
| | | margin-top: unset; |
| | | } |