| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897 |
- <template>
- <div class="dictionary-management">
- <div class="page-header">
- <h2>字典管理</h2>
- <p>管理系统字典类型和字典项</p>
- </div>
- <!-- 主容器:树 + 列表 -->
- <div class="content-container">
- <!-- 左侧:字典类型树 -->
- <div class="tree-panel">
- <div class="tree-header">
- <h3>字典类型</h3>
- <div class="tree-actions">
- <el-button type="primary" size="small" @click="openCreateCategoryDialog">
- <el-icon><Plus /></el-icon>
- 新增
- </el-button>
- <el-button
- type="warning"
- size="small"
- @click="openEditCategoryDialog"
- :disabled="!selectedCategory"
- >
- <el-icon><Edit /></el-icon>
- 修改
- </el-button>
- <el-button
- type="danger"
- size="small"
- @click="deleteCategoryConfirm"
- :disabled="!selectedCategory"
- >
- <el-icon><Delete /></el-icon>
- 删除
- </el-button>
- </div>
- </div>
- <el-tree
- ref="treeRef"
- :data="categoryTree"
- node-key="category_id"
- :props="{ children: 'children', label: 'category_name' }"
- default-expand-all
- highlight-current
- @node-click="handleTreeNodeClick"
- v-loading="treeLoading"
- />
- </div>
- <!-- 右侧:字典项列表 -->
- <div class="list-panel">
- <div class="list-header">
- <div v-if="selectedCategory">
- <h3>{{ selectedCategory.category_name }} 中的字典项</h3>
- </div>
- <div v-else>
- <h3>请在左侧选择字典类型</h3>
- </div>
- <div class="list-actions" v-if="selectedCategory">
- <el-input
- v-model="searchKeyword"
- placeholder="搜索字典项"
- style="width: 200px; margin-right: 10px"
- clearable
- @clear="loadItems"
- >
- <template #prefix>
- <el-icon><Search /></el-icon>
- </template>
- </el-input>
- <el-select
- v-model="searchEnableFlag"
- placeholder="状态"
- style="width: 120px; margin-right: 10px"
- clearable
- @change="loadItems"
- >
- <el-option label="全部" value="" />
- <el-option label="启用" value="1" />
- <el-option label="禁用" value="0" />
- </el-select>
- <el-button type="primary" @click="loadItems">
- <el-icon><Search /></el-icon>
- 查询
- </el-button>
- <el-button type="primary" @click="openCreateItemDialog">
- <el-icon><Plus /></el-icon>
- 新增
- </el-button>
- <el-button
- type="danger"
- @click="batchDeleteItems"
- :disabled="selectedItems.length === 0"
- >
- <el-icon><Delete /></el-icon>
- 批量删除
- </el-button>
- </div>
- </div>
- <!-- 字典项列表 -->
- <el-table
- v-if="selectedCategory"
- v-loading="loading"
- :data="items"
- style="width: 100%"
- @selection-change="handleSelectionChange"
- >
- <el-table-column type="selection" width="55" />
- <el-table-column prop="dict_name" label="字典名称" min-width="150" show-overflow-tooltip />
- <el-table-column prop="dict_value" label="字典值" width="120" show-overflow-tooltip />
- <el-table-column prop="dict_desc" label="字典备注" min-width="150" show-overflow-tooltip>
- <template #default="{ row }">
- <el-tooltip v-if="row.dict_desc && row.dict_desc.length > 100" :content="row.dict_desc" placement="top">
- <span>{{ row.dict_desc.substring(0, 100) }}...</span>
- </el-tooltip>
- <span v-else>{{ row.dict_desc }}</span>
- </template>
- </el-table-column>
- <el-table-column prop="sort" label="排序" width="80" align="center" />
- <el-table-column prop="enable_flag" label="状态" width="100" align="center">
- <template #default="{ row }">
- <el-switch
- v-model="row.enable_flag"
- active-value="1"
- inactive-value="0"
- @change="handleStatusChange(row)"
- />
- </template>
- </el-table-column>
- <el-table-column prop="created_by_name" label="创建人" width="100" />
- <el-table-column prop="created_time" label="创建时间" width="160">
- <template #default="{ row }">
- {{ formatDate(row.created_time) }}
- </template>
- </el-table-column>
- <el-table-column prop="updated_by_name" label="修改人" width="100" />
- <el-table-column prop="updated_time" label="修改时间" width="160">
- <template #default="{ row }">
- {{ formatDate(row.updated_time) }}
- </template>
- </el-table-column>
- <el-table-column label="操作" width="150" fixed="right">
- <template #default="{ row }">
- <el-button type="warning" size="small" @click="editItem(row)">
- 修改
- </el-button>
- <el-button type="danger" size="small" @click="deleteItem(row)">
- 删除
- </el-button>
- </template>
- </el-table-column>
- </el-table>
- <div v-else class="empty-state">
- <el-empty description="请在左侧选择一个字典类型" />
- </div>
- <!-- 分页 -->
- <div v-if="selectedCategory" class="pagination">
- <el-pagination
- v-model:current-page="currentPage"
- v-model:page-size="pageSize"
- :page-sizes="[10, 20, 50, 100]"
- :total="total"
- layout="total, sizes, prev, pager, next, jumper"
- @size-change="handleSizeChange"
- @current-change="handleCurrentChange"
- />
- </div>
- </div>
- </div>
- <!-- 创建/编辑字典类型对话框 -->
- <el-dialog
- v-model="showCategoryDialog"
- :title="editingCategory ? '编辑字典类型' : '创建字典类型'"
- width="600px"
- @close="resetCategoryForm"
- >
- <el-form
- ref="categoryFormRef"
- :model="categoryForm"
- :rules="categoryRules"
- label-width="120px"
- >
- <el-form-item label="字典类型ID" prop="category_id" v-if="editingCategory">
- <el-input v-model="categoryForm.category_id" disabled />
- </el-form-item>
- <el-form-item label="字典类型编号" prop="category_no">
- <el-input v-model="categoryForm.category_no" placeholder="请输入字典类型编号" maxlength="512" />
- </el-form-item>
- <el-form-item label="字典类型名称" prop="category_name">
- <el-input v-model="categoryForm.category_name" placeholder="请输入字典类型名称" maxlength="512" />
- </el-form-item>
- <el-form-item label="字典类型备注" prop="category_desc">
- <el-input
- v-model="categoryForm.category_desc"
- type="textarea"
- :rows="3"
- placeholder="请输入字典类型备注"
- maxlength="512"
- show-word-limit
- />
- </el-form-item>
- <el-form-item label="父节点" prop="parent_field">
- <el-tree-select
- v-model="categoryForm.parent_field"
- :data="categoryTreeForSelect"
- node-key="category_id"
- :props="{ children: 'children', label: 'category_name' }"
- placeholder="请选择父节点(默认为根节点)"
- check-strictly
- clearable
- />
- </el-form-item>
- <el-form-item label="字典层级" prop="category_level">
- <el-input v-model="categoryForm.category_level" placeholder="请输入字典层级" maxlength="1" />
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button @click="showCategoryDialog = false">取消</el-button>
- <el-button type="primary" @click="submitCategoryForm" :loading="submitting">
- 确定
- </el-button>
- </template>
- </el-dialog>
- <!-- 创建/编辑字典项对话框 -->
- <el-dialog
- v-model="showItemDialog"
- :title="editingItem ? '编辑字典项' : '创建字典项'"
- width="600px"
- @close="resetItemForm"
- >
- <el-form
- ref="itemFormRef"
- :model="itemForm"
- :rules="itemRules"
- label-width="120px"
- >
- <el-form-item label="字典名称" prop="dict_name">
- <el-input v-model="itemForm.dict_name" placeholder="请输入字典名称" maxlength="512" />
- </el-form-item>
- <el-form-item label="字典值" prop="dict_value">
- <el-input v-model="itemForm.dict_value" placeholder="请输入字典值" maxlength="512" />
- </el-form-item>
- <el-form-item label="字典备注" prop="dict_desc">
- <el-input
- v-model="itemForm.dict_desc"
- type="textarea"
- :rows="3"
- placeholder="请输入字典备注"
- maxlength="512"
- show-word-limit
- />
- </el-form-item>
- <el-form-item label="字典类型" prop="category_id">
- <el-tree-select
- v-model="itemForm.category_id"
- :data="categoryTree"
- node-key="category_id"
- :props="{ children: 'children', label: 'category_name' }"
- placeholder="请选择字典类型"
- check-strictly
- />
- </el-form-item>
- <el-form-item label="排序" prop="sort">
- <el-input-number v-model="itemForm.sort" :min="0" controls-position="right" />
- </el-form-item>
- <el-form-item label="启用状态" prop="enable_flag">
- <el-radio-group v-model="itemForm.enable_flag">
- <el-radio label="1">启用</el-radio>
- <el-radio label="0">禁用</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button @click="showItemDialog = false">取消</el-button>
- <el-button type="primary" @click="submitItemForm" :loading="submitting">
- 确定
- </el-button>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup lang="ts">
- import { ref, reactive, onMounted, computed } from 'vue'
- import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus'
- import { Plus, Edit, Delete, Search } from '@element-plus/icons-vue'
- import { dictApi, type DictCategory, type DictItem, type DictCategoryForm, type DictItemForm } from '@/api/dict'
- // 树相关
- const treeRef = ref()
- const treeLoading = ref(false)
- const categoryTree = ref<DictCategory[]>([])
- const selectedCategory = ref<DictCategory | null>(null)
- // 列表相关
- const loading = ref(false)
- const items = ref<DictItem[]>([])
- const currentPage = ref(1)
- const pageSize = ref(10)
- const total = ref(0)
- const selectedItems = ref<DictItem[]>([])
- // 搜索相关
- const searchKeyword = ref('')
- const searchEnableFlag = ref('')
- // 字典类型对话框
- const showCategoryDialog = ref(false)
- const editingCategory = ref(false)
- const categoryFormRef = ref<FormInstance>()
- const categoryForm = reactive<DictCategoryForm & { category_id?: string }>({
- category_id: '',
- category_no: '',
- category_name: '',
- category_desc: '',
- parent_field: '0',
- category_level: ''
- })
- const categoryRules: FormRules = {
- category_name: [
- { required: true, message: '请输入字典类型名称', trigger: 'blur' },
- { max: 512, message: '字典类型名称不能超过512个字符', trigger: 'blur' }
- ],
- category_no: [
- { max: 512, message: '字典类型编号不能超过512个字符', trigger: 'blur' }
- ],
- category_desc: [
- { max: 512, message: '字典类型备注不能超过512个字符', trigger: 'blur' }
- ]
- }
- // 字典项对话框
- const showItemDialog = ref(false)
- const editingItem = ref(false)
- const itemFormRef = ref<FormInstance>()
- const itemForm = reactive<DictItemForm & { dict_id?: number }>({
- dict_id: undefined,
- dict_name: '',
- dict_value: '',
- dict_desc: '',
- category_id: '',
- enable_flag: '1',
- sort: 0
- })
- const itemRules: FormRules = {
- dict_name: [
- { required: true, message: '请输入字典名称', trigger: 'blur' },
- { max: 512, message: '字典名称不能超过512个字符', trigger: 'blur' }
- ],
- dict_value: [
- { required: true, message: '请输入字典值', trigger: 'blur' },
- { max: 512, message: '字典值不能超过512个字符', trigger: 'blur' }
- ],
- dict_desc: [
- { max: 512, message: '字典备注不能超过512个字符', trigger: 'blur' }
- ],
- category_id: [
- { required: true, message: '请选择字典类型', trigger: 'change' }
- ]
- }
- const submitting = ref(false)
- // 计算属性:用于选择父节点的树(排除当前编辑的节点)
- const categoryTreeForSelect = computed(() => {
- if (!editingCategory.value) {
- return [{ category_id: '0', category_name: '根节点', children: categoryTree.value }]
- }
- // 编辑时需要排除自己和子节点
- const filterNode = (nodes: DictCategory[], excludeId: string): DictCategory[] => {
- return nodes.filter(node => node.category_id !== excludeId).map(node => ({
- ...node,
- children: node.children ? filterNode(node.children, excludeId) : []
- }))
- }
- return [{
- category_id: '0',
- category_name: '根节点',
- children: filterNode(categoryTree.value, categoryForm.category_id || '')
- }]
- })
- // 加载字典类型树
- const loadCategoryTree = async () => {
- treeLoading.value = true
- try {
- const res = await dictApi.getCategoryTree()
- if (res.code === '000000') {
- categoryTree.value = res.data || []
- } else {
- ElMessage.error(res.message || '加载字典类型树失败')
- }
- } catch (error: any) {
- console.error('加载字典类型树失败:', error)
- ElMessage.error('加载字典类型树失败')
- } finally {
- treeLoading.value = false
- }
- }
- // 树节点点击
- const handleTreeNodeClick = (data: DictCategory) => {
- selectedCategory.value = data
- currentPage.value = 1
- searchKeyword.value = ''
- searchEnableFlag.value = ''
- loadItems()
- }
- // 加载字典项列表
- const loadItems = async () => {
- if (!selectedCategory.value) return
-
- loading.value = true
- try {
- const res = await dictApi.getItemList({
- category_id: selectedCategory.value.category_id,
- keyword: searchKeyword.value || undefined,
- enable_flag: searchEnableFlag.value || undefined,
- page: currentPage.value,
- page_size: pageSize.value
- })
- if (res.code === '000000') {
- items.value = res.data.list || []
- total.value = res.data.total || 0
- } else {
- ElMessage.error(res.message || '加载字典项列表失败')
- }
- } catch (error: any) {
- console.error('加载字典项列表失败:', error)
- ElMessage.error('加载字典项列表失败')
- } finally {
- loading.value = false
- }
- }
- // 分页相关
- const handleSizeChange = (val: number) => {
- pageSize.value = val
- currentPage.value = 1
- loadItems()
- }
- const handleCurrentChange = (val: number) => {
- currentPage.value = val
- loadItems()
- }
- // 选择变化
- const handleSelectionChange = (val: DictItem[]) => {
- selectedItems.value = val
- }
- // ==================== 字典类型操作 ====================
- // 打开创建字典类型对话框
- const openCreateCategoryDialog = () => {
- editingCategory.value = false
- resetCategoryForm()
- showCategoryDialog.value = true
- }
- // 打开编辑字典类型对话框
- const openEditCategoryDialog = () => {
- if (!selectedCategory.value) return
-
- editingCategory.value = true
- Object.assign(categoryForm, {
- category_id: selectedCategory.value.category_id,
- category_no: selectedCategory.value.category_no || '',
- category_name: selectedCategory.value.category_name,
- category_desc: selectedCategory.value.category_desc || '',
- parent_field: selectedCategory.value.parent_field || '0',
- category_level: selectedCategory.value.category_level || ''
- })
- showCategoryDialog.value = true
- }
- // 重置字典类型表单
- const resetCategoryForm = () => {
- categoryFormRef.value?.resetFields()
- Object.assign(categoryForm, {
- category_id: '',
- category_no: '',
- category_name: '',
- category_desc: '',
- parent_field: '0',
- category_level: ''
- })
- }
- // 提交字典类型表单
- const submitCategoryForm = async () => {
- if (!categoryFormRef.value) return
-
- await categoryFormRef.value.validate(async (valid) => {
- if (!valid) return
-
- submitting.value = true
- try {
- const data: DictCategoryForm = {
- category_no: categoryForm.category_no || undefined,
- category_name: categoryForm.category_name,
- category_desc: categoryForm.category_desc || undefined,
- parent_field: categoryForm.parent_field || '0',
- category_level: categoryForm.category_level || undefined
- }
-
- if (editingCategory.value && categoryForm.category_id) {
- // 更新
- const res = await dictApi.updateCategory(categoryForm.category_id, data)
- if (res.code === '000000') {
- ElMessage.success('字典类型更新成功')
- showCategoryDialog.value = false
- await loadCategoryTree()
- } else {
- ElMessage.error(res.message || '字典类型更新失败')
- }
- } else {
- // 创建
- const res = await dictApi.createCategory(data)
- if (res.code === '000000') {
- ElMessage.success('字典类型创建成功')
- showCategoryDialog.value = false
- await loadCategoryTree()
- } else {
- ElMessage.error(res.message || '字典类型创建失败')
- }
- }
- } catch (error: any) {
- console.error('提交字典类型失败:', error)
- ElMessage.error('操作失败')
- } finally {
- submitting.value = false
- }
- })
- }
- // 删除字典类型确认
- const deleteCategoryConfirm = () => {
- if (!selectedCategory.value) return
-
- ElMessageBox.confirm(
- `确定要删除字典类型"${selectedCategory.value.category_name}"吗?`,
- '删除确认',
- {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }
- ).then(async () => {
- await deleteCategory()
- }).catch(() => {
- // 取消删除
- })
- }
- // 删除字典类型
- const deleteCategory = async () => {
- if (!selectedCategory.value) return
-
- try {
- const res = await dictApi.deleteCategory(selectedCategory.value.category_id)
- if (res.code === '000000') {
- ElMessage.success('字典类型删除成功')
- selectedCategory.value = null
- items.value = []
- await loadCategoryTree()
- } else {
- ElMessage.error(res.message || '字典类型删除失败')
- }
- } catch (error: any) {
- console.error('删除字典类型失败:', error)
- ElMessage.error('删除失败')
- }
- }
- // ==================== 字典项操作 ====================
- // 打开创建字典项对话框
- const openCreateItemDialog = () => {
- if (!selectedCategory.value) {
- ElMessage.warning('请先选择字典类型')
- return
- }
-
- editingItem.value = false
- resetItemForm()
- itemForm.category_id = selectedCategory.value.category_id
- showItemDialog.value = true
- }
- // 编辑字典项
- const editItem = (row: DictItem) => {
- editingItem.value = true
- Object.assign(itemForm, {
- dict_id: row.dict_id,
- dict_name: row.dict_name,
- dict_value: row.dict_value,
- dict_desc: row.dict_desc || '',
- category_id: row.category_id,
- enable_flag: row.enable_flag,
- sort: row.sort || 0
- })
- showItemDialog.value = true
- }
- // 重置字典项表单
- const resetItemForm = () => {
- itemFormRef.value?.resetFields()
- Object.assign(itemForm, {
- dict_id: undefined,
- dict_name: '',
- dict_value: '',
- dict_desc: '',
- category_id: '',
- enable_flag: '1',
- sort: 0
- })
- }
- // 提交字典项表单
- const submitItemForm = async () => {
- if (!itemFormRef.value) return
-
- await itemFormRef.value.validate(async (valid) => {
- if (!valid) return
-
- submitting.value = true
- try {
- const data: DictItemForm = {
- dict_name: itemForm.dict_name,
- dict_value: itemForm.dict_value,
- dict_desc: itemForm.dict_desc || undefined,
- category_id: itemForm.category_id,
- enable_flag: itemForm.enable_flag,
- sort: itemForm.sort
- }
-
- if (editingItem.value && itemForm.dict_id) {
- // 更新
- const res = await dictApi.updateItem(itemForm.dict_id, data)
- if (res.code === '000000') {
- ElMessage.success('字典项更新成功')
- showItemDialog.value = false
- await loadItems()
- } else {
- ElMessage.error(res.message || '字典项更新失败')
- }
- } else {
- // 创建
- const res = await dictApi.createItem(data)
- if (res.code === '000000') {
- ElMessage.success('字典项创建成功')
- showItemDialog.value = false
- await loadItems()
- } else {
- ElMessage.error(res.message || '字典项创建失败')
- }
- }
- } catch (error: any) {
- console.error('提交字典项失败:', error)
- ElMessage.error('操作失败')
- } finally {
- submitting.value = false
- }
- })
- }
- // 删除字典项
- const deleteItem = (row: DictItem) => {
- ElMessageBox.confirm(
- `确定要删除字典项"${row.dict_name}"吗?`,
- '删除确认',
- {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }
- ).then(async () => {
- try {
- const res = await dictApi.deleteItem(row.dict_id)
- if (res.code === '000000') {
- ElMessage.success('字典项删除成功')
- await loadItems()
- } else {
- ElMessage.error(res.message || '字典项删除失败')
- }
- } catch (error: any) {
- console.error('删除字典项失败:', error)
- ElMessage.error('删除失败')
- }
- }).catch(() => {
- // 取消删除
- })
- }
- // 批量删除字典项
- const batchDeleteItems = () => {
- if (selectedItems.value.length === 0) {
- ElMessage.warning('请先选择要删除的字典项')
- return
- }
-
- ElMessageBox.confirm(
- `确定要删除选中的 ${selectedItems.value.length} 个字典项吗?`,
- '批量删除确认',
- {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning'
- }
- ).then(async () => {
- try {
- const dictIds = selectedItems.value.map(item => item.dict_id)
- const res = await dictApi.batchDeleteItems(dictIds)
- if (res.code === '000000') {
- ElMessage.success(res.message || '批量删除成功')
- selectedItems.value = []
- await loadItems()
- } else {
- ElMessage.error(res.message || '批量删除失败')
- }
- } catch (error: any) {
- console.error('批量删除字典项失败:', error)
- ElMessage.error('批量删除失败')
- }
- }).catch(() => {
- // 取消删除
- })
- }
- // 切换字典项状态
- const handleStatusChange = async (row: DictItem) => {
- try {
- const res = await dictApi.toggleItemStatus(row.dict_id, row.enable_flag)
- if (res.code === '000000') {
- ElMessage.success(res.message || '状态更新成功')
- } else {
- ElMessage.error(res.message || '状态更新失败')
- // 恢复原状态
- row.enable_flag = row.enable_flag === '1' ? '0' : '1'
- }
- } catch (error: any) {
- console.error('切换字典项状态失败:', error)
- ElMessage.error('状态更新失败')
- // 恢复原状态
- row.enable_flag = row.enable_flag === '1' ? '0' : '1'
- }
- }
- // 格式化日期
- const formatDate = (dateStr: string | undefined) => {
- if (!dateStr) return '-'
- const date = new Date(dateStr)
- return date.toLocaleString('zh-CN', {
- year: 'numeric',
- month: '2-digit',
- day: '2-digit',
- hour: '2-digit',
- minute: '2-digit',
- second: '2-digit'
- })
- }
- // 初始化
- onMounted(() => {
- loadCategoryTree()
- })
- </script>
- <style scoped>
- .dictionary-management {
- padding: 20px;
- height: 100%;
- display: flex;
- flex-direction: column;
- }
- .page-header {
- margin-bottom: 20px;
- }
- .page-header h2 {
- margin: 0 0 8px 0;
- font-size: 24px;
- font-weight: 600;
- color: #303133;
- }
- .page-header p {
- margin: 0;
- font-size: 14px;
- color: #909399;
- }
- .content-container {
- flex: 1;
- display: flex;
- gap: 20px;
- overflow: hidden;
- }
- .tree-panel {
- width: 300px;
- background: #fff;
- border-radius: 4px;
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
- display: flex;
- flex-direction: column;
- overflow: hidden;
- }
- .tree-header {
- padding: 16px;
- border-bottom: 1px solid #ebeef5;
- }
- .tree-header h3 {
- margin: 0 0 12px 0;
- font-size: 16px;
- font-weight: 600;
- color: #303133;
- }
- .tree-actions {
- display: flex;
- gap: 8px;
- }
- .tree-actions .el-button {
- flex: 1;
- }
- .el-tree {
- flex: 1;
- overflow-y: auto;
- padding: 16px;
- }
- .list-panel {
- flex: 1;
- background: #fff;
- border-radius: 4px;
- box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
- display: flex;
- flex-direction: column;
- overflow: hidden;
- }
- .list-header {
- padding: 16px;
- border-bottom: 1px solid #ebeef5;
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .list-header h3 {
- margin: 0;
- font-size: 16px;
- font-weight: 600;
- color: #303133;
- }
- .list-actions {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .el-table {
- flex: 1;
- }
- .empty-state {
- flex: 1;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .pagination {
- padding: 16px;
- border-top: 1px solid #ebeef5;
- display: flex;
- justify-content: flex-end;
- }
- </style>
|