feat:审批

This commit is contained in:
dzc committed 2025-01-12 20:49:49 +08:00
1 parent f5c3e0b0ea
commit cd86ae5521
18 files changed
+2025 -1658

No files matched your search

+160 -148
View File
@@ -1,179 +1,191 @@
<template>
<el-dialog :title="$t('orgSelecotr.select') + $t(`orgSelecotr.${props.type}`)" v-model="visibleDialog" :width="600" append-to-body class="promoter_person">
<div class="person_body clear">
<div class="person_tree l">
<selectBox ref="selectBoxRef" :selectSelf="selectSelf" :list="list" :multiple="multiple"
v-model:selectedList="selectedList" :type="type"/>
</div>
<selectResult :total="total" @del="delList" :list="resList"/>
</div>
<template #footer>
<el-button @click="$emit('update:visible', false)">{{ $t('common.cancelButtonText') }}</el-button>
<el-button type="primary" @click="saveDialog">{{ $t('common.confirmButtonText') }}</el-button>
</template>
</el-dialog>
<el-dialog
:title="$t('orgSelecotr.select') + $t(`orgSelecotr.${props.type}`)"
v-model="visibleDialog"
:width="600"
append-to-body
class="promoter_person"
>
<div class="person_body clear">
<div class="person_tree l">
<selectBox
ref="selectBoxRef"
:selectSelf="selectSelf"
:list="list"
:multiple="multiple"
v-model:selectedList="selectedList"
:type="type"
/>
</div>
<selectResult :total="total" @del="delList" :list="resList" />
</div>
<template #footer>
<el-button @click="$emit('update:visible', false)">{{ $t("common.cancelButtonText") }}</el-button>
<el-button type="primary" @click="saveDialog">{{ $t("common.confirmButtonText") }}</el-button>
</template>
</el-dialog>
</template>
<script setup>
import selectBox from './selectBox.vue';
import selectResult from './selectResult.vue';
import {computed, watch, ref, onMounted} from 'vue';
import {departments, searchVal} from './common';
import other from '/@/utils/other';
import {useI18n} from "vue-i18n";
import selectBox from "./selectBox.vue"
import selectResult from "./selectResult.vue"
import { computed, watch, ref, onMounted } from "vue"
import { departments, searchVal } from "./common"
import other from "/@/utils/other"
import { useI18n } from "vue-i18n"
const selectBoxRef = ref();
const selectBoxRef = ref()
let props = defineProps({
visible: {
type: Boolean,
default: false,
},
data: {
type: Array,
default: () => [],
},
type: {
type: String,
default: 'user',
},
multiple: {
type: Boolean,
default: true,
},
selectSelf: {
type: Boolean,
default: true,
},
});
visible: {
type: Boolean,
default: false,
},
data: {
type: Array,
default: () => [],
},
type: {
type: String,
default: "user",
},
multiple: {
type: Boolean,
default: true,
},
selectSelf: {
type: Boolean,
default: true,
},
})
//已选择的集合
let selectedList = ref([]);
let selectedList = ref([])
let emits = defineEmits(['update:visible', 'change']);
let emits = defineEmits(["update:visible", "change"])
let visibleDialog = computed({
get() {
return props.visible;
},
set() {
closeDialog();
},
});
get() {
return props.visible
},
set() {
closeDialog()
},
})
const isChecked = (id, type) => {
return selectedList.value.filter((res) => res.id === id && res.type === type).length > 0;
};
return selectedList.value.filter((res) => res.id === id && res.type === type).length > 0
}
let list = computed(() => {
let value = departments.value;
return [
{
type: 'dept',
data: value === undefined ? [] : value.childDepartments,
},
{
type: 'role',
data: value === undefined ? [] : value.roleList,
},
{
type: 'user',
data: value === undefined ? [] : value.employees,
change: (item) => {
if (!isChecked(item.id, item.type)) {
if (!props.multiple) {
//单选
selectedList.value = [];
}
let value = departments.value
return [
{
type: "dept",
data: value === undefined ? [] : value.childDepartments,
},
{
type: "role",
data: value === undefined ? [] : value.roleList,
},
{
type: "user",
data: value === undefined ? [] : value.employees,
change: (item) => {
if (!isChecked(item.id, item.type)) {
if (!props.multiple) {
//单选
selectedList.value = []
}
selectedList.value.push(item);
} else {
selectedList.value = selectedList.value.filter((res) => !(res.id === item.id && res.type === item.type));
}
},
},
];
});
selectedList.value.push(item)
} else {
selectedList.value = selectedList.value.filter((res) => !(res.id === item.id && res.type === item.type))
}
},
},
]
})
let resList = computed(() => {
let userData = selectedList.value.filter((res) => res.type === 'user');
let deptData = selectedList.value.filter((res) => res.type === 'dept');
let roleData = selectedList.value.filter((res) => res.type === 'role');
let userData = selectedList.value.filter((res) => res.type === "user")
let deptData = selectedList.value.filter((res) => res.type === "dept")
let roleData = selectedList.value.filter((res) => res.type === "role")
let data = [
{
type: 'user',
data: userData,
cancel: (item) => {
item.selected = false;
selectBoxRef.value.changeEvent(item);
},
},
];
if (props.type === 'org' || props.type === 'dept') {
data.unshift({
type: 'dept',
data: deptData,
cancel: (item) => {
item.selected = false;
selectBoxRef.value.changeEvent(item);
},
});
}
if (props.type === 'role') {
data.unshift({
type: 'role',
data: roleData,
cancel: (item) => {
item.selected = false;
selectBoxRef.value.changeEvent(item);
},
});
}
return data;
});
let data = [
{
type: "user",
data: userData,
cancel: (item) => {
item.selected = false
selectBoxRef.value.changeEvent(item)
},
},
]
if (props.type === "org" || props.type === "dept") {
data.unshift({
type: "dept",
data: deptData,
cancel: (item) => {
item.selected = false
selectBoxRef.value.changeEvent(item)
},
})
}
if (props.type === "role") {
data.unshift({
type: "role",
data: roleData,
cancel: (item) => {
item.selected = false
selectBoxRef.value.changeEvent(item)
},
})
}
return data
})
watch(
() => props.visible,
(val) => {
if (val) {
selectedList.value = props.data;
searchVal.value = '';
}
}
);
() => props.visible,
(val) => {
if (val) {
selectedList.value = props.data
searchVal.value = ""
}
},
)
const closeDialog = () => {
emits('update:visible', false);
};
emits("update:visible", false)
}
let total = computed(() => {
let v = departments.value;
if (!v) {
return 0;
}
return selectedList.value.length;
});
let v = departments.value
if (!v) {
return 0
}
return selectedList.value.length
})
const {proxy} = getCurrentInstance();
const { proxy } = getCurrentInstance()
let saveDialog = () => {
const v = selectedList.value;
const v = selectedList.value
let checkedList = other.deepClone(v).map((item) => ({
type: item.type,
id: item.id,
name: item.name,
avatar: item.avatar,
}));
emits('change', checkedList);
//selectedList.value=[]
};
let checkedList = other.deepClone(v).map((item) => ({
type: item.type,
id: item.id,
name: item.name,
avatar: item.avatar,
}))
emits("change", checkedList)
//selectedList.value=[]
}
const delList = () => {
for (const item of other.deepClone(selectedList.value)) {
item.selected = false;
selectBoxRef.value.changeEvent(item);
}
selectedList.value = [];
};
for (const item of other.deepClone(selectedList.value)) {
item.selected = false
selectBoxRef.value.changeEvent(item)
}
selectedList.value = []
}
</script>
<style scoped>
@import './dialog.css';
@import "./dialog.css";
</style>
+212 -206
View File
@@ -1,291 +1,297 @@
<template>
<div>
<el-input
v-model="searchVal"
class="w-50 m-2"
style="width: 100%"
v-if="type === 'user'"
:placeholder="$t('orgSelecotr.search')"
@input="getDebounceData($event)"
:prefix-icon="Search"
/>
<p class="ellipsis tree_nav" v-if="!searchVal && type !== 'role'">
<span @click="queryData(0)" class="ellipsis">根节点</span>
<span v-for="(item, index) in departments.titleDepartments" class="ellipsis" :key="index + 'a'" @click="queryData(item.id)">{{
item.name
}}</span>
</p>
<div>
<el-input
v-model="searchVal"
class="w-50 m-2"
style="width: 100%"
v-if="type === 'user'"
:placeholder="$t('orgSelecotr.search')"
@input="getDebounceData($event)"
:prefix-icon="Search"
/>
<p class="ellipsis tree_nav" v-if="!searchVal && type !== 'role'">
<span @click="queryData(0)" class="ellipsis">根节点</span>
<span
v-for="(item, index) in departments.titleDepartments"
class="ellipsis"
:key="index + 'a'"
@click="queryData(item.id)"
>{{ item.name }}</span
>
</p>
<ul class="select-box">
<template v-for="(elem, i) in dataList" :key="i">
<template v-if="elem.type === 'role'">
<li v-for="item in elem.data" :key="item.id">
<el-checkbox v-model="item.selected" @change="changeEvent(item)" :disabled="item.status === 0">
<div style="display: flex; flex-direction: row">
<div class="f11">
<el-icon style="font-size: 20px">
<Share />
</el-icon>
</div>
<div class="f12">{{ item.name }}</div>
</div>
</el-checkbox>
</li>
</template>
<template v-if="elem.type === 'dept' && (type === 'org' || type === 'dept' || type === 'user')">
<li v-for="item in elem.data" :key="item.id">
<div style="display: flex; flex-direction: row">
<div class="d11">
<el-checkbox v-model="item.selected" @change="changeEvent(item)" :disabled="!(type === 'org' || type === 'dept') || item.status == 0">
<div style="display: flex; flex-direction: row">
<div class="f11">
<el-icon style="font-size: 20px">
<Grid />
</el-icon>
</div>
<div class="f12">{{ item.name }}</div>
</div>
</el-checkbox>
</div>
<div class="d22" @click="queryData(item.id)">下级</div>
</div>
</li>
</template>
<template v-if="elem.type === 'user' && (type === 'org' || type === 'user')">
<li v-for="item in elem.data" :key="item.id" class="check_box">
<el-checkbox
v-model="item.selected"
:disabled="item.status === 0 || (!selectSelf && currentUserId === item.id)"
@change="changeEvent(item)"
>
<div style="display: flex; flex-direction: row">
<div class="f11">
<upload-img v-model:image-url="item.avatar" disabled width="20px" height="20px"/>
</div>
<div class="f12">{{ item.name }}</div>
</div>
</el-checkbox>
</li>
</template>
</template>
</ul>
</div>
<ul class="select-box">
<template v-for="(elem, i) in dataList" :key="i">
<template v-if="elem.type === 'role'">
<li v-for="item in elem.data" :key="item.id">
<el-checkbox v-model="item.selected" @change="changeEvent(item)" :disabled="item.status === 0">
<div style="display: flex; flex-direction: row">
<div class="f11">
<el-icon style="font-size: 20px">
<Share />
</el-icon>
</div>
<div class="f12">{{ item.name }}</div>
</div>
</el-checkbox>
</li>
</template>
<template v-if="elem.type === 'dept' && (type === 'org' || type === 'dept' || type === 'user')">
<li v-for="item in elem.data" :key="item.id">
<div style="display: flex; flex-direction: row">
<div class="d11">
<el-checkbox
v-model="item.selected"
@change="changeEvent(item)"
:disabled="!(type === 'org' || type === 'dept') || item.status == 0"
>
<div style="display: flex; flex-direction: row">
<div class="f11">
<el-icon style="font-size: 20px">
<Grid />
</el-icon>
</div>
<div class="f12">{{ item.name }}</div>
</div>
</el-checkbox>
</div>
<div class="d22" @click="queryData(item.id)">下级</div>
</div>
</li>
</template>
<template v-if="elem.type === 'user' && (type === 'org' || type === 'user')">
<li v-for="item in elem.data" :key="item.id" class="check_box">
<el-checkbox
v-model="item.selected"
:disabled="item.status === 0 || (!selectSelf && currentUserId === item.id)"
@change="changeEvent(item)"
>
<div style="display: flex; flex-direction: row">
<div class="f11">
<preview-image width="20px" height="20px" :src="item.avatar" />
</div>
<div class="f12">{{ item.name }}</div>
</div>
</el-checkbox>
</li>
</template>
</template>
</ul>
</div>
</template>
<script setup>
import {useUserInfo} from '/@/stores/userInfo';
import { useUserInfo } from "/@/stores/userInfo"
import {departments, getDebounceData, getDepartmentList, searchVal} from './common';
import other from '/@/utils/other';
import UploadImg from "/@/components/Upload/Image.vue";
import {Grid, Search, Share} from '@element-plus/icons-vue';
import { departments, getDebounceData, getDepartmentList, searchVal } from "./common"
import other from "/@/utils/other"
import UploadImg from "/@/components/Upload/Image.vue"
import { Grid, Search, Share } from "@element-plus/icons-vue"
var props = defineProps({
selectedList: {
type: Array,
default: () => [],
},
type: {
type: String,
default: 'org',
},
multiple: {
type: Boolean,
default: true,
},
selectSelf: {
type: Boolean,
default: true,
},
});
selectedList: {
type: Array,
default: () => [],
},
type: {
type: String,
default: "org",
},
multiple: {
type: Boolean,
default: true,
},
selectSelf: {
type: Boolean,
default: true,
},
})
const currentUserId = computed(() => {
return useUserInfo().userInfos.user.userId;
});
return useUserInfo().userInfos.user.userId
})
const queryData = (pid) => {
getDepartmentList(pid, props.type).then((res) => {
let selectedList = props.selectedList;
getDepartmentList(pid, props.type).then((res) => {
let selectedList = props.selectedList
for (const it of dataList.value) {
for (const item of it.data) {
item.selected = selectedList.filter((res) => res.id === item.id && res.type === item.type).length > 0;
}
}
});
};
for (const it of dataList.value) {
for (const item of it.data) {
item.selected = selectedList.filter((res) => res.id === item.id && res.type === item.type).length > 0
}
}
})
}
let deptList = computed(() => {
return departments.value.childDepartments;
});
return departments.value.childDepartments
})
let userList = computed(() => {
return departments.value.employees;
});
return departments.value.employees
})
let roleList = computed(() => {
return departments.value.roleList;
});
return departments.value.roleList
})
const dataList = computed(() => {
return [
{
type: 'dept',
data: deptList.value,
},
{
type: 'user',
data: userList.value,
},
{
type: 'role',
data: roleList.value,
}
];
});
return [
{
type: "dept",
data: deptList.value,
},
{
type: "user",
data: userList.value,
},
{
type: "role",
data: roleList.value,
},
]
})
const { proxy } = getCurrentInstance();
const { proxy } = getCurrentInstance()
let emits = defineEmits(['update:selectedList']);
let emits = defineEmits(["update:selectedList"])
onMounted(() => {
queryData(0);
});
queryData(0)
})
const changeEvent = (e) => {
let selectedList = other.deepClone(props.selectedList);
let selectedList = other.deepClone(props.selectedList)
if (e.selected) {
if (!props.multiple) {
userList.value.forEach((res) => (res.selected = false));
selectedList = [];
}
e.selected = true;
selectedList.push(e);
} else {
for (const it of dataList.value) {
let filter = it.data.filter((res) => res.id === e.id && res.type === e.type);
if (filter.length > 0) {
filter[0].selected = false;
}
}
selectedList = selectedList.filter((res) => !(res.id === e.id && res.type === e.type));
}
emits('update:selectedList', selectedList);
};
if (e.selected) {
if (!props.multiple) {
userList.value.forEach((res) => (res.selected = false))
selectedList = []
}
e.selected = true
selectedList.push(e)
} else {
for (const it of dataList.value) {
let filter = it.data.filter((res) => res.id === e.id && res.type === e.type)
if (filter.length > 0) {
filter[0].selected = false
}
}
selectedList = selectedList.filter((res) => !(res.id === e.id && res.type === e.type))
}
emits("update:selectedList", selectedList)
}
const refreshData = () => {
let selectedList = props.selectedList;
let selectedList = props.selectedList
for (var it of dataList.value) {
for (var item of it.data) {
var b = selectedList.filter((res) => res.id === item.id && res.type === item.type).length > 0;
item.selected = b;
}
}
};
defineExpose({ queryData, changeEvent, refreshData });
for (var it of dataList.value) {
for (var item of it.data) {
var b = selectedList.filter((res) => res.id === item.id && res.type === item.type).length > 0
item.selected = b
}
}
}
defineExpose({ queryData, changeEvent, refreshData })
watch(
() => props.selectedList,
(val) => {
refreshData();
}
);
() => props.selectedList,
(val) => {
refreshData()
},
)
</script>
<style scoped lang="scss">
@import './dialog.css';
@import "./dialog.css";
.select-box {
height: 420px;
overflow-y: auto;
height: 420px;
overflow-y: auto;
li {
padding: 5px 0;
}
li {
padding: 5px 0;
}
}
.radio_box a,
.check_box a {
font-size: 12px;
position: relative;
padding-left: 20px;
margin-right: 30px;
cursor: pointer;
color: #333;
white-space: pre;
font-size: 12px;
position: relative;
padding-left: 20px;
margin-right: 30px;
cursor: pointer;
color: #333;
white-space: pre;
}
.check_box.not a:hover {
color: #333;
color: #333;
}
.check_box.not a::before,
.check_box.not a:hover::before {
border: none;
border: none;
}
.check_box.not.active {
background: #f3f3f3;
background: #f3f3f3;
}
.radio_box a:hover::before,
.check_box a:hover::before {
border: 1px solid #46a6fe;
border: 1px solid #46a6fe;
}
.radio_box a::before,
.check_box a::before {
position: absolute;
width: 14px;
height: 14px;
border: 1px solid #dcdfe6;
border-radius: 2px;
left: 0;
top: 1px;
content: '';
position: absolute;
width: 14px;
height: 14px;
border: 1px solid #dcdfe6;
border-radius: 2px;
left: 0;
top: 1px;
content: "";
}
.radio_box a::before {
border-radius: 50%;
border-radius: 50%;
}
.check-dot.active::after,
.radio_box a.active::after,
.check_box a.active::after {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
top: 3px;
left: 3px;
content: '';
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
top: 3px;
left: 3px;
content: "";
}
.radio_box a.active::after {
background: #46a6fe;
background: #46a6fe;
}
.check_box a.active::after {
background: url(./assets/check_box.png) no-repeat center;
background: url(./assets/check_box.png) no-repeat center;
}
.f11 {
width: 30px;
width: 30px;
}
.f12 {
width: calc(100% - 30px);
height: 20px;
line-height: 20px;
width: calc(100% - 30px);
height: 20px;
line-height: 20px;
}
.d11 {
width: calc(100% - 30px);
width: calc(100% - 30px);
}
.d22 {
width: 30px;
line-height: 41px;
cursor: pointer;
width: 30px;
line-height: 41px;
cursor: pointer;
}
</style>
+6 -6
View File
@@ -46,7 +46,7 @@
<li v-for="item in data" :key="item.id">
<div style="display: flex; flex-direction: row">
<div class="f11">
<upload-img v-model:image-url="item.avatar" disabled width="20px" height="20px" />
<preview-image width="20px" height="20px" :src="item.avatar" />
</div>
<div class="f12">{{ item.name }}</div>
<div class="f13">
@@ -60,8 +60,8 @@
</div>
</template>
<script setup>
import { CircleClose, Grid, Share } from '@element-plus/icons-vue';
import UploadImg from '/@/components/Upload/Image.vue';
import { CircleClose, Grid, Share } from "@element-plus/icons-vue"
import UploadImg from "/@/components/Upload/Image.vue"
defineProps({
total: {
@@ -70,10 +70,10 @@ defineProps({
},
list: {
type: Array,
default: () => [{ type: 'role', data, cancel }],
default: () => [{ type: "role", data, cancel }],
},
});
let emits = defineEmits(['del']);
})
let emits = defineEmits(["del"])
</script>
<style scoped lang="scss">