Files
klp-oa/klp-ui/src/views/wms/warehouse/real.vue
2025-11-25 01:13:26 +08:00

890 lines
30 KiB
Vue

<template>
<div class="app-container warehouse-page">
<el-form
v-show="showSearch"
ref="queryForm"
:model="queryParams"
size="small"
:inline="true"
label-width="80px"
>
<el-form-item label="关键字">
<el-input
v-model="queryParams.keyword"
placeholder="输入编码/名称关键字"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
<el-form-item label="层级">
<el-select v-model="queryParams.level" placeholder="全部" clearable @change="handleQuery">
<el-option label="一级" :value="1" />
<el-option label="二级" :value="2" />
<el-option label="三级" :value="3" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="12" class="toolbar-row">
<el-col :xs="24" :sm="16" :md="16" class="toolbar-actions">
<el-button type="primary" icon="el-icon-plus" size="mini" @click="openQuickDialog()">
快速新增 1~3
</el-button>
<el-button type="success" icon="el-icon-plus" size="mini" @click="openCreateDialog()">
新增单级节点
</el-button>
<el-button type="warning" icon="el-icon-download" size="mini" @click="handleDownloadTemplate">
下载导入模板
</el-button>
<el-button type="danger" icon="el-icon-upload2" size="mini" @click="triggerImport">
导入
</el-button>
<el-button type="info" icon="el-icon-sort" size="mini" @click="toggleExpand">
{{ isExpandAll ? '折叠全部' : '展开全部' }}
</el-button>
<input
ref="importInput"
type="file"
accept=".xls,.xlsx"
style="display: none"
@change="handleImportChange"
/>
</el-col>
<el-col :xs="24" :sm="8" :md="8" class="toolbar-right">
<right-toolbar :showSearch.sync="showSearch" @queryTable="getTreeData"></right-toolbar>
</el-col>
</el-row>
<el-table
ref="treeTable"
v-loading="loading"
:data="filteredTreeData"
row-key="actualWarehouseId"
:default-expand-all="isExpandAll"
class="warehouse-table"
:tree-props="{ children: 'children' }"
>
<el-table-column label="层级" align="center">
<template slot-scope="scope">
<span >{{ getLevelLabel(scope.row.level) }}</span>
</template>
</el-table-column>
<el-table-column label="编码" prop="actualWarehouseCode" show-overflow-tooltip />
<el-table-column label="名称" prop="actualWarehouseName" show-overflow-tooltip />
<el-table-column label="排序号" prop="sortNo" width="100" align="center" />
<el-table-column label="状态" width="120" align="center">
<template slot-scope="scope">
<el-tag :type="scope.row.isEnabled === 1 ? 'success' : 'info'" effect="plain">
{{ scope.row.isEnabled === 1 ? '未占用' : '已占用' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="备注" prop="remark" show-overflow-tooltip />
<el-table-column label="二维码" width="120" align="center">
<template slot-scope="scope">
<QRCode
v-if="scope.row.level === 3"
:content="scope.row.actualWarehouseId"
:size="60"
/>
</template>
</el-table-column>
<el-table-column label="操作" width="220" align="center">
<template slot-scope="scope">
<el-button type="text" size="mini" @click="openCreateDialog(scope.row)">新增下级</el-button>
<el-button type="text" size="mini" @click="openEditDialog(scope.row)">编辑</el-button>
<el-button type="text" size="mini" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-dialog
title="批量新增 1-3 级"
:visible.sync="quickDialog.visible"
width="860px"
append-to-body
custom-class="warehouse-dialog"
>
<el-form label-position="top" class="quick-form">
<div class="level-card">
<div class="level-card__header">
<div class="level-card__title">一级节点</div>
</div>
<el-row :gutter="12">
<el-col :span="8">
<el-form-item label="编码">
<el-input v-model="quickForm.level1.code" placeholder="请输入一级编码" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="名称">
<el-input v-model="quickForm.level1.name" placeholder="请输入一级名称" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="排序号">
<el-input-number v-model="quickForm.level1.sortNo" :min="0" :max="9999" controls-position="right" />
</el-form-item>
</el-col>
</el-row>
</div>
<div class="level-card">
<div class="level-card__header">
<div class="level-card__title">二级 / 三级节点</div>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="addLevel2">新增二级</el-button>
</div>
<div
class="level-card__item"
v-for="(level2, index) in quickForm.level2List"
:key="`level2-${index}`"
>
<div class="level-card__item-header">
<div class="level-card__item-title">二级节点 {{ index + 1 }}</div>
<div class="level-card__item-actions">
<el-button
v-if="quickForm.level2List.length > 1"
type="text"
size="mini"
icon="el-icon-minus"
@click="removeLevel2(index)"
>移除</el-button>
<el-button
type="text"
size="mini"
icon="el-icon-plus"
@click="addLevel3(level2)"
>添加三级</el-button>
</div>
</div>
<el-row :gutter="12">
<el-col :span="8">
<el-form-item label="二级编码">
<el-input v-model="level2.code" placeholder="请输入二级编码" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="二级名称">
<el-input v-model="level2.name" placeholder="请输入二级名称" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="排序号">
<el-input-number v-model="level2.sortNo" :min="0" :max="9999" controls-position="right" />
</el-form-item>
</el-col>
</el-row>
<div class="level-card__children" v-if="level2.children.length">
<div
class="level-card__child"
v-for="(child, cIndex) in level2.children"
:key="`level3-${index}-${cIndex}`"
>
<div class="level-card__child-header">
<span>三级节点 {{ index + 1 }}-{{ cIndex + 1 }}</span>
<el-button
type="text"
size="mini"
icon="el-icon-delete"
@click="removeLevel3(level2, cIndex)"
>移除</el-button>
</div>
<el-row :gutter="12">
<el-col :span="8">
<el-form-item label="三级编码">
<el-input v-model="child.code" placeholder="请输入三级编码" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="三级名称">
<el-input v-model="child.name" placeholder="请输入三级名称" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="排序号">
<el-input-number v-model="child.sortNo" :min="0" :max="9999" controls-position="right" />
</el-form-item>
</el-col>
</el-row>
</div>
</div>
</div>
</div>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="quickDialog.visible = false"> </el-button>
<el-button type="primary" :loading="quickDialog.loading" @click="submitQuickForm"> </el-button>
</div>
</el-dialog>
<el-dialog
:title="editDialog.title"
:visible.sync="editDialog.visible"
width="520px"
append-to-body
custom-class="warehouse-dialog"
>
<el-form ref="editForm" :model="editDialog.form" :rules="editDialog.rules" label-width="90px">
<el-form-item label="层级" prop="actualWarehouseType">
<el-radio-group v-model="editDialog.form.actualWarehouseType" size="small">
<el-radio-button :label="1">一级</el-radio-button>
<el-radio-button :label="2">二级</el-radio-button>
<el-radio-button :label="3">三级</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="父节点">
<span>{{ editDialog.parentPath || '最高级' }}</span>
</el-form-item>
<el-form-item label="编码" prop="actualWarehouseCode">
<el-input v-model="editDialog.form.actualWarehouseCode" placeholder="请输入编码" />
</el-form-item>
<el-form-item label="名称" prop="actualWarehouseName">
<el-input v-model="editDialog.form.actualWarehouseName" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="排序号" prop="sortNo">
<el-input-number v-model="editDialog.form.sortNo" :min="0" :max="9999" controls-position="right" />
</el-form-item>
<el-form-item label="状态" prop="isEnabled">
<el-radio-group v-model="editDialog.form.isEnabled">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="editDialog.form.remark" type="textarea" rows="2" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="editDialog.visible = false"> </el-button>
<el-button type="primary" :loading="editDialog.loading" @click="submitEditForm"> </el-button>
</div>
</el-dialog>
<el-dialog
:title="createDialog.title"
:visible.sync="createDialog.visible"
width="520px"
append-to-body
custom-class="warehouse-dialog"
>
<el-form ref="createForm" :model="createDialog.form" :rules="createDialog.rules" label-width="90px">
<el-form-item label="父节点">
<template v-if="createDialog.parentPath">
<span>{{ createDialog.parentPath }}</span>
</template>
<template v-else>
<ActualWarehouseSelect
v-model="createDialog.form.parentId"
placeholder="选择父节点(可留空)"
:width="240"
@select="handleCreateParentSelect"
/>
</template>
</el-form-item>
<el-form-item label="层级" prop="actualWarehouseType">
<el-radio-group v-model="createDialog.form.actualWarehouseType" size="small" :disabled="!!createDialog.parentNode">
<el-radio-button :label="1">一级</el-radio-button>
<el-radio-button :label="2">二级</el-radio-button>
<el-radio-button :label="3">三级</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label="编码" prop="actualWarehouseCode">
<el-input v-model="createDialog.form.actualWarehouseCode" placeholder="请输入编码" />
</el-form-item>
<el-form-item label="名称" prop="actualWarehouseName">
<el-input v-model="createDialog.form.actualWarehouseName" placeholder="请输入名称" />
</el-form-item>
<el-form-item label="排序号" prop="sortNo">
<el-input-number v-model="createDialog.form.sortNo" :min="0" :max="9999" controls-position="right" />
</el-form-item>
<el-form-item label="状态" prop="isEnabled">
<el-radio-group v-model="createDialog.form.isEnabled">
<el-radio :label="1">启用</el-radio>
<el-radio :label="0">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="createDialog.form.remark" type="textarea" rows="2" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="createDialog.visible = false"> </el-button>
<el-button type="primary" :loading="createDialog.loading" @click="submitCreateForm"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
listActualWarehouseTree,
getActualWarehouse,
delActualWarehouse,
addActualWarehouse,
updateActualWarehouse,
createActualWarehouseHierarchy,
importActualWarehouse
} from "@/api/wms/actualWarehouse";
import QRCode from "../print/components/QRCode.vue";
import ActualWarehouseSelect from "@/components/KLPService/ActualWarehouseSelect";
const LEVELS = [1, 2, 3];
const LEVEL_LABELS = {
1: "一级",
2: "二级",
3: "三级"
};
export default {
name: "ActualWarehouse",
components: { QRCode, ActualWarehouseSelect },
data() {
return {
showSearch: true,
loading: false,
isExpandAll: true,
warehouseTree: [],
filteredCache: [],
nodeIndex: {},
queryParams: {
keyword: undefined,
level: undefined
},
quickDialog: {
visible: false,
loading: false
},
quickForm: this.buildQuickForm(),
editDialog: {
visible: false,
loading: false,
title: "编辑节点",
parentPath: "",
form: {
actualWarehouseId: null,
actualWarehouseType: 1,
actualWarehouseCode: "",
actualWarehouseName: "",
sortNo: 0,
isEnabled: 1,
remark: ""
},
rules: {
actualWarehouseType: [{ required: true, message: "请选择层级", trigger: "change" }],
actualWarehouseCode: [{ required: true, message: "请输入编码", trigger: "blur" }],
actualWarehouseName: [{ required: true, message: "请输入名称", trigger: "blur" }],
sortNo: [{ required: true, type: "number", message: "请输入排序号", trigger: "change" }]
}
},
createDialog: {
visible: false,
loading: false,
title: "新增节点",
parentNode: null,
parentPath: "",
form: {
parentId: 0,
actualWarehouseType: 1,
actualWarehouseCode: "",
actualWarehouseName: "",
sortNo: 0,
isEnabled: 1,
remark: ""
},
rules: {
actualWarehouseType: [{ required: true, message: "请选择层级", trigger: "change" }],
actualWarehouseCode: [{ required: true, message: "请输入编码", trigger: "blur" }],
actualWarehouseName: [{ required: true, message: "请输入名称", trigger: "blur" }],
sortNo: [{ required: true, type: "number", message: "请输入排序号", trigger: "change" }]
}
}
};
},
computed: {
filteredTreeData() {
const keyword = (this.queryParams.keyword || "").trim();
const levelFilter = this.queryParams.level;
if (!keyword && !levelFilter) {
return this.warehouseTree;
}
return this.filterTree(this.warehouseTree, keyword, levelFilter);
}
},
created() {
this.getTreeData();
},
methods: {
createLevelNode(level) {
return {
level,
code: "",
name: "",
sortNo: level * 10,
isEnabled: 1,
remark: "",
actualWarehouseId: null,
children: level === 2 ? [] : undefined
};
},
buildQuickForm() {
return {
level1: this.createLevelNode(1),
level2List: [this.createLevelNode(2)]
};
},
getTreeData() {
this.loading = true;
listActualWarehouseTree({ actualWarehouseName: this.queryParams.keyword })
.then(res => {
const list = res.data || [];
this.decorateTree(list);
})
.finally(() => {
this.loading = false;
});
},
decorateTree(list) {
this.nodeIndex = {};
const walker = (nodes, level = 1, parentId = 0, parentPath = []) => {
return (nodes || []).map(item => {
const current = {
...item,
level,
parentId: item.parentId ?? parentId,
path: [...parentPath, item.actualWarehouseName].filter(Boolean)
};
this.nodeIndex[current.actualWarehouseId] = current;
current.children = walker(item.children || [], level + 1, current.actualWarehouseId, current.path);
return current;
});
};
this.warehouseTree = walker(list);
},
filterTree(nodes, keyword, levelFilter) {
const result = [];
nodes.forEach(node => {
const matchKeyword =
!keyword ||
(node.actualWarehouseName && node.actualWarehouseName.includes(keyword)) ||
(node.actualWarehouseCode && node.actualWarehouseCode.includes(keyword));
const matchLevel = !levelFilter || node.level === levelFilter;
const filteredChildren = this.filterTree(node.children || [], keyword, levelFilter);
if ((matchKeyword && matchLevel) || filteredChildren.length) {
result.push({
...node,
children: filteredChildren.length ? filteredChildren : node.children
});
}
});
return result;
},
handleQuery() {
this.getTreeData();
},
resetQuery() {
this.queryParams.keyword = undefined;
this.queryParams.level = undefined;
this.handleQuery();
},
toggleExpand() {
this.isExpandAll = !this.isExpandAll;
this.$nextTick(() => {
this.toggleTreeRows(this.filteredTreeData, this.isExpandAll);
});
},
toggleTreeRows(nodes, expand) {
const table = this.$refs.treeTable;
if (!table || !Array.isArray(nodes)) return;
nodes.forEach(node => {
table.toggleRowExpansion(node, expand);
if (node.children && node.children.length) {
this.toggleTreeRows(node.children, expand);
}
});
},
handleDownloadTemplate() {
this.download("wms/actualWarehouse/importTemplate", {}, "实际库区导入模板.xlsx");
},
triggerImport() {
if (this.$refs.importInput) {
this.$refs.importInput.value = null;
this.$refs.importInput.click();
}
},
handleImportChange(e) {
const file = e.target.files && e.target.files[0];
if (!file) return;
const formData = new FormData();
formData.append("file", file);
const loading = this.$loading({
lock: true,
text: "导入中,请稍候...",
spinner: "el-icon-loading",
background: "rgba(0, 0, 0, 0.4)"
});
importActualWarehouse(formData)
.then(res => {
this.$modal.msgSuccess(res.msg || "导入成功");
this.getTreeData();
})
.catch(() => {
this.$modal.msgError("导入失败,请检查模板数据");
})
.finally(() => {
loading.close();
if (this.$refs.importInput) {
this.$refs.importInput.value = null;
}
});
},
getLevelLabel(level) {
return LEVEL_LABELS[level] || `${level}`;
},
openQuickDialog() {
this.quickDialog.visible = true;
this.quickDialog.loading = false;
this.quickForm = this.buildQuickForm();
},
addLevel2() {
this.quickForm.level2List.push(this.createLevelNode(2));
},
removeLevel2(index) {
if (this.quickForm.level2List.length === 1) return;
this.quickForm.level2List.splice(index, 1);
},
addLevel3(level2) {
if (!Array.isArray(level2.children)) {
this.$set(level2, "children", []);
}
level2.children.push(this.createLevelNode(3));
},
removeLevel3(level2, childIndex) {
level2.children.splice(childIndex, 1);
},
submitQuickForm() {
const level1Payload = this.normalizeNode(this.quickForm.level1);
if (!level1Payload) {
this.$modal.msgWarning("请先填写完整的一级编码和名称");
return;
}
const validationError = this.validateQuickForm();
if (validationError) {
this.$modal.msgWarning(validationError);
return;
}
const paths = this.buildHierarchyPaths(level1Payload);
if (!paths.length) {
this.$modal.msgWarning("请至少填写一个二级或三级节点");
return;
}
this.quickDialog.loading = true;
const runner = async () => {
for (const path of paths) {
await createActualWarehouseHierarchy({ levels: path });
}
};
runner()
.then(() => {
this.$modal.msgSuccess("已完成录入");
this.quickDialog.visible = false;
this.getTreeData();
})
.catch(() => {
this.$modal.msgError("批量新增失败,请重试");
})
.finally(() => {
this.quickDialog.loading = false;
});
},
validateQuickForm() {
const level2List = this.quickForm.level2List;
const hasSecondOrThird = level2List.some(item => {
const hasSecond = (item.code || "").trim() && (item.name || "").trim();
const hasThird = (item.children || []).some(child => (child.code || "").trim() || (child.name || "").trim());
return hasSecond || hasThird;
});
if (!hasSecondOrThird) {
return "请至少填写一个二级或三级节点";
}
for (const level2 of level2List) {
const children = level2.children || [];
const hasChildren = children.some(child => (child.code || "").trim() || (child.name || "").trim());
if (hasChildren && (!(level2.code || "").trim() || !(level2.name || "").trim())) {
return "有三级节点时,所属的二级节点必须填写完整";
}
const invalidChild = children.find(child => {
const code = (child.code || "").trim();
const name = (child.name || "").trim();
return (code && !name) || (!code && name);
});
if (invalidChild) {
return "三级节点需同时填写编码与名称";
}
if (!hasChildren && ((level2.code || "").trim() && !(level2.name || "").trim())) {
return "二级节点需同时填写编码与名称";
}
}
return "";
},
buildHierarchyPaths(level1Payload) {
const paths = [];
this.quickForm.level2List.forEach(level2 => {
const level2Payload = this.normalizeNode(level2);
const childNodes = level2.children
.map(child => this.normalizeNode(child))
.filter(Boolean);
if (childNodes.length) {
if (!level2Payload) return;
childNodes.forEach(child => {
paths.push([level1Payload, level2Payload, child]);
});
} else if (level2Payload) {
paths.push([level1Payload, level2Payload]);
}
});
if (!paths.some(path => path.length > 1)) {
paths.push([level1Payload]);
}
return paths;
},
normalizeNode(node) {
if (!node) return null;
const code = (node.code || "").trim();
const name = (node.name || "").trim();
if (!code || !name) return null;
return {
level: node.level,
actualWarehouseId: node.actualWarehouseId || null,
actualWarehouseCode: code,
actualWarehouseName: name,
actualWarehouseType: node.level,
sortNo: Number(node.sortNo) || 0,
isEnabled: node.isEnabled ?? 1,
remark: node.remark
};
},
openEditDialog(row) {
this.editDialog.visible = true;
this.editDialog.loading = false;
getActualWarehouse(row.actualWarehouseId).then(res => {
const data = res.data || {};
this.editDialog.form = {
actualWarehouseId: data.actualWarehouseId,
actualWarehouseType: data.actualWarehouseType,
actualWarehouseCode: data.actualWarehouseCode,
actualWarehouseName: data.actualWarehouseName,
sortNo: data.sortNo,
isEnabled: data.isEnabled ?? 1,
remark: data.remark
};
const chain = this.findNodeChain(data.parentId);
this.editDialog.parentPath = chain.map(item => item.actualWarehouseName).join(" / ");
});
},
openCreateDialog(parentNode) {
if (parentNode && parentNode.level >= 3) {
this.$modal.msgWarning("三级节点无法继续新增下级");
return;
}
this.createDialog.visible = true;
this.createDialog.loading = false;
this.createDialog.parentNode = parentNode || null;
this.createDialog.parentPath = "";
this.createDialog.title = parentNode
? `在【${parentNode.actualWarehouseName}】下新增`
: "新增节点";
const nextLevel = parentNode ? Math.min(parentNode.level + 1, 3) : 1;
this.createDialog.form = {
parentId: parentNode ? parentNode.actualWarehouseId : 0,
actualWarehouseType: nextLevel,
actualWarehouseCode: "",
actualWarehouseName: "",
sortNo: (parentNode?.children?.length || 0) * 10,
isEnabled: 1,
remark: ""
};
if (parentNode) {
this.createDialog.parentPath = this.findNodeChain(parentNode.actualWarehouseId)
.map(item => item.actualWarehouseName)
.join(" / ");
}
},
handleCreateParentSelect(node) {
if (!node) {
this.createDialog.form.parentId = 0;
this.createDialog.form.actualWarehouseType = 1;
this.createDialog.parentPath = "";
return;
}
if (node.level >= 3) {
this.$modal.msgWarning("三级节点无法再新增下级");
this.createDialog.form.parentId = 0;
this.createDialog.form.actualWarehouseType = 1;
return;
}
this.createDialog.form.actualWarehouseType = node.level + 1;
this.createDialog.parentPath = this.findNodeChain(node.actualWarehouseId)
.map(item => item.actualWarehouseName)
.join(" / ");
},
submitCreateForm() {
this.$refs.createForm.validate(valid => {
if (!valid) return;
const payload = { ...this.createDialog.form };
this.createDialog.loading = true;
addActualWarehouse(payload)
.then(() => {
this.$modal.msgSuccess("新增成功");
this.createDialog.visible = false;
this.getTreeData();
})
.finally(() => {
this.createDialog.loading = false;
});
});
},
submitEditForm() {
this.$refs.editForm.validate(valid => {
if (!valid) return;
this.editDialog.loading = true;
updateActualWarehouse(this.editDialog.form)
.then(() => {
this.$modal.msgSuccess("修改成功");
this.editDialog.visible = false;
this.getTreeData();
})
.finally(() => {
this.editDialog.loading = false;
});
});
},
handleDelete(row) {
this.$modal
.confirm(`确认删除【${row.actualWarehouseName}】吗?`)
.then(() => delActualWarehouse(row.actualWarehouseId))
.then(() => {
this.$modal.msgSuccess("删除成功");
this.getTreeData();
})
.catch(() => {});
},
findNodeChain(nodeId) {
if (!nodeId) return [];
const chain = [];
let current = this.nodeIndex[nodeId];
while (current) {
chain.unshift(current);
current = current.parentId ? this.nodeIndex[current.parentId] : null;
}
return chain;
}
}
};
</script>
<style scoped>
.warehouse-page {
min-height: 100%;
}
.toolbar-row {
margin-bottom: 12px;
align-items: center;
}
.toolbar-actions .el-button + .el-button {
margin-left: 8px;
}
.toolbar-right {
text-align: right;
}
.warehouse-table {
width: 100%;
}
.warehouse-dialog ::v-deep .el-dialog__body {
max-height: 60vh;
overflow-y: auto;
}
.quick-form {
padding-bottom: 8px;
}
.level-card {
border: 1px solid #ebeef5;
border-radius: 6px;
padding: 12px;
margin-bottom: 12px;
background: #fff;
}
.level-card__header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
}
.level-card__title {
font-weight: 600;
color: #303133;
}
.level-card__item {
border-top: 1px dashed #ebeef5;
padding-top: 12px;
margin-top: 12px;
}
.level-card__item-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
font-weight: 600;
}
.level-card__item-actions .el-button + .el-button {
margin-left: 6px;
}
.level-card__children {
margin-top: 12px;
border-left: 2px solid #f2f6fc;
padding-left: 12px;
}
.level-card__child {
border: 1px dashed #dcdfe6;
border-radius: 4px;
padding: 10px;
margin-bottom: 10px;
background: #fafafa;
}
.level-card__child-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
font-weight: 500;
}
.qr-disabled {
color: #c0c4cc;
font-size: 12px;
}
</style>