Przeglądaj źródła

新增 TagSwitch 项目级通用组件

夜鹰 8 miesięcy temu
rodzic
commit
7341bf1f74

+ 22 - 0
Web/src/components/TagSwitch/README.md

@@ -0,0 +1,22 @@
+# `TagSwitch` 使用说明
+
+`TagSwitch`,是基于 [喵你个汪](https://https://gitee.com/jasondom) PR的 `SysDict`组件封装的标签开关,展示状态下显示为 tag 标签,需要修改时,移动鼠标至 `tag` 上将自动切换为 `switch` ,点击即可切换。本组件与 `switch` 一样,适用于仅有两个不同值的场景(如: 启用/禁用、 是/否、 男/女 等)。
+
+---
+
+## 如何使用
+
+```html
+<template>
+	<tag-switch v-model="你要绑定的值" :active-value="switch打开时的值" :inactive-value="switch关闭时的值" code="字典编码" @change="change回调的方法" />
+</template>
+<script lang="ts" setup>
+import TagSwitch from '/@/components/TagSwitch/index.vue';
+</script>
+```
+
+注意:`code` 必须为在系统中已经配置的数据字典
+
+---
+
+最新更新于 2025.09.29

+ 93 - 0
Web/src/components/TagSwitch/index.vue

@@ -0,0 +1,93 @@
+<template>
+    <div class="tagsw">
+        <el-switch size="small" class="tagsw-switch" 
+            v-model="tgswModelValue"
+            :active-value="activeValue"
+            :inactive-value="inactiveValue" 
+            @change="handleChange"
+        />
+        <span class="tagsw-tage">
+            <GSysDict v-model="tgswModelValue" :code="code" />
+        </span>
+    </div>
+</template>
+
+<script lang="ts" setup name="TagSwitch">
+import { computed, PropType } from 'vue';
+import GSysDict from "/@/components/sysDict/sysDict.vue";
+
+const emit = defineEmits(['change', 'update:modelValue']);
+
+const props = defineProps({
+    /**
+     * 绑定的值,支持多种类型
+     * @example
+     * <tag-switch v-model="value" code="xxxx" />
+   */
+    modelValue: {
+        type: [String, Number, Boolean, Array, null] as PropType<string | number | boolean | any[] | null>,
+        default: null,
+        required: true,
+    },
+
+    /**
+     * 字典编码,用于获取字典项 (同sys-dict)
+     * @example 'gender'
+   */
+    code: {
+        type: String,
+        required: true,
+    },
+    
+    /**
+     * switch 状态为 on 时的值,默认true (同el-switch)
+     * @example true
+     */
+    activeValue: {
+        type: [String, Number, Boolean] as PropType<string | number | boolean>,
+        default: true,
+    },
+    /**
+     * switch的状态为 off 时的值,默false (同el-switch)
+     * @example false
+     */
+    inactiveValue: {
+        type: [String, Number, Boolean] as PropType<string | number | boolean>,
+        default: false,
+    },
+});
+const tgswModelValue = computed({
+    get: () => props.modelValue,
+    set: (val) => emit('update:modelValue', val),
+});
+
+
+const handleChange = (val: any) => {
+    emit('change', val);
+};
+</script>
+
+<style lang="scss" scoped>
+.tagsw {
+    //width: 100%;
+
+    .tagsw-switch {
+        display: none;
+        height: 100%;
+        line-height: 100%;
+    }
+
+    .tagsw-tage {
+        display: block;
+    }
+}
+.tagsw:hover {
+    .tagsw-switch {
+        display: inline-flex;
+    }
+
+    .tagsw-tage {
+        display: none;
+    }
+}
+</style>

+ 2 - 2
Web/src/theme/element.scss

@@ -398,11 +398,11 @@
 	padding: 15px 20px;
 }
 .el-card__body {
-	padding: 8px;
+	--el-card-padding: 8px;
 }
    // 由于card没有size属性,所以通过其子元素来判断,当组件大小选择为默认时
 .el-card__body:has(.el-table--default) {
-    padding: 20px;
+    --el-card-padding: 20px;
 }
 
 /* Table 表格 element plus 2.2.0 版本

+ 1 - 1
Web/src/views/system/dict/component/editDictData.vue

@@ -65,7 +65,7 @@
 					</el-col>
 					<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
 						<el-form-item label="拓展数据">
-							<el-input v-model="state.ruleForm.extData" placeholder="请输入拓展数据" clearable type="textarea" rows="6" />
+							<el-input v-model="state.ruleForm.extData" placeholder="请输入拓展数据" clearable type="textarea" :rows="6" />
 						</el-form-item>
 					</el-col>
 				</el-row>

+ 17 - 9
Web/src/views/system/dict/index.vue

@@ -6,7 +6,8 @@
 					<template #header>
 						<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-Collection /></el-icon>字典
 					</template>
-					<el-form :model="state.queryDictTypeParams" ref="queryForm" :inline="true" @submit.native.prevent>
+                    
+					<el-form :model="state.queryDictTypeParams" ref="queryForm" :inline="true" @submit.native.prevent class="handle-form">
 						<el-form-item label="名称">
 							<el-input v-model="state.queryDictTypeParams.name" @keyup.enter.native="handleDictTypeQuery" placeholder="字典名称" clearable />
 						</el-form-item>
@@ -23,24 +24,24 @@
 							<el-button type="primary" icon="ele-Plus" @click="openAddDictType" v-auth="'sysDictType:add'"> 新增 </el-button>
 						</el-form-item>
 					</el-form>
-
+                    
 					<el-table :data="state.dictTypeData" style="width: 100%" v-loading="state.typeLoading" @row-click="handleDictType" highlight-current-row @sort-change="sortChangeDityType" border>
 						<el-table-column type="index" label="序号" width="55" align="center" sortable='custom' />
 						<el-table-column prop="name" label="字典名称" min-width="120" header-align="center" sortable='custom' show-overflow-tooltip />
 						<el-table-column prop="code" label="字典编码" min-width="140" header-align="center" sortable='custom' show-overflow-tooltip />
 						<el-table-column prop="sysFlag" label="系统内置" min-width="90" align="center" sortable='custom' show-overflow-tooltip v-if="userInfo.accountType === AccountTypeEnum.NUMBER_999">
 							<template #default="scope">
-                <g-sys-dict v-model="scope.row.sysFlag" code="YesNoEnum" />
+                                <g-sys-dict v-model="scope.row.sysFlag" code="YesNoEnum" />
 							</template>
 						</el-table-column>
 						<el-table-column prop="isTenant" label="租户字典" min-width="90" align="center"  sortable='custom'  show-overflow-tooltip v-if="userInfo.accountType === AccountTypeEnum.NUMBER_999">
 							<template #default="scope">
-                <g-sys-dict v-model="scope.row.isTenant" code="YesNoEnum" />
+                                <g-sys-dict v-model="scope.row.isTenant" code="YesNoEnum" />
 							</template>
 						</el-table-column>
 						<el-table-column prop="status" label="状态" width="80" align="center"  sortable='custom'  show-overflow-tooltip>
 							<template #default="scope">
-                <g-sys-dict v-model="scope.row.status" code="StatusEnum" />
+                                <g-sys-dict v-model="scope.row.status" code="StatusEnum" />
 							</template>
 						</el-table-column>
 						<el-table-column prop="orderNo" label="排序" width="80" align="center"  sortable='custom'  show-overflow-tooltip />
@@ -79,7 +80,7 @@
 					<template #header>
 						<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-Collection /></el-icon>字典值【{{ state.editDictTypeName }}】
 					</template>
-					<el-form :model="state.queryDictDataParams" ref="queryForm" :inline="true" @submit.native.prevent>
+					<el-form :model="state.queryDictDataParams" ref="queryForm" :inline="true" @submit.native.prevent class="handle-form">
 						<el-form-item label="显示文本">
 							<el-input v-model="state.queryDictDataParams.label" placeholder="显示文本" @keyup.enter="handleDictDataQuery" />
 						</el-form-item>
@@ -111,7 +112,7 @@
 						</el-table-column>
 						<el-table-column prop="status" label="状态" width="70" align="center" show-overflow-tooltip>
 							<template #default="scope">
-                <g-sys-dict v-model="scope.row.status" code="StatusEnum" />
+                                <g-sys-dict v-model="scope.row.status" code="StatusEnum" />
 							</template>
 						</el-table-column>
 						<el-table-column prop="orderNo" label="排序" width="60" align="center" show-overflow-tooltip />
@@ -158,7 +159,7 @@ import { onMounted, reactive, ref } from 'vue';
 import { getAPI } from '/@/utils/axios-utils';
 import { useUserInfo } from '/@/stores/userInfo';
 import { ElMessageBox, ElMessage } from 'element-plus';
-import {SysDictType, SysDictData, UpdateDictDataInput, AccountTypeEnum} from '/@/api-services/models';
+import {SysDictType, SysDictData, AccountTypeEnum} from '/@/api-services/models';
 import { SysDictTypeApi, SysDictDataApi } from '/@/api-services/api';
 import EditDictType from '/@/views/system/dict/component/editDictType.vue';
 import EditDictData from '/@/views/system/dict/component/editDictData.vue';
@@ -361,10 +362,17 @@ const updateDictSession = async () => {
 };
 </script>
 
-<style scoped>
+<style lang="scss" scoped>
 .sys-dict-container {
     flex-direction: row !important;
 }
+.handle-form {
+    margin-bottom: var(--el-card-padding);
+
+    .el-form-item, .el-form-item:last-of-type {
+        margin: 0 10px !important;
+    }
+}
 :deep(.notice-bar) {
 	position: absolute;
 	display: inline-flex;

+ 2 - 2
Web/src/views/system/user/index.vue

@@ -72,8 +72,7 @@
 							show-overflow-tooltip />
 						<el-table-column label="状态" width="70" align="center" show-overflow-tooltip>
 							<template #default="scope">
-								<el-switch v-model="scope.row.status" :active-value="1" :inactive-value="2" size="small"
-									@change="changeStatus(scope.row)" v-auth="'sysUser:setStatus'" />
+								<TagSwitch v-model="scope.row.status" :active-value="1" :inactive-value="2" code="StatusEnum" @change="changeStatus(scope.row)" v-auth="'sysUser:setStatus'" />
 							</template>
 						</el-table-column>
 						<el-table-column prop="orderNo" label="排序" width="70" align="center" show-overflow-tooltip />
@@ -140,6 +139,7 @@ import 'splitpanes/dist/splitpanes.css';
 import { getAPI } from '/@/utils/axios-utils';
 import { SysUserApi, SysOrgApi } from '/@/api-services/api';
 import { SysUser, UpdateUserInput, OrgTreeOutput } from '/@/api-services/models';
+import TagSwitch from '/@/components/TagSwitch/index.vue';
 
 const orgTreeRef = ref<InstanceType<typeof OrgTree>>();
 const editUserRef = ref<InstanceType<typeof EditUser>>();