Jelajahi Sumber

Merge branch 'dev-qd' into 'dev'

fix(platform/dictionary): 修改字典管理样式问题

See merge request product-group-fe/sfy-safety-group/sfy-safety!42
楼航飞 11 bulan lalu
induk
melakukan
f7edea4853

TEMPAT SAMPAH
src/assets/icons/rollback.png


File diff ditekan karena terlalu besar
+ 11 - 0
src/assets/icons/sortdown.svg


File diff ditekan karena terlalu besar
+ 11 - 0
src/assets/icons/sortdown_active.svg


File diff ditekan karena terlalu besar
+ 11 - 0
src/assets/icons/sortup.svg


File diff ditekan karena terlalu besar
+ 11 - 0
src/assets/icons/sortup_active.svg


+ 39 - 0
src/components/Breadcrumb.vue

@@ -0,0 +1,39 @@
+<template>
+  <el-card>
+    <div class="breadcrumb">
+      <span v-if="showIcon" class="return-icon" @click="router.back()"
+        ><img src="@/assets/icons/rollback.png" alt=""
+      /></span>
+      <span class="title">{{ title }}</span>
+    </div>
+  </el-card>
+</template>
+
+<script setup lang="ts">
+  import { useRouter } from 'vue-router';
+
+  defineProps({
+    title: {
+      type: String,
+      default: '',
+    },
+    showIcon: {
+      type: Boolean,
+      default: false,
+    },
+  });
+
+  const router = useRouter();
+</script>
+
+<style scoped lang="scss">
+  .breadcrumb {
+    .return-icon {
+      cursor: pointer;
+    }
+
+    .title {
+      margin-left: 10px;
+    }
+  }
+</style>

+ 21 - 0
src/styles/common.scss

@@ -8,3 +8,24 @@
 .component-container {
   @extend .container;
 }
+
+//表格
+.el-table {
+  --el-table-header-bg-color: #f5f7fa;
+  --el-table-header-text-color: rgb(31, 34, 37) !important;
+}
+
+
+.el-table thead {
+  background-color: rgb(31, 34, 37);
+}
+
+.el-table th.el-table__cell {
+  background-color: #f5f7fa !important;
+}
+
+.el-table {
+  .el-button {
+    font-weight: 400;
+  }
+}

+ 105 - 32
src/views/system/dictionary/components/AddDict.vue

@@ -27,28 +27,19 @@
               <!-- 移动按钮 -->
               <div class="dict-item-header">
                 <div class="move-buttons">
-                  <el-button v-if="index > 0" type="primary" link @click="moveDictItem(index, 'up')">
-                    <el-icon>
-                      <Top />
-                    </el-icon>
-                  </el-button>
-                  <el-button
+                  <MoveButton v-if="index > 0" type="up" @move="moveDictItem(index, $event)" />
+                  <MoveButton
                     v-if="index < formData.sysDictDataList.length - 1"
-                    type="primary"
-                    link
-                    @click="moveDictItem(index, 'down')"
-                  >
-                    <el-icon>
-                      <Bottom />
-                    </el-icon>
-                  </el-button>
+                    type="down"
+                    @move="moveDictItem(index, $event)"
+                  />
                   <el-button
                     v-if="formData.sysDictDataList.length > 1"
-                    type="danger"
                     link
+                    class="delete-botton"
                     @click="removeDictItem(index)"
                   >
-                    <el-icon> <Delete /> </el-icon>删除
+                    <el-icon><Delete /></el-icon>
                   </el-button>
                 </div>
               </div>
@@ -68,18 +59,45 @@
                 <el-input v-model="item.itemCode" placeholder="请输入" />
               </el-form-item>
               <el-form-item label="图标">
-                <el-upload
+                <!-- // 在模板部分修改上传组件的ref绑定 -->
+                <!-- <el-upload
+                  :ref="(el) => setUploadRef(index, el)"
                   v-model:file-list="item.fileList"
                   :auto-upload="false"
                   list-type="picture-card"
                   :limit="1"
