GuLiMmo
2024-01-17 16862bd1d0a4a4307c8b8940089caafafc68b08e
同票数任务下发
3 files modified
2 files added
766 ■■■■■ changed files
src/views/evaluate/components/evaluateTypeResult.vue 53 ●●●●● patch | view | raw | blame | history
src/views/evaluate/components/reissueSecondRound.vue 402 ●●●●● patch | view | raw | blame | history
src/views/evaluate/components/reissueSrCandiadate.vue 300 ●●●●● patch | view | raw | blame | history
src/views/evaluate/components/typeDetails.vue 5 ●●●●● patch | view | raw | blame | history
src/views/evaluate/evaluateResult.vue 6 ●●●●● patch | view | raw | blame | history
src/views/evaluate/components/evaluateTypeResult.vue
@@ -1,5 +1,13 @@
<template>
    <div class="container">
        <!-- v-if="params.data.evaluateState === 2" -->
        <el-alert type="warning" show-icon style="margin-bottom: 20px;">
            <template #title>
                如对当前任务有相同票数候选人,可点击右侧重新下发任务进行投票
                <span class="right-arrow">→</span>
                <el-button text type="success" icon="el-icon-position" @click="reissueTask">下发任务</el-button>
            </template>
        </el-alert>
        <ul class="type-list">
            <li class="type-item">
                <div class="title">奖项</div>
@@ -25,16 +33,19 @@
            </li>
        </ul>
        <typeDetails :params="typeDetailsParams" />
        <reissueSecondRound :params="reissueTaskParams" @initAsideData="initAsideData" />
    </div>
