Jelajahi Sumber

满意度调查统计页面开发

luoaoxuan 1 tahun lalu
induk
melakukan
28e6c5ed3d

+ 96 - 0
src/views/platform/examination/survey/all.vue

@@ -0,0 +1,96 @@
+<template>
+    <div class="all">
+        <el-table
+            ref="elTable"
+            :data="tableData"
+            border
+            stripe
+            highlight-current-row
+            style="width: 100%"
+            max-height="400px"
+            class="exam-table"
+        >
+            <el-table-column
+                prop="xu_hao_"
+                label="序号"
+                width="50"
+            />
+            <el-table-column
+                prop="ti_gan_"
+                label="题干"
+                min-width="200"
+            />
+            <el-table-column
+                v-for="(item,index) in xuanXiangCount"
+                :key="index"
+                :prop="`xuan_xiang_${index+1}`"
+                :label="`选项${index+1}`"
+                width="100"
+            />
+        </el-table>
+
+    </div>
+</template>
+
+<script>
+export default {
+    props: {
+        statisItemData: {
+            type: Object,
+            default: () => ({})
+        }
+    },
+    data () {
+        return {
+            // tableData: []
+        }
+    },
+    computed: {
+        tableData () {
+            // console.log('statisItemData', this.statisItemData)
+            const arr = []
+            let xu_hao_ = 1
+            for (const key in this.statisItemData) {
+                const val = this.statisItemData[key]
+                const obj = {}
+                if (val[0].xuan_xiang_) {
+                    const t = Object.keys(JSON.parse(val[0].xuan_xiang_)).length
+                    for (let i = 1; i <= 8; i++) {
+                        if (i <= t) {
+                            obj[`xuan_xiang_${i}`] = (val.filter(item => item.da_an_ === String.fromCharCode('A'.charCodeAt() + i - 1)).length / val.length * 100).toFixed(2) + ' %'
+                        } else {
+                            obj[`xuan_xiang_${i}`] = '/'
+                        }
+                    }
+                }
+                if (val[0].ti_xing_ === '单选题' || val[0].ti_xing_ === '多选题') {
+                    arr.push({
+                        xu_hao_: xu_hao_,
+                        ti_gan_: val[0].ti_gan_,
+                        ...obj
+                    })
+                }
+                xu_hao_++
+            }
+            // console.log('arr', arr)
+            return arr
+        },
+        // 计算最长选项
+        xuanXiangCount () {
+            let ans = 4
+            for (const key in this.statisItemData) {
+                const val = this.statisItemData[key]
+                if (val[0].xuan_xiang_) {
+                    const t = JSON.parse(val[0].xuan_xiang_)
+                    ans = Math.max(Object.keys(t).length, ans)
+                }
+            }
+            return ans
+        }
+    },
+    mounted () {
+
+    }
+
+}
+</script>

+ 127 - 0
src/views/platform/examination/survey/itemEchart.vue