-                  :on-preview="(file) => handlePictureCardPreview(file, index)"
+                  :on-preview="(file) => handlePictureCardPreview(file)"
                   :on-remove="() => handleRemove(index)"
                   :on-change="(file) => handleChange(file, index)"
+                  :on-exceed="(files) => handleExceed(files, index)"
                 >
                   <el-icon>
                     <Plus />
                   </el-icon>
+                </el-upload> -->
+                <el-upload
+                  :ref="(el) => setUploadRef(index, el)"
+                  v-model:file-list="item.fileList"
+                  :auto-upload="false"
+                  list-type="picture-card"
+                  :limit="1"
+                  :on-change="(file) => handleChange(file, index)"
+                  :on-exceed="(files) => handleExceed(files, index)"
+                >
+                  <el-icon><Plus /></el-icon>
+                  <template #file="{ file }">
+                    <div>
+                      <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />
+                      <span class="el-upload-list__item-actions">
+                        <span class="el-upload-list__item-preview" @click="handlePictureCardPreview(file)">
+                          <el-icon><zoom-in /></el-icon>
+                        </span>
+                        <span class="el-upload-list__item-delete" @click="handleRemove(index)">
+                          <el-icon><Delete /></el-icon>
+                        </span>
+                      </span>
+                    </div>
+                  </template>
                 </el-upload>
               </el-form-item>
             </div>
@@ -89,10 +107,10 @@
 
       <el-form-item>
         <el-button type="primary" link @click="addDictItem">
-          <el-icon>
+          <el-icon :size="16">
             <CirclePlus />
           </el-icon>
-          新增字典分类
+          <span class="add-text">新增</span>
         </el-button>
       </el-form-item>
 
@@ -115,14 +133,14 @@
         </el-radio-group>
       </el-form-item>
 
-      <el-form-item class="form-footer">
+      <div class="form-footer">
         <el-button @click="handleCancel">取消</el-button>
         <el-button type="primary" @click="handleSubmit">提交</el-button>
-      </el-form-item>
+      </div>
     </el-form>
   </el-drawer>
 
-  <el-dialog v-model="dialogVisible">
+  <el-dialog v-model="dialogVisible" width="30%">
     <div class="dialog-content">
       <img :src="dialogImageUrl" alt="Preview Image" />
     </div>
@@ -147,12 +165,17 @@
     FormRules,
     UploadProps,
     UploadUserFile,
+    UploadInstance,
+    UploadRawFile,
+    genFileId,
+    ElMessage,
   } from 'element-plus';
-  import { Plus, Delete, CirclePlus, Top, Bottom } from '@element-plus/icons-vue';
+  import { Plus, Delete, CirclePlus, ZoomIn } from '@element-plus/icons-vue';
   import { dictionaryTypeOptions, DictionaryStatus, dictionaryStatusOptions } from '../constants';
   import { queryDictTypeDetail } from '@/api/dict';
   import { uploadFileApi, UPLOAD_BIZ_TYPE } from '@/api/minio';
   import { cloneDeep } from 'lodash-es';
+  import MoveButton from './MoveButton.vue';
 
   interface SysDictDataItem {
     id?: string | number; // 可选,用于编辑时
@@ -282,6 +305,7 @@
   const handleRemove = (itemIndex: number) => {
     if (formData.sysDictDataList[itemIndex]) {
       formData.sysDictDataList[itemIndex].imageUrl = ''; // 如果有单独的 URL 字段
+      formData.sysDictDataList[itemIndex].fileList = [];
     }
   };
 
@@ -301,6 +325,26 @@
     }
   };
 