</template>
<script>
import { getEcList } from '@/api/evaluate/evaluateTask'
import typeDetails from './typeDetails.vue'
import reissueSecondRound from './reissueSecondRound.vue'
export default {
    components: {
        typeDetails
        typeDetails,
        reissueSecondRound
    },
    props: {
        params: {
@@ -54,7 +65,8 @@
                size: 10,
                total: 0
            },
            typeDetailsParams: {}
            typeDetailsParams: {},
            reissueTaskParams: {}
        }
    },
    watch: {
@@ -86,6 +98,22 @@
                    evaluateTaskCategoryId
                }
            }
        },
        reissueTask() {
            this.$confirm('是否发下任务?', '提示', {
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning',
            }).then(res => {
                this.reissueTaskParams = {
                    visible: true,
                    data: this.params.data
                }
            })
        },
        initAsideData() {
            this.$emit('initAsideData')
        }
    },
    mounted() {
@@ -97,6 +125,27 @@
<style lang="scss" scoped>
$borderColor: var(--el-border-color);
.right-arrow {
    display: inline-block;
    padding: 0 7px;
    font-weight: bolder;
    animation: moveAnimation 1s ease-in-out infinite;
}
@keyframes moveAnimation {
    from {
        transform: translateX(7px);
    }
    50% {
        transform: translateX(-7px);
    }
    to {
        transform: translateX(7px);
    }
}
.type-list {
    margin: 0;
    padding: 0;
src/views/evaluate/components/reissueSecondRound.vue
New file
@@ -0,0 +1,402 @@
<template>
    <el-dialog v-model="params.visible" :title="`下发任务(${params.data?.taskName || ''})`" width="65%" @open="openDialog"
        @close="dialogClose">
        <div class="content" v-loading="isLoading">
            <el-form :model="form" ref="formRef" :rules="rules" label-position="top">
                <el-form-item label="评优奖项" prop="categoryEntities">
                    <ul class="type-list">
                        <li class="type-item">
                            <div class="title">奖项</div>
                            <div class="introduction">认定标准</div>
                            <div class="number">名额</div>
                            <div class="tool">操作</div>
                        </li>
                        <li class="type-item" v-for="(item, index) in form.categoryEntities" :key="index">
                            <div class="title">{{ item.categoryName }}</div>
                            <el-tooltip effect="dark" placement="top">
                                <template #content>
                                    <p style="max-width: 500px;">{{ item.standard }}</p>
                                </template>
                                <div class="introduction">
                                    {{ item.standard }}
                                </div>
                            </el-tooltip>
                            <div class="number">{{ item.peopleNum }}</div>
                            <div class="tool">
                                <el-button type="primary" icon="el-icon-plus" text
                                    @click="addEcCandidateHandler(item)">添加候选人</el-button>
                            </div>
                        </li>
                    </ul>
                </el-form-item>
                <el-form-item label="投票人员" prop="pollingPersons">
                    <el-checkbox-group v-model="form.pollingPersons">
                        <el-checkbox v-for="item in employeeDict" :key="item.id" :label="item.dictKey"
                            @change="checkBoxChange($event, item)">
                            {{ item.dictValue }}
                            <el-button type="primary" icon="el-icon-edit" text
                                @click="selectionHandler(item)">设置人员</el-button>
                        </el-checkbox>
                    </el-checkbox-group>
                </el-form-item>
                <el-form-item label="第二轮任务结束时间" required>
                    <el-form-item class="time-box" prop="evaluateCutoffTimeStart">
                        <el-date-picker v-model="form.evaluateCutoffTimeStart" type="datetime" placeholder="请选择任务开始时间"
                            value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%;" />
                    </el-form-item>
                    <span class="time-span">至</span>
                    <el-form-item class="time-box" prop="evaluateCutoffTimeEnd">
                        <el-date-picker v-model="form.evaluateCutoffTimeEnd" type="datetime" placeholder="请选择任务结束时间"
                            value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%;" />
                    </el-form-item>
                </el-form-item>
            </el-form>
        </div>
        <template #footer>
            <el-button @click="() => params.visible = false" :loading="isLoading">取消</el-button>
            <el-button type="primary" @click="taskPublic" :loading="isLoading">确认发布</el-button>
        </template>
        <!-- 添加评优种类候选人 -->
        <reissueSrCandiadate :params="addEcCandidateParams" @addCandidateList="addCandidateList" />
        <!-- 人员选择 -->
        <selectionDialog :params="selectionParams" @addEvaluateParams="addEvaluateParams" />
    </el-dialog>
</template>
<script>
import _ from 'lodash';
import { getDict } from '@/api/dict'
import { add, update, getEcList, getEmployeeLevelList, addEtaskCc } from '@/api/evaluate/evaluateTask'
import selectionDialog from './selectionDialog.vue';
import reissueSrCandiadate from './reissueSrCandiadate.vue';
export default {
    components: {
        selectionDialog,
        reissueSrCandiadate
    },
    props: {
        params: {
            type: Object,
            default: () => {
                return {
                    visible: false,
                    data: {}
                };
            },
        },
    },
    data() {
        return {
            isLoading: false,
            employeeDict: [],
            form: {
                categoryEntities: [],
                pollingPersons: [],
                votePersonObjInfo: [],
                evaluateCutoffTimeStart: '',
                evaluateCutoffTimeEnd: ''
            },
            rules: {
                categoryEntities: [
                    { required: true, message: '任务类别不可为空', trigger: 'click' },
                    {
                        validator: (rule, value, callback) => {
                            if (this.candidateList.length <= 0) {
                                callback(new Error("候选人不可为空!!"))
                            } else {
                                callback()
                            }
                        },
                        trigger: 'click'
                    }
                ],
                pollingPersons: [
                    { required: true, message: '请选择评定人员', trigger: 'click' },
                ],
                evaluateCutoffTimeStart: [
                    { required: true, message: '请选择任务开始时间', trigger: 'click' },
                ],
                evaluateCutoffTimeEnd: [
                    { required: true, message: '请选择任务开始时间', trigger: 'click' },
                ]
            },
            page: {
                current: 1,
                size: 100,
                total: 0
            },
            addEcCandidateParams: {},
            selectionParams: {},
            candidateList: [],
        }
    },
    watch: {
        // 'params.visible': {
        //     handler(value) {
        //         if (!value) return
        //         this.form.pollingPersons = this.params.data.pollingPersons.split(',') || []
        //         this.form.votePersonObjInfo = JSON.parse(this.params.data.votePersonObjInfo) || []
        //         this.form.evaluateCutoffTimeStart = this.params.data.evaluateCutoffTimeStart || ''
        //         this.form.evaluateCutoffTimeEnd = this.params.data.evaluateCutoffTimeEnd || ''
        //     },
        //     deep: true
        // }
    },
    methods: {
        dialogClose() {
            this.candidateList = []
            this.$refs.formRef.resetFields()
        },
        openDialog() {
            this.initDict()
            const { id } = this.params.data
            const { current, size } = this.page
            getEcList(current, size, id).then(ecResult => {
                const { code, data: { records } } = ecResult.data
                if (code !== 200) return this.$message.error('评优类别加载失败')
                this.form.categoryEntities = records
            })
        },
        initDict() {
            getDict('employee_type').then(res => {
                const { code, data } = res.data
                if (code !== 200) {
                    return this.$message.error('人员类型字典加载失败')
                }
                this.employeeDict = data
            })
        },
        // 发布任务
        taskPublic() {
            this.$refs.formRef.validate(valid => {
                if (!valid) return
                this.isLoading = true
                // 创建新任务
                this.createNewTask(this.params.data).then(taskRes => {
                    this.addCategoryCandiadate(taskRes).then(respones => {
                        const data = _.cloneDeep(this.form)
                        const { id } = this.params.data
                        data.id = id
                        data.candidateState = 2
                        data.pollingPersons = data.pollingPersons.join(',')
                        delete data.categoryEntities
                        update(data).then(res => {
                            if (res.data.code !== 200) return
                            this.isLoading = false
                            this.params.visible = false
                            this.$emit('initAsideData')
                        })
                    })
                })
            })
        },
        addCandidateList(list) {
            list.forEach(item => {
                const isExist = this.candidateList.find(user => user.userId === item.userId && user.categoryName === item.categoryName)
                if (!isExist) {
                    this.candidateList.push(item)
                }
            })
        },
        getNowDate() {
            const date = new Date()
            const year = date.getFullYear()
            const month = date.getMonth() + 1
            const day = date.getDate()
            return year + '-' + month + '-' + day + ' ' + '00:00:00'
        },
        // 创建新任务
        createNewTask(params) {
            const { id, taskName, candidateState } = params
            // 获取当前任务评优奖项
            return getEcList(1, 100, id).then(res => {
                if (res.data.code !== 200) return this.$message.error(res.data.msg)
                const categoryEntities = []
                res.data.data.records.forEach(item => {
                    const { categoryName, standard, peopleNum } = item
                    categoryEntities.push({ categoryName, standard, peopleNum })
                })
                return categoryEntities
            }).then(categoryEntities => {
                // 发起创建任务请求
                const newTaskData = {
                    taskName: taskName + '(同票数)',
                    categoryEntities: categoryEntities,
                    candidateState: candidateState,
                    candidateCutoffTimeEnd: this.getNowDate(),
                    candidateCutoffTimeStart: this.getNowDate()
                }
                return add(newTaskData).then(taskRes => {
                    if (taskRes.data.code !== 200) return this.$message.error(res.data.msg)
                    return taskRes.data.data
                })
            })
        },
        // 将候选人添加进类别中
        addCategoryCandiadate(taskRes) {
            const { categoryEntities } = taskRes
            const newCandidateList = this.candidateList.map(user => {
                const sUser = categoryEntities.find(category => category.categoryName === user.categoryName)
                if (sUser !== void 0) {
                    const { id } = sUser
                    user['evaluateTaskCategoryId'] = id
                    delete user['categoryName']
                    return user
                }
            })
            const promiseArrs = []
            newCandidateList.forEach(sParams => {
                promiseArrs.push(addEtaskCc(sParams))
            })
            return Promise.allSettled(promiseArrs).then((responses) => {
                return responses
            }, error => {
                this.$message.error(error)
            })
        },
        addEcCandidateHandler(row) {
            const { id, categoryName, evaluateTaskId } = row
            this.addEcCandidateParams = {
                visible: true,
                data: {
                    categoryName,
                    evaluateTaskId,
                    evaluateTaskCategoryId: id,
                    list: this.candidateList
                }
            }
        },
        viewCandidateResult() {
            this.candidateResultParams = {
                visible: true,
                data: this.params.data
            }
        },
        selectionHandler(row) {
            const obj = this.form.votePersonObjInfo.find(item => item.employeeType === row.dictKey) || {}
            this.selectionParams = {
                visible: true,
                data: row,
                values: obj
            }
        },
        checkBoxChange(e, { dictKey }) {
            const index = this.form.votePersonObjInfo.findIndex(item => item.employeeType === dictKey)
            if (!e) {
                this.form.votePersonObjInfo.splice(index, 1)
                return
            }
            getEmployeeLevelList(dictKey).then((res) => {
                const { code, data } = res.data
                if (code !== 200) return this.$message.error('当前级别人员加载失败,请重试!!')
                const participateInList = data.map(item => {
                    const { id, name, deptId, deptName, postId, postName } = item
                    return { id, name, deptId, deptName, postId, postName }
                })
                const params = {
                    employeeType: dictKey,
                    participateIn: participateInList,
                    notParticipateIn: []
                }
                if (index === -1) {
                    this.form.votePersonObjInfo.push(params)
                } else {
                    this.form.votePersonObjInfo[index] = params
                }
            })
        },
        addEvaluateParams(params) {
            const { participateIn, employeeType } = params
            const index = this.form.votePersonObjInfo.findIndex(item => item.employeeType === employeeType)
            const typeIndex = this.form.pollingPersons.findIndex(item => item === employeeType)
            if (index === -1) {
                if (participateIn.length > 0) {
                    this.form.votePersonObjInfo.push(params)
                    this.form.pollingPersons.push(params.employeeType)
                }
            } else {
                if (participateIn.length > 0) {
                    this.form.votePersonObjInfo[index] = params
                } else {
                    this.form.votePersonObjInfo.splice(index, 1)
                    this.form.pollingPersons.splice(typeIndex, 1)
                }
            }
        }
    }
};
</script>
<style lang="scss" scoped>
$borderColor: var(--el-border-color);
.content {
    max-height: 600px;
    overflow-y: auto;
    .time-span {
        margin: 0 10px;
    }
    .time-box {
        width: calc(100% / 2 - 20px);
    }
    .type-list {
        margin: 0;
        padding: 0;
        list-style-type: none;
        width: 100%;
        border: 1px solid $borderColor;
        border-radius: var(--el-border-radius-base);
        box-sizing: border-box;
        .type-item {
            display: flex;
            height: 40px;
            line-height: 40px;
            text-align: center;
            div {
                border-bottom: 1px solid $borderColor;
                flex-shrink: 0;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }
            .title {
                flex: 2;
            }
            .introduction {
                flex: 5;
                flex-shrink: 0;
                border: {
                    right: 1px solid $borderColor;
                    left: 1px solid $borderColor;
                }
            }
            .number {
                flex: 1;
            }
            .tool {
                flex: 2;
                border-left: 1px solid $borderColor;
            }
            &:last-child {
                div {
                    border-bottom: 0;
                }
            }
        }
    }
}
</style>
src/views/evaluate/components/reissueSrCandiadate.vue
New file
@@ -0,0 +1,300 @@
<template>
    <el-dialog v-model="params.visible" :title="params.data?.categoryName || '添加类别候选人'" width="50%" destroy-on-close
        @close="cancel" @open="openDialog">
        <avue-crud :option="option" v-model:search="search" v-model:page="page" v-model="form" :table-loading="loading"
            :data="data" :before-open="beforeOpen" ref="crud" @row-update="rowUpdate" @row-del="rowDel"
            @search-change="searchChange" @search-reset="searchReset" @selection-change="selectionChange"
            @current-change="currentChange" @size-change="sizeChange" @refresh-change="refreshChange" @on-load="onLoad">
            <template #menu="{ row }">
                <el-checkbox v-model="row.checked" @change="handleCheckChange($event, row)">参加</el-checkbox>
            </template>
        </avue-crud>
        <template #footer>
            <el-button @click="cancel">取消</el-button>
            <el-button type="primary" @click="addCandidate">添加候选人</el-button>
        </template>
    </el-dialog>
</template>
<script>
import { getFinallyTypeResult, removeEtaskCc } from '@/api/evaluate/evaluateTask'
import { exportBlob } from "@/api/common";
import { getToken } from '@/utils/auth';
import { downloadXls } from "@/utils/util";
import { dateNow } from "@/utils/date";
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
export default {
    props: {
        params: {
            type: Object,
            default: () => {
                return {
                    visible: false,
                    data: {
                        categoryName: '',
                        evaluateTaskId: '',
                        evaluateTaskCategoryId: '',
                        list: []
                    }
                }
            }
        }
    },
    data() {
        return {
            form: {},
            query: {},
            search: {},
            loading: true,
            page: {
                pageSize: 10,
                currentPage: 1,
                total: 0
            },
            selectionList: [],
            option: {
                height: '300',
                calcHeight: 30,
                tip: false,
                searchShow: true,
                // selection: true,
                searchMenuSpan: 6,
                border: true,
                index: true,
                viewBtn: false,
                editBtn: false,
                delBtn: false,
                // menu: false,
                addBtn: false,
                header: false,
                dialogClickModal: false,
                menuWidth: 120,
                menuTitle: '是否参加候选',
                column: [
                    {
                        label: '姓名',
                        prop: 'user_name',
                        type: 'input'
                    },
                    {
                        label: '职位',
                        prop: 'post_name',
                        type: 'input'
                    },
                    {
                        label: '部门',
                        prop: 'dept_name',
                        type: 'input'
                    },
                    {
                        label: '票数',
                        prop: 'voteNum',
                        type: 'input'
                    }
                ]
            },
            data: [],
        };
    },
    computed: {
        ids() {
            let ids = [];
            this.selectionList.forEach(ele => {
                ids.push(ele.id);
            });
            return ids.join(",");
        }
    },
    methods: {
        rowSave(row, done, loading) {
            add(row).then(() => {
                this.onLoad(this.page);
                this.$message({
                    type: "success",
                    message: "操作成功!"
                });
                done();
            }, error => {
                loading();
                window.console.log(error);
            });
        },
        rowUpdate(row, index, done, loading) {
            update(row).then(() => {
                this.onLoad(this.page);
                this.$message({
                    type: "success",
                    message: "操作成功!"
                });
                done();
            }, error => {
                loading();
                console.log(error);
            });
        },
        rowDel(row) {
            this.$confirm("确定将选择数据删除?", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning"
            })
                .then(() => {
                    return removeEtaskCc(row.id);
                })
                .then(() => {
                    this.onLoad(this.page);
                    this.$message({
                        type: "success",
                        message: "操作成功!"
                    });
                });
        },
        handleDelete() {
            if (this.selectionList.length === 0) {
                this.$message.warning("请选择至少一条数据");
                return;
            }
            this.$confirm("确定将选择数据删除?", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning"
            })
                .then(() => {
                    return removeEtaskCc(this.ids);
                })
                .then(() => {
                    this.onLoad(this.page);
                    this.$message({
                        type: "success",
                        message: "操作成功!"
                    });
                    this.$refs.crud.toggleSelection();
                });
        },
        handleExport() {
            let downloadUrl = `/evaluate/evaluateResult/export-evaluateResult?${this.website.tokenHeader}=${getToken()}`;
            const {
            } = this.query;
            let values = {
            };
            this.$confirm("是否导出数据?", "提示", {
                confirmButtonText: "确定",
                cancelButtonText: "取消",
                type: "warning"
            }).then(() => {
                NProgress.start();
                exportBlob(downloadUrl, values).then(res => {
                    downloadXls(res.data, `评优结果${dateNow()}.xlsx`);
                    NProgress.done();
                })
            });
        },
        beforeOpen(done, type) {
            if (["edit", "view"].includes(type)) {
                getDetail(this.form.id).then(res => {
                    this.form = res.data.data;
                });
            }
            done();
        },
        searchReset() {
            this.query = {};
            this.onLoad(this.page);
        },
        searchChange(params, done) {
            this.query = {
                type: this.defaultTaskType,
                ...params
            };
            this.page.currentPage = 1;
            this.onLoad(this.page, params);
            done();
        },
        selectionChange(list) {
            this.selectionList = list;
        },
        selectionClear() {
            this.selectionList = [];
            this.$refs.crud.toggleSelection();
        },
        currentChange(currentPage) {
            this.page.currentPage = currentPage;
        },
        sizeChange(pageSize) {
            this.page.pageSize = pageSize;
        },
        refreshChange() {
            this.onLoad(this.page, this.query);
        },
        onLoad(page, params = {}) {
            this.loading = true;
            const { evaluateTaskId, evaluateTaskCategoryId, list } = this.params.data
            const {
            } = this.query;
            let values = {
                ...this.query,
                ...params,
                evaluateTaskId,
                evaluateTaskCategoryId
            };
            getFinallyTypeResult(page.currentPage, page.pageSize, values).then(res => {
                const data = res.data.data;
                this.page.total = data.total;
                this.data = data.records;
                this.loading = false;
                // this.selectionClear();
                this.data.forEach(item => {
                    const isExist = list.find(user => user.userId === item.id)
                    if (isExist) {
                        item.checked = true
                    }
                })
            });
        },
        openDialog() {
            this.onLoad(this.page);
        },
        cancel() {
            this.params.visible = false
            this.selectionList = []
        },
        addCandidate() {
            if (this.selectionList.length <= 0) return this.$message.warning('请选择候选人')
            const { categoryName } = this.params.data
            const list = this.selectionList.map((item, index) => {
                const { id, user_name, dept_id, dept_name, post_name } = item
                const listParams = {
                    categoryName,
                    userId: id,
                    userName: user_name,
                    deptId: dept_id,
                    deptName: dept_name,
                    postName: post_name
                }
                return listParams
            })
            this.$emit('addCandidateList', list)
            this.params.visible = false
            this.$message.success('添加候选人成功')
        },
        handleCheckChange(value, row) {
            row.checked = value
            if (!value) {
                const index = this.selectionList.findIndex(item => item.id === row.id)
                if (index !== -1) {
                    this.selectionList.splice(index, 1)
                }
                return
            }
            this.selectionList.push(row)
        }
    }
};
</script>
src/views/evaluate/components/typeDetails.vue
@@ -63,6 +63,11 @@
                        label: '职位',
                        prop: 'dept_name',
                        type: 'input'
                    },
                    {
                        label: '票数',
                        prop: 'voteNum',
                        type: 'input'
                    }
                ]
            },
src/views/evaluate/evaluateResult.vue
@@ -33,8 +33,8 @@
      <el-main>
        <template v-if="this.taskList.length > 0">
          <el-collapse v-model="activeNames">
            <el-collapse-item title="当前任务评优奖项详情" name="1" v-if="!defaultTaskType">
              <evaluateTypeResult :params="{ data: taskList[taskActive] }" />
            <el-collapse-item title="当前任务评优奖项候选人详情" name="1" v-if="!defaultTaskType">
              <evaluateTypeResult :params="{ data: taskList[taskActive] }" @initAsideData="initData" />
            </el-collapse-item>
            <el-collapse-item name="2" v-if="!defaultTaskType">
              <template #title>
@@ -127,6 +127,7 @@
      this.getTaskList()
    },
    getTaskList(params) {
      this.page.current = 1
      const { current, size } = this.page
      const values = {
        type: this.defaultTaskType,
@@ -147,6 +148,7 @@
      this.getTaskList({ taskName: this.taskWord })
    },
    tabChange(value) {
      this.taskActive = 0
      this.defaultTaskType = value.prop;
      this.getTaskList()
      this.defaultTaskType ? this.activeNames = ['3'] : this.activeNames = ['1']