123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- <template>
- <div class="le-select-role">
- <el-input :model-value="modelValue" style="display: none" />
- <el-tooltip v-if="!disabled" content="添加角色" placement="left">
- <el-button style="width: 32px" @click="selectHandler">
- <svg-icon style="font-size: 18px" icon-class="flow-group-add" />
- </el-button>
- </el-tooltip>
- <FlowNodeAvatar v-for="(item, i) of modelValue" :key="i" :name="item.name">
- <template #avatar>
- <svg-icon icon-class="flow-group" color="#fff" />
- </template>
- </FlowNodeAvatar>
- <el-dialog v-model="dialogVisible" class="le-dialog" title="角色选择" :width="460" destroy-on-close append-to-body>
- <div class="sc-user-select sc-user-select-role">
- <div class="sc-user-select__left">
- <div class="sc-user-select__select">
- <div v-loading="dataInfo.loading" class="sc-user-select__tree">
- <el-scrollbar>
- <el-tree
- ref="treeRef"
- class="menu"
- :data="dataInfo.list"
- :node-key="roleProps.key"
- :props="roleProps"
- show-checkbox
- check-strictly
- check-on-click-node
- :expand-on-click-node="false"
- :default-checked-keys="selectedIds"
- @check-change="checkChange"
- />
- </el-scrollbar>
- </div>
- </div>
- </div>
- <div class="sc-user-select__toicon">
- <el-icon><ArrowRight /></el-icon>
- </div>
- <div class="sc-user-select__selected">
- <header>已选 ({{ selected.length }})</header>
- <ul style="padding: 0; margin: 0">
- <el-scrollbar>
- <li v-for="(item, index) in selected" :key="item.id">
- <span class="name">
- <label>{{ item.name || '-' }}</label>
- </span>
- <span class="delete">
- <el-button type="danger" icon="Delete" circle size="small" @click="removeItem(index)" />
- </span>
- </li>
- </el-scrollbar>
- </ul>
- </div>
- </div>
- <template #footer>
- <el-button @click="dialogVisible = false">取消</el-button>
- <el-button type="primary" @click="submit">确认</el-button>
- </template>
- </el-dialog>
- </div>
- </template>
- <script lang="tsx" setup>
- import { watch, unref, ref, computed, PropType } from 'vue'
- import FlowNodeAvatar from '@/components/Flow/FlowNodeAvatar.vue'
- import role from '@/api/system/role.ts'
- import { ElMessage } from 'element-plus'
- defineOptions({ name: 'LeSelectRole' })
- const emit = defineEmits(['update:modelValue', 'change', 'input', 'update:visible', 'getCurRow'])
- type Item = { name: string; id: string; [key: string]: any }
- const props = defineProps({
- modelValue: {
- type: Array as PropType<Item[]>,
- default: () => []
- },
- min: { type: Number, default: 0 },
- max: { type: Number, default: 999999 },
- disabled: {
- type: Boolean,
- default: false
- },
- // params: {
- // type: Object
- // }
- })
- const treeRef = ref()
- const dialogVisible = ref(false)
- const dataInfo = ref({ list: [], loading: false })
- const roleProps = {
- key: 'id',
- label: 'name',
- children: 'children'
- }
- // 命中的数据
- const selected = ref<Item[]>([])
- const selectedIds = computed(() => {
- return selected.value.map(v => v.id)
- })
- watch(
- () => props.modelValue,
- vals => {
- selected.value = JSON.parse(JSON.stringify(vals || []))
- },
- {
- immediate: true,
- deep: true
- }
- )
- const checkChange = (data, checked) => {
- console.log(data, checked, 'data, checked')
- if (checked) {
- selected.value.push({
- id: data.id,
- name: data.name
- })
- } else {
- const idx = selected.value.findIndex(v => v.id === data.id)
- if (idx >= 0) {
- selected.value.splice(idx, 1)
- }
- }
- }
- const removeItem = (index: number) => {
- selected.value.splice(index, 1)
- treeRef.value?.setCheckedKeys(selectedIds.value)
- }
- // const { t } = useI18n()
- const selectHandler = (nodeKey: string, type: 1 | 3) => {
- console.log(nodeKey, 'nodeKey type', type)
- dialogVisible.value = true
- const _info = dataInfo.value
- if (!_info.loading && !_info.list.length) {
- queryRoleData()
- }
- }
- const queryRoleData = () => {
- dataInfo.value.loading = true
- role
- .rolePageApi({ page: 1, pageSize: 999 })
- .then((res: any) => {
- dataInfo.value = {
- list: res.records || [],
- loading: false
- }
- })
- .catch(() => {
- dataInfo.value.loading = false
- })
- }
- const submit = () => {
- // props.modelValue
- const _selected = selected.value
- if (!Array.isArray(_selected)) return ElMessage.warning('请选择数据')
- // 最小限制
- if (_selected.length < props.min) return ElMessage.warning(`选中的数据个数不能小于${props.min}条`)
- // 最大限制
- if (_selected.length > props.max) return ElMessage.warning(`选中的数据个数不能大于${props.max}条`)
- dialogVisible.value = false
- emit('update:modelValue', _selected)
- emit('change', _selected)
- console.log('我submit了...')
- // emit('input', _selected)
- }
- // const { prefixIcon, suffixIcon, prop, controlsPosition, t_placeholder, size, placeholder, max = 999999999999999, ...local_props } = ctx.attrs
- </script>
- <style scoped lang="scss">
- .le-select-role {
- display: flex;
- align-items: center;
- gap: 6px;
- flex-wrap: wrap;
- min-height: 32px;
- }
- .sc-user-select {
- display: flex;
- .sc-user-select__left {
- width: 200px;
- }
- .sc-user-select__tree {
- width: 200px;
- //height: 300px;
- //border: none;
- height: 343px;
- }
- .sc-user-select__toicon {
- display: flex;
- justify-content: center;
- align-items: center;
- margin: 0 10px;
- }
- .sc-user-select__toicon i {
- display: flex;
- justify-content: center;
- align-items: center;
- background: #ccc;
- width: 20px;
- height: 20px;
- text-align: center;
- line-height: 20px;
- border-radius: 50%;
- color: #fff;
- }
- .sc-user-select__select {
- display: flex;
- border: 1px solid var(--el-border-color-light);
- background: var(--el-color-white);
- }
- .sc-user-select__selected {
- height: 345px;
- width: 200px;
- border: 1px solid var(--el-border-color-light);
- background: var(--el-color-white);
- header {
- height: 43px;
- line-height: 43px;
- border-bottom: 1px solid var(--el-border-color-light);
- padding: 0 15px;
- font-size: 12px;
- }
- ul {
- height: 300px;
- overflow: auto;
- }
- li {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 5px 5px 5px 15px;
- height: 38px;
- .name {
- display: flex;
- align-items: center;
- .el-avatar {
- background: var(--el-color-primary);
- margin-right: 10px;
- }
- label {
- }
- }
- .delete {
- display: none;
- }
- &:hover {
- background: var(--el-color-primary-light-9);
- .delete {
- display: inline-block;
- }
- }
- }
- }
- }
- </style>
|