+  // 添加上传组件引用数组
+  const uploadRefs = ref<UploadInstance[]>([]);
+  const setUploadRef = (index: number, el: any) => {
+    uploadRefs.value[index] = el;
+  };
+
+  // 修改handleExceed方法
+  const handleExceed: UploadProps['onExceed'] = (files: File[], index: number) => {
+    const uploadInstance = uploadRefs.value[index];
+    if (!uploadInstance) return;
+
+    // 清空当前实例的文件
+    uploadInstance.clearFiles();
+
+    // 添加新文件
+    const file = files[0] as UploadRawFile;
+    file.uid = genFileId();
+    uploadInstance.handleStart(file);
+  };
+
   const handleSubmit = async () => {
     if (!formRef.value) return;
 
@@ -320,6 +364,15 @@
     });
   };
 
+  const hoverState = reactive({
+    up: false,
+    down: false,
+  });
+
+  const handleHover = (event: Event, type: 'up' | 'down', isEnter = true) => {
+    hoverState[type] = isEnter;
+  };
+
   // 移动方法
   const moveDictItem = (index: number, direction: 'up' | 'down') => {
     const items = formData.sysDictDataList;
@@ -365,6 +418,7 @@
 
 <style lang="scss" scoped>
   .add-dict-form {
+    // padding-bottom: 40px;
     .el-select,
     .el-input-number {
       width: 100%;
@@ -373,9 +427,9 @@
 
   .dict-item-group {
     padding: 15px;
-    border: 1px solid #dcdfe6;
     border-radius: 4px;
     margin-bottom: 20px;
+    background-color: #f0f2f5;
     position: relative;
 
     .dict-item-header {
@@ -392,8 +446,22 @@
   }
 
   .form-footer {
+    position: sticky;
+    bottom: 0;
+    background: white;
+    padding: 20px 0;
+    z-index: 100;
+    box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.06);
     text-align: right;
-    margin-top: 20px;
+  }
+
+  .add-dict-form {
+    height: calc(100vh - 120px); // 根据实际抽屉高度调整
+    overflow-y: auto;
+    .el-select,
+    .el-input-number {
+      width: 100%;
+    }
   }
 
   // 覆盖 el-upload 的样式,使其适应小图标场景
@@ -425,27 +493,32 @@
   }
 
   .dict-item-header {
-    display: flex;
-    justify-content: flex-end;
-    align-items: center;
     margin-bottom: 10px;
 
     .move-buttons {
+      display: flex;
+      align-items: center;
+      justify-content: end;
+      width: 100%;
       margin-right: auto;
       .el-button {
         padding: 5px;
-        margin-right: 8px;
+        // margin-right: 8px;
       }
     }
   }
 
   .dialog-content {
-    width: 100%;
-    height: 100%;
+    // width: 600px;
+    // height: 600px;
 
     img {
       width: 100%;
       height: 100%;
     }
   }
+
+  .add-text {
+    margin-left: 10px;
+  }
 </style>

+ 37 - 0
src/views/system/dictionary/components/MoveButton.vue

@@ -0,0 +1,37 @@
+<template>
+  <el-button type="primary" link @click="handleClick" @mouseenter="hoverState = true" @mouseleave="hoverState = false">
+    <el-icon size="18">
+      <img :src="currentIcon" :alt="type === 'up' ? '上移' : '下移'" />
+    </el-icon>
+  </el-button>
+</template>
+
+<script lang="ts" setup>
+  import { computed, ref } from 'vue';
+  import upActive from '@/assets/icons/sortup_active.svg';
+  import upHover from '@/assets/icons/sortup.svg';
+  import downActive from '@/assets/icons/sortdown_active.svg';
+  import downHover from '@/assets/icons/sortdown.svg';
+
+  const props = defineProps({
+    type: {
+      type: String as () => 'up' | 'down',
+      required: true,
+    },
+  });
+
+  const emit = defineEmits(['move']);
+
+  const hoverState = ref(false);
+
+  const currentIcon = computed(() => {
+    if (props.type === 'up') {
+      return hoverState.value ? upHover : upActive;
+    }
+    return hoverState.value ? downHover : downActive;
+  });
+
+  const handleClick = () => {
+    emit('move', props.type);
+  };
+</script>

+ 48 - 40
src/views/system/dictionary/dictionary.vue

@@ -1,43 +1,51 @@
 <template>
+  <Breadcrumb title="字典管理" :show-icon="false" />
   <div class="dictionary-container">
-    <div class="table-operations">
-      <el-button type="primary" @click="handleAddDialogShow">新增字典</el-button>
-    </div>
-
-    <el-table v-loading="loading" height="calc(100vh - 220px)" :data="dataSource" style="width: 100%" border>
-      <el-table-column prop="dictName" label="字典名称" />
-      <el-table-column prop="dictCode" label="字典编码" />
-      <el-table-column prop="description" label="字典描述" show-overflow-tooltip />
-      <el-table-column prop="dictType" label="分类" width="180">
-        <template #default="{ row }">
-          {{ typeLabelMap[row.dictType] || '' }}
-        </template>
-      </el-table-column>
-      <el-table-column prop="status" label="状态" width="180">
-        <template #default="{ row }">
-          {{ statusLabelMap[row.status] || '' }}
-        </template>
-      </el-table-column>
-      <el-table-column label="操作" width="200" fixed="right">
-        <template #default="{ row }">
-          <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
-          <el-button type="danger" link @click="handleDelete(row)">删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <div class="pagination-container">
-      <el-pagination
-        v-model:current-page="currentPage"
-        v-model:page-size="pageSize"
-        :page-sizes="[10, 20, 50, 100]"
-        :total="totalRow"
-        layout="total, sizes, prev, pager, next, jumper"
-        @size-change="handleSizeChange"
-        @current-change="handleCurrentChange"
-      />
-    </div>
-
+    <el-card shadow="hover">
+      <div class="table-operations">
+        <el-button type="primary" @click="handleAddDialogShow" :icon="Plus">新增字典项</el-button>
+      </div>
+
+      <el-table
+        v-loading="loading"
+        height="calc(100vh - 300px)"
+        :data="dataSource"
+        style="width: 100%; margin-top: 16px"
+      >
+        <el-table-column prop="dictName" label="字典名称" />
+        <el-table-column prop="dictCode" label="字典编码" />
+        <el-table-column prop="description" label="字典描述" show-overflow-tooltip />
+        <el-table-column prop="dictType" label="分类" width="180">
+          <template #default="{ row }">
+            {{ typeLabelMap[row.dictType] || '' }}
+          </template>
+        </el-table-column>
+        <el-table-column prop="status" label="状态" width="180">
+          <template #default="{ row }">
+            {{ statusLabelMap[row.status] || '' }}
+          </template>
+        </el-table-column>
+        <el-table-column label="操作" width="200" fixed="right">
+          <template #default="{ row }">
+            <el-button type="primary" link @click="handleEdit(row)">编辑</el-button>
+            <el-button type="primary" link @click="handleDelete(row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <div class="pagination-container">
+        <el-pagination
+          v-model:current-page="currentPage"
+          v-model:page-size="pageSize"
+          :page-sizes="[10, 20, 50, 100]"
+          :total="totalRow"
+          background
+          layout="total, prev, pager, next, sizes, jumper"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </el-card>
     <AddDict
       v-if="dialogVisible"
       ref="addDictRef"
@@ -51,10 +59,12 @@
 <script lang="ts" setup>
   import { ref, onMounted, computed } from 'vue';
   import { ElMessage, ElMessageBox } from 'element-plus';
+  import { Plus } from '@element-plus/icons-vue';
   import AddDict from './components/AddDict.vue';
   import { createDictApi, SaveDictParams, updateDict, deleteDict } from '@/api/dict';
   import { useDataSource } from './useDataSource';
   import { dictionaryStatusOptions, dictionaryTypeOptions } from './constants';
+  import Breadcrumb from '@/components/Breadcrumb.vue';
 
   // 表格数据
   const loading = ref(false);
@@ -156,8 +166,6 @@
 
 <style lang="scss" scoped>
   .dictionary-container {
-    padding: 16px;
-
     .search-form {
       margin-bottom: 16px;
     }