@@ -0,0 +1,127 @@
+<template>
+    <div class="echart" style="width:100%">
+        <div class="pie" style="width: 50%;height:420px;">
+            <div ref="echart1" style="width: 100%;height:100%;" />
+        </div>
+        <div class="bar" style="width: 50%;height:420px;">
+            <div ref="echart2" style="width: 100%;height:100%" />
+        </div>
+    </div>
+</template>
+
+<script>
+import * as echarts from 'echarts'
+export default {
+    props: {
+        statisItemData: {
+            type: Array,
+            default: () => []
+        }
+    },
+    data () {
+        return {
+
+        }
+    },
+    mounted () {
+        const echart1 = echarts.init(this.$refs.echart1)
+        const echart2 = echarts.init(this.$refs.echart2)
+        const option1 = this.formatData1()
+        const option2 = this.formatData2()
+        echart1.setOption(option1)
+        echart2.setOption(option2)
+        echart1.resize()
+        echart2.resize()
+    },
+    methods: {
+        formatData1 () {
+            let t = {}
+            const data = []
+            if (this.statisItemData[0].xuan_xiang_) {
+                t = JSON.parse(this.statisItemData[0].xuan_xiang_)
+                let cnt = 1
+                for (const key in t) {
+                    data.push({
+                        value: this.statisItemData.filter(item => item.da_an_ === key).length,
+                        name: `选项${cnt}`
+                    })
+                    cnt++
+                }
+            }
+            return {
+                title: {
+                    // text: this.statisItemData[0].ti_gan_,
+                    subtext: this.statisItemData[0].ti_gan_,
+                    left: 'center'
+                },
+                tooltip: {
+                    trigger: 'item'
+                },
+                legend: {
+                    orient: 'vertical',
+                    left: 'left'
+                },
+                series: [
+                    {
+                        // name: 'Access From',
+                        type: 'pie',
+                        radius: '50%',
+                        data: data,
+                        emphasis: {
+                            itemStyle: {
+                                shadowBlur: 10,
+                                shadowOffsetX: 0,
+                                shadowColor: 'rgba(0, 0, 0, 0.5)'
+                            }
+                        }
+                    }
+                ]
+            }
+        },
+        formatData2 () {
+            let t = {}
+            const data = []
+            if (this.statisItemData[0].xuan_xiang_) {
+                t = JSON.parse(this.statisItemData[0].xuan_xiang_)
+                let cnt = 1
+                for (const key in t) {
+                    data.push({
+                        value: this.statisItemData.filter(item => item.da_an_ === key).length,
+                        name: `选项${cnt}`
+                    })
+                    cnt++
+                }
+            }
+            return {
+                tooltip: {
+                    trigger: 'item'
+                },
+                xAxis: {
+                    type: 'category',
+                    name: '选项',
+                    data: data.map(item => item.name)
+                },
+                yAxis: {
+                    type: 'value',
+                    name: '人数',
+                    minInterval: 1
+                },
+                series: [
+                    {
+                        data: data.map(item => item.value),
+                        type: 'bar',
+                        barWidth: 30
+                    }
+                ]
+            }
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+    .echart{
+        display: flex;
+        justify-content: center;
+    }
+</style>

+ 105 - 0
src/views/platform/examination/survey/itemTable.vue

@@ -0,0 +1,105 @@
+<template>
+    <div class="item-table">
+        <el-table
+            v-if="statisItemData[0].ti_xing_==='单选题' || statisItemData[0].ti_xing_==='多选题'"
+            ref="elTable"
+            :data="tableData"
+            border
+            stripe
+            highlight-current-row
+            style="width: 100%"
+            max-height="400px"
+            class="exam-table"
+        >
+            <el-table-column
+                prop="xx"
+                label="选项"
+                width="100"
+            />
+            <el-table-column
+                prop="xuan_xiang_"
+                label="选项内容"
+                min-width="200"
+            />
+            <el-table-column
+                prop="xiao_ji_"
+                label="小计"
+                width="100"
+            />
+            <el-table-column
+                prop="bi_li_"
+                label="比例"
+                width="100"
+            />
+        </el-table>
+
+        <el-table
+            v-else
+            ref="elTable2"
+            :data="tableData"
+            border
+            stripe
+            highlight-current-row
+            style="width: 100%"
+            max-height="400px"
+            class="exam-table"
+        >
+            <el-table-column
+                type="index"
+                label="序号"
+                width="50"
+            />
+
+            <el-table-column
+                prop="hui_da_"
+                label="回答"
+            />
+        </el-table>
+
+    </div>
+</template>
+
+<script>
+export default {
+    props: {
+        statisItemData: {
+            type: Array,
+            default: () => []
+        }
+    },
+    data () {
+        return {
+            // tableData: []
+        }
+    },
+    computed: {
+        tableData () {
+            let arr = []
+            if (this.statisItemData[0].ti_xing_ === '单选题' || this.statisItemData[0].ti_xing_ === '多选题') {
+                if (this.statisItemData[0].xuan_xiang_) {
+                    let ind = 1
+                    const t = JSON.parse(this.statisItemData[0].xuan_xiang_)
+                    for (const key in t) {
+                        const cnt = this.statisItemData.filter(item => item.da_an_ === key).length
+                        arr.push({
+                            xx: `选项${ind}`,
+                            xuan_xiang_: t[key],
+                            xiao_ji_: cnt,
+                            bi_li_: (cnt / this.statisItemData.length * 100).toFixed(2) + ' %'
+                        })
+                        ind++
+                    }
+                }
+            } else {
+                arr = this.statisItemData.map(item => ({ hui_da_: item.da_an_ }))
+            }
+            // console.log('item-arr', arr)
+
+            return arr
+        }
+    },
+    mounted () {
+    }
+
+}
+</script>

+ 284 - 0
src/views/platform/examination/survey/statistics.vue

@@ -0,0 +1,284 @@
+<template>
+    <el-dialog
+        v-loading="loading"
+        :title="title"
+        :visible.sync="dialogVisible"
+        :close-on-click-modal="false"
+        :close-on-press-escape="false"
+        :show-close="false"
+        append-to-body
+        fullscreen
+        class="dialog paper-detail-dialog"
+        top="0"
+    >
+        <div slot="title" class="dialog-title">
+            <span class="dialogtitle">{{ title }}</span>
+            <div>
+                <ibps-toolbar :actions="toolbars" @action-event="handleActionEvent" />
+            </div>
+        </div>
+        <div class="container">
+            <div class="left" :style="{width:initWidth}">
+                <div class="header">
+                    <div class="header-name">
+                        调查名称:{{ diao_cha_ming_che }}
+                    </div>
+                    <div class="header-left">
+                        <span>调查对象:</span>
+                        <div>
+                            <el-select
+                                v-model="diao_cha_dui_xian"
+                                filterable
+                                width="100%"
+                                size="mini"
+                            >
+                                <el-option
+                                    v-for="(v,k) in statisData"
+                                    :key="k"
+                                    :label="k"
+                                    :value="k"
+                                />
+                            </el-select>
+                        </div>
+                    </div>
+                    <div class="header-right">
+                        <span>统计时间:</span>
+                        <div>
+                            {{ $common.getDateNow(19) }}
+                        </div>
+                    </div>
+                </div>
+                <div class="title" style="margin-left:8px">统计总览</div>
+                <div class="all" style="margin-bottom:20px">
+                    <All :statis-item-data="showData" />
+                </div>
+                <div class="title" style="margin-left:8px">统计详情</div>
+                <div v-for="(v,k) in showData" :key="k" class="every">
+                    <div class="table-title">
+                        <div class="desc">
+                            {{ Object.keys(showData).findIndex(i=>i===k)+1 }}.{{ v[0].ti_gan_ }}
+                        </div>
+                        <div class="shown">
+                            填写人数:{{ v.length }}
+                        </div>
+                    </div>
+                    <div class="item-table">
+                        <ItemTable :statis-item-data="v" />
+                    </div>
+                    <div v-if="v[0].ti_xing_==='单选题' || v[0].ti_xing_==='多选题'" class="item-echart">
+                        <ItemEchart :statis-item-data="v" />
+                    </div>
+                </div>
+
+            </div>
+        </div>
+    </el-dialog>
+</template>
+
+<script>
+import _ from 'lodash'
+import ibpsUserSelector from '@/business/platform/org/selector'
+import All from './all.vue'
+import ItemTable from './itemTable.vue'
+import ItemEchart from './itemEchart.vue'
+
+export default {
+    components: {
+        ibpsUserSelector, All, ItemTable, ItemEchart
+    },
+    props: {
+        id_: {
+            type: String,
+            default: ''
+        },
+        dialogVisible: {
+            type: Boolean,
+            default: false
+        },
+        diao_cha_ming_che: {
+            type: String,
+            default: ''
+        }
+    },
+    data () {
+        const { userId, position, level } = this.$store.getters
+        return {
+            statisData: {},
+            diao_cha_dui_xian: '',
+            filter: [{
+                descVal: '2',
+                includeSub: true,
+                old: 'position',
+                partyId: this.$store.getters.userInfo.employee.positions,
+                partyName: '',
+                scriptContent: '',
+                type: 'user',
+                userType: 'position'
+            }],
+            userId: userId,
+            position: position,
+            level: level.second || level.first,
+            loading: false,
+            title: '满意度调查统计',
+            toolbars: [
+                // { key: 'save', label: '保存' },
+                { key: 'cancel', label: '退出', type: 'danger' }
+            ],
+            initWidth: '60%',
+            isEdit: false,
+            isFinished: false,
+            readonly: false,
+            preParams: {},
+            Ids: [],
+            form: {
+            },
+            rules: {
+
+            }
+        }
+    },
+    computed: {
+        showData () {
+            return this.statisData?.[this.diao_cha_dui_xian] || {}
+        }
+    },
+    watch: {
+
+    },
+    mounted () {
+        this.init()
+    },
+    methods: {
+        handleActionEvent ({ key }) {
+            switch (key) {
+                case 'cancel':
+                    this.closeDialog(true)
+                    break
+                // case 'save':
+                //     this.goSave('close')
+                //     break
+                default:
+                    break
+            }
+        },
+
+        // 获取人员部门
+        getPersonPosition (id) {
+            const userList = this.$store.getters.userList
+            const bianzhiUserid = userList.find(i => i.userId === id)
+            if (bianzhiUserid) {
+                return bianzhiUserid.positionId
+            }
+        },
+        checkRequired (flag) {
+        },
+        // 刷新
+        async goRefresh () {
+        },
+        // 关闭当前窗口
+        closeDialog (needRefresh) {
+            this.$emit('update:dialogVisible', false, needRefresh)
+        },
+        async init () {
+            this.initWidth = window.innerWidth > 1600 ? '60%' : '80%'
+            console.log('id_', this.id_)
+            const sql = `select a.*,b.diao_cha_dui_xian,b.diao_cha_ming_che FROM t_myddcjlxq a LEFT JOIN t_myddcjl b on a.parent_id_=b.id_ where b.diao_cha_id_='${this.id_}' and b.shi_fou_guo_shen_='已完成' ORDER BY b.create_time_ desc`
+            const { variables: { data = [] } = {}} = await this.$common.request('sql', sql)
+            const res = _.groupBy(data, 'diao_cha_dui_xian')
+            for (const key in res) {
+                const val = res[key]
+                res[key] = _.groupBy(val, 'ti_mu_id_')
+            }
+            this.statisData = res
+            this.diao_cha_dui_xian = Object.keys(res)?.[0] || ''
+            console.log('res', res)
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.paper-detail-dialog {
+    ::v-deep {
+        .el-dialog__header {
+            text-align: center;
+        }
+    }
+.dialog-title{
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    div{
+        z-index: 99999999;
+        position: absolute;
+        right:8vw;
+    }
+    .dialogtitle{
+        font-size: 22px;
+        font-family: SimHei;
+        font-weight: bold;
+        color: #222;
+    }
+}
+.container {
+        display: flex;
+        width: 100%;
+        justify-content: center;
+        .el-row{
+            margin: 0 !important;
+        }
+        .required{
+            color: #606266 !important;
+            &::before{
+                content: '*';
+                margin: 0 4px 0 -7.5px;
+                color: #F56C6C;
+            }
+        }
+        .left{
+            height: calc(100vh - 100px);
+            box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
+            padding:20px;
+            overflow-y: auto;
+            .item{
+                width: 100%;
+            }
+            .title{
+                margin: 16px 0 6px -16px;
+            }
+            .header{
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+                .header-left{
+                    display: flex;
+                    align-items: center;
+                }
+                .header-right{
+                    display: flex;
+                    align-items: center;
+                }
+                margin-bottom: 20px;
+            }
+            .every{
+                margin-bottom: 20px;
+            }
+            .table-title{
+                display: flex;
+                justify-content: space-between;
+                align-items: center;
+            }
+        }
+    }
+}
+    ::v-deep {
+        .el-form-item__label{
+            text-align: left;
+            font-size: 12px !important;
+        }
+        .el-form-item__content{
+            font-size: 12px !important;
+            display: flex;
+        }
+    }
+</style>