master
xy 1 year ago
parent c35def3014
commit f405aaa69a

@ -35,3 +35,12 @@ export function destroy(params, isLoading = true) {
isLoading isLoading
}) })
} }
export function chart(params, isLoading = true) {
return request({
method: 'get',
url: '/api/admin/user/chart',
params,
isLoading: true
})
}

@ -10,21 +10,87 @@
> >
<template #title> <template #title>
<div class="title-panel"> <div class="title-panel">
<p>{{ $route.meta.title }}</p> <h4>{{ $route.meta.title }}</h4>
<el-button icon="el-icon-download" type="primary" size="small" circle @click="exportTable"></el-button> <el-button icon="el-icon-download" type="primary" size="small" circle @click="exportTable"></el-button>
</div> </div>
</template> </template>
<template #default>
<template v-if="detail.aspiration && detail.aspiration.group === '太仓'">
<vxe-table
ref="table"
:data="list"
align="center"
border
:merge-cells="taicangMergeCells"
show-footer
:footer-data="[{ v1: detail.aspiration ? detail.aspiration.remark : '' }, { v2: '考试签名(亲笔)', v4: '家长签名(亲笔)' }]"
:merge-footer-items="[{ row: 0, col: 0, rowspan: 1, colspan: 5 }]">
<vxe-colgroup :title="detail.aspiration ? detail.aspiration.title : ''" align="center">
<vxe-column header-class-name="batch-table-bkg--white" :title="(detail.aspiration && detail.aspiration.need_sign) ? '准考证号' : ''" field="v1"></vxe-column>
<vxe-column header-class-name="batch-table-bkg--white" field="v2"></vxe-column>
<vxe-column header-class-name="batch-table-bkg--white" :title="(detail.aspiration && detail.aspiration.need_sign) ? '姓名' : ''" field="v3"></vxe-column>
<vxe-column header-class-name="batch-table-bkg--white" field="v4"></vxe-column>
<vxe-column header-class-name="batch-table-bkg--white" :title="(detail.aspiration && detail.aspiration.need_sign) ? '毕业学校' : ''" field="v5"></vxe-column>
</vxe-colgroup>
</vxe-table>
</template>
<template v-else>
<section class="drawer-container"> <section class="drawer-container">
<h3 class="title">{{ detail.aspiration ? detail.aspiration.title : '' }}</h3>
<vxe-table ref="table" :data="list" align="center" border :merge-cells="mergeCells"> <vxe-table ref="table" :data="list" align="center" border :merge-cells="mergeCells">
<vxe-colgroup :title="detail.aspiration ? detail.aspiration.title : ''" align="center" header-class-name="batch-table__title">
<template v-if="(detail.aspiration && detail.aspiration.need_sign)">
<vxe-colgroup title="准考证号" header-align="left">
<vxe-colgroup title="录取批次" align="center">
<vxe-column title="" field="name"></vxe-column>
<vxe-column title="" field="batchSubs.name"></vxe-column>
</vxe-colgroup>
<vxe-column field="batchSubs.batchSubSchools.name" title="志愿序号">
<template #default="{ row }">
{{ (row.batchSubs && row.batchSubs.isSchoolObey) ? '其他院校是否服从' : row.batchSubs.batchSubSchools.name }}
</template>
</vxe-column>
</vxe-colgroup>
<vxe-colgroup title="姓名" header-align="left">
<vxe-colgroup title="学校">
<vxe-column title="代码" field="batchSubs.batchSubSchools.code">
<template #default="{ row }">
{{ (row.batchSubs && row.batchSubs.isSchoolObey) ? (row.batchSubs.schoolObey ? '是' : '否') : row.batchSubs.batchSubSchools.code }}
</template>
</vxe-column>
<vxe-column title="名称" field="batchSubs.batchSubSchools.value"></vxe-column>
</vxe-colgroup>
</vxe-colgroup>
<vxe-colgroup title="毕业学校" header-align="left">
<vxe-colgroup title="专业">
<vxe-column title="序号" field="batchSubs.batchSubSchools.specialties.name"></vxe-column>
<vxe-column title="代码" field="batchSubs.batchSubSchools.specialties.code"></vxe-column>
<vxe-column title="名称" field="batchSubs.batchSubSchools.specialties.value"></vxe-column>
</vxe-colgroup>
<vxe-colgroup title="其他专业是否服从">
<vxe-column title="(是/否)" field="">
<template #default="{ row }">
{{ row.batchSubs.hasOwnProperty("notShowSpecialtyObey") ? "-" : (row.batchSubs.specialtyObey ? "是" : "否") }}
</template>
</vxe-column>
</vxe-colgroup>
</vxe-colgroup>
</template>
<template v-else>
<vxe-colgroup title="录取批次" align="center"> <vxe-colgroup title="录取批次" align="center">
<vxe-column title="" field="name"></vxe-column> <vxe-column title="" field="name"></vxe-column>
<vxe-column title="" field="batchSubs.name"></vxe-column> <vxe-column title="" field="batchSubs.name"></vxe-column>
</vxe-colgroup> </vxe-colgroup>
<vxe-column field="batchSubs.batchSubSchools.name" title="志愿序号"></vxe-column> <vxe-column field="batchSubs.batchSubSchools.name" title="志愿序号">
<template #default="{ row }">
{{ (row.batchSubs && row.batchSubs.isSchoolObey) ? '其他院校是否服从' : row.batchSubs.batchSubSchools.name }}
</template>
</vxe-column>
<vxe-colgroup title="学校"> <vxe-colgroup title="学校">
<vxe-column title="代码" field="batchSubs.batchSubSchools.code"></vxe-column> <vxe-column title="代码" field="batchSubs.batchSubSchools.code">
<template #default="{ row }">
{{ (row.batchSubs && row.batchSubs.isSchoolObey) ? (row.batchSubs.schoolObey ? '是' : '否') : row.batchSubs.batchSubSchools.code }}
</template>
</vxe-column>
<vxe-column title="名称" field="batchSubs.batchSubSchools.value"></vxe-column> <vxe-column title="名称" field="batchSubs.batchSubSchools.value"></vxe-column>
</vxe-colgroup> </vxe-colgroup>
<vxe-colgroup title="专业"> <vxe-colgroup title="专业">
@ -39,8 +105,12 @@
</template> </template>
</vxe-column> </vxe-column>
</vxe-colgroup> </vxe-colgroup>
</template>
</vxe-colgroup>
</vxe-table> </vxe-table>
</section> </section>
</template>
</template>
</el-drawer> </el-drawer>
</div> </div>
</template> </template>
@ -61,7 +131,8 @@ export default {
loading: false, loading: false,
visible: false, visible: false,
detail: {}, detail: {},
list: [] list: [],
taicangMergeCells: []
}; };
}, },
watch: { watch: {
@ -81,6 +152,184 @@ export default {
}) })
} }
}, },
formatTaiCangData(arr) {
const transformedArray = [];
arr.forEach((batch, batchIndex) => {
transformedArray.push({
v1: batch.name??"",
v2: null,
v3: null,
v4: null,
v5: null,
colspan: [
{
col: 0, span: 5
}
]
})
batch.batchSubs.forEach(sub => {
if (batchIndex === 0) {
transformedArray.push({
v1: sub.name??"",
v2: "学校代号、名称",
v3: "专业代号、名称",
v4: "专业代号、名称",
v5: "专业服从",
colspan: []
})
} else if (batchIndex === 1) {
transformedArray.push({
v1: sub.name??"",
v2: "学校代号、名称",
v3: null,
v4: "说明",
v5: null,
colspan: [
{
col: 1, span: 2
},
{
col: 3, span: 2
}
]
})
} else {
transformedArray.push({
v1: sub.name??"",
v2: "学校代号、名称",
v3: "第一专业代号、名称",
v4: "第二专业代号、名称",
v5: "专业服从",
colspan: []
})
}
sub.batchSubSchools.forEach((school, schoolIndex) => {
if (batchIndex === 1) {
transformedArray.push({
v1: school.name??"",
v2: (school.code??"") + " " + (school.value??""),
v3: null,
v4: schoolIndex === 0 ? "具有指标生资格的考生可填1所学校,在江苏省太仓高级中学(0001)、江苏省太仓高级中学娄江新城校0002江苏省沙溪高级中学(0003)和太仓市明德高级中学(0004)中选择。"
:
"可填一至四个志愿和一个服从志愿,在江苏省太仓高级中学(0001)、江苏省太仓高级中学娄江新城校0002江苏省沙溪高级中学(0003)和太仓市明德高级中学(0004)中选择。",
v5: null,
colspan: [
{ col: 1, span: 2 },
{ col: 3, span: 2, hasRowspan: true },
],
})
} else {
transformedArray.push({
v1: school.name??"",
v2: (school.code??"") + " " + (school.value??""),
v3: (school.specialties[0]?.code??"") + " " + (school.specialties[0]?.value??""),
v4: (school.specialties[1]?.code??"") + " " + (school.specialties[1]?.value??""),
v5: sub.specialtyObey ? '是' : '否',
colspan: []
})
}
})
if (sub.schoolObey) {
transformedArray.push({
v1: '是否服从'+sub.name,
v2: sub.schoolObey ? '是' : '否',
v3: null,
v4: null,
v5: null,
colspan: [
{},
{ col: 1, span: 4, hasRowspan: batchIndex === 1 }
],
})
}
})
})
return transformedArray
},
getTaicangMerge() {
//
const mergedPositions = new Set()
this.list.forEach((row, rowIndex) => {
if (row.colspan && row.colspan.length > 0) {
row.colspan.forEach((spanItem) => {
const { col, span } = spanItem
//
const mergeKey = `${rowIndex}-${col}`
if (mergedPositions.has(mergeKey)) {
return //
}
//
if (col === 0 && span === 5) {
this.taicangMergeCells.push({
row: rowIndex,
col: col,
rowspan: 1,
colspan: span
})
//
for (let i = 0; i < span; i++) {
mergedPositions.add(`${rowIndex}-${i}`)
}
return
}
//
let rowspan = 1
if (spanItem.hasRowspan) {
let nextRowIndex = rowIndex + 1
while (
nextRowIndex < this.list.length &&
this.list[nextRowIndex].colspan?.some(item =>
item.col === col && item.hasRowspan
)
) {
rowspan++
//
for (let i = 0; i < span; i++) {
mergedPositions.add(`${nextRowIndex}-${(col + i)}`)
}
nextRowIndex++
}
}
//
this.taicangMergeCells.push({
row: rowIndex,
col: col,
rowspan: rowspan,
colspan: span
})
//
for (let i = 0; i < span; i++) {
mergedPositions.add(`${rowIndex}-${(col + i)}`)
}
})
}
})
},
// getTaicangMerge() {
// this.list.forEach((row, rowIndex) => {
// if (row.colspan && row.colspan.length > 0) {
// row.colspan.forEach((spanItem) => {
// const { col, span, hasRowspan } = spanItem
//
// this.taicangMergeCells.push({
// row: rowIndex,
// col: col,
// rowspan: 1,
// colspan: span
// })
// })
// }
// })
// },
formatData(arr) { formatData(arr) {
const transformedArray = []; const transformedArray = [];
arr.forEach(batch => { arr.forEach(batch => {
@ -131,6 +380,25 @@ export default {
}); });
} }
}); });
if (sub.schoolObey) {
transformedArray.push({
name: batch.name,
batchId: batch.batchId,
batchSubs: {
name: sub.name,
batchSubId: sub.batchSubId,
batchSubSchools: {
code: null,
name: null,
value: null,
specialties: [],
batchSubSchoolId: null
},
isSchoolObey: !sub.hasOwnProperty('notShowSchoolObey'),
schoolObey: sub.schoolObey,
}
});
}
}); });
}); });
console.log(transformedArray); console.log(transformedArray);
@ -143,7 +411,14 @@ export default {
show_relation: ["aspiration"] show_relation: ["aspiration"]
}); });
this.detail = detail this.detail = detail
if (this.detail.aspiration?.group === '太仓') {
this.list = this.formatTaiCangData(detail.data)
console.log(333, this.list)
this.getTaicangMerge()
console.log(444, this.taicangMergeCells)
} else {
this.list = this.formatData(detail.data) this.list = this.formatData(detail.data)
}
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
@ -222,6 +497,12 @@ export default {
row: i - (c3rowspan - 1), col: 8, rowspan: c3rowspan, colspan: 1 row: i - (c3rowspan - 1), col: 8, rowspan: c3rowspan, colspan: 1
}); });
} }
if (item.batchSubs.isSchoolObey) {
mergeCells.push({
row: i, col: 3, rowspan: 1, colspan: 7
})
}
} }
console.log(mergeCells); console.log(mergeCells);
@ -231,6 +512,14 @@ export default {
}; };
</script> </script>
<style>
.batch-table-bkg--white {
background: #fff;
}
.batch-table__title {
font-size: 17px;
}
</style>
<style scoped lang="scss"> <style scoped lang="scss">
.span2 { .span2 {
grid-column: span 2; grid-column: span 2;

@ -0,0 +1,159 @@
<template>
<el-card>
<div :id="id" :class="className" :style="{height:height,width:width}" />
</el-card>
</template>
<script>
import * as echarts from 'echarts'
import resize from '@/components/Charts/mixins/resize'
import { chart } from "@/api/user/user";
export default {
mixins: [resize],
props: {
select: {
type: Object,
default: () => ({})
},
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
},
data() {
return {
chart: null,
data: [],
}
},
created() {
},
mounted() {
this.getData().then(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
async getData () {
try {
const { userAreas } = await chart(this.select)
this.data = userAreas;
} catch (err) {
console.error(err)
}
},
initChart() {
this.chart = echarts.init(document.getElementById(this.id))
this.setOption()
},
setOption () {
this.chart.setOption({
title: {
text: "区域占比统计"
},
tooltip: {
trigger: 'item',
},
legend: {
right: "right",
top: "6%",
icon: "circle",
formatter: name => {
let total = this.data.reduce((pre, cur) => pre + (isNaN(Number(cur.total??0)) ? 0 : Number(cur.total??0)), 0)
let arr = [
'{a|' + name + '}',
'{b|' + (Math.round(this.data.find(i => i.area === name)?.total??0 / total) * 100).toFixed(2) + '%}',
'{c|' + (this.data.find(i => i.area === name)?.total??0) + '}'
]
return arr.join(' ')
},
textStyle: {
padding: [0, 0, 0, 0],
rich: {
a: {
fontSize: 15,
width: 110
},
b: {
fontSize: 15,
width: 70,
color: '#c1c1c1'
},
c: {
fontSize: 15
}
}
}
},
toolbox: {
show: false,
feature: {
mark: { show: true },
dataView: { show: true, readOnly: false },
restore: { show: true },
saveAsImage: { show: true }
}
},
color:['#609ff8','#79c97e','#f5d564','#de5567', '#9062de','#73c9ca'],
series: [
{
name: '区域',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 30,
borderColor: '#fff',
borderWidth: 4
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: 30,
fontWeight: 'bold'
}
},
labelLine: {
show: false
},
data: this.data.map(i => ({ value: i.total ?? 0, name: i.area ?? '-' })),
}
]
})
}
},
watch: {
select: {
handler: function () {
this.getData().then(() => {
this.initChart()
})
}
}
}
}
</script>

@ -0,0 +1,104 @@
<template>
<div>
<el-card shadow="never" style="margin-top: 20px">
<template #header>
<slot name="header">
<vxe-toolbar ref="toolbar">
<template #buttons>
<el-date-picker
v-model="select.start"
align="right"
type="date"
size="small"
placeholder="选择开始日期"
style="width: 140px;margin-right: 10px;"
:picker-options="pickerOptions">
</el-date-picker>
<el-date-picker
v-model="select.end"
align="right"
type="date"
size="small"
placeholder="选择结束日期"
style="width: 140px;margin-right: 10px;"
:picker-options="pickerOptions">
</el-date-picker>
<el-button
v-if="isHasAuth('search')"
icon="el-icon-search"
type="primary"
plain
size="small"
@click="$refs['PieChart'].getData()"
>搜索</el-button
>
</template>
</vxe-toolbar>
</slot>
</template>
<PieChart ref="PieChart" id="pie-chart" :select="select" width="100%" height="64vh"></PieChart>
</el-card>
</div>
</template>
<script>
import { authMixin } from "@/mixin/authMixin";
import PieChart from "./components/PieChart.vue"
export default {
components: {
PieChart
},
mixins: [authMixin],
data() {
return {
select: {
start: "",
end: ""
},
pickerOptions: {
shortcuts: [{
text: '今天',
onClick(picker) {
picker.$emit('pick', new Date());
}
}, {
text: '昨天',
onClick(picker) {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24);
picker.$emit('pick', date);
}
}, {
text: '一周前',
onClick(picker) {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit('pick', date);
}
}]
}
}
},
methods: {
},
computed: {
isHasAuth() {
return function (auth) {
return this.auths_auth_mixin.indexOf(auth) !== -1;
};
},
},
created() {
}
}
</script>
<style scoped lang="scss">
::v-deep .el-card__header {
padding: 6px 20px;
}
::v-deep .el-tag + .el-tag {
margin-left: 4px;
}
</style>
Loading…
Cancel
Save