提交 c8ba2aa9 authored 作者: 王鹏飞's avatar 王鹏飞

feat: 增加生源地分布

上级 732a4574
......@@ -216,14 +216,15 @@ export const menus: IMenuItem[] = [
name: '数据可视化',
path: '/teach/chart/visualization',
},
// {
// tag: '',
// icon: DataAnalysis,
// name: '生源地分布',
// path:
// import.meta.env.VITE_BI_URL +
// '/bi/?proc=1&action=viewer&hback=true&isInPreview=true&db=!7d2b!!8346!!6559!!80b2!e-SaaS!2f!!751f!!6e90!!5730!!5206!!5e03!.db&platform=PC&browserType=chrome',
// },
{
tag: '',
icon: DataAnalysis,
name: '生源地分布',
path: '/teach/chart/origin',
// path:
// import.meta.env.VITE_BI_URL +
// '/bi/?proc=1&action=viewer&hback=true&isInPreview=true&db=!7d2b!!8346!!6559!!80b2!e-SaaS!2f!!751f!!6e90!!5730!!5206!!5e03!.db&platform=PC&browserType=chrome',
},
],
},
]
......@@ -154,10 +154,11 @@ const handleSelectionChange = (val: any) => {
}
const handleAnalysis = () => {
// isShowAnalysisDialog.value = true
window.open(
import.meta.env.VITE_BI_URL +
'/bi/?proc=1&action=viewer&hback=true&isInPreview=true&db=!7d2b!!8346!!6559!!80b2!e-SaaS!2f!!751f!!6e90!!5730!!5206!!5e03!.db&platform=PC&browserType=chrome'
)
window.open('/teach/chart/origin')
// window.open(
// import.meta.env.VITE_BI_URL +
// '/bi/?proc=1&action=viewer&hback=true&isInPreview=true&db=!7d2b!!8346!!6559!!80b2!e-SaaS!2f!!751f!!6e90!!5730!!5206!!5e03!.db&platform=PC&browserType=chrome'
// )
}
</script>
......
......@@ -9,6 +9,7 @@ export const routes: Array<RouteRecordRaw> = [
{ path: 'resource', component: () => import('./views/Resource.vue') },
{ path: 'learning', component: () => import('./views/Learning.vue') },
{ path: 'visualization', component: () => import('./views/Visualization.vue') },
{ path: 'origin', component: () => import('./views/Origin.vue') },
],
},
]
<template>
<div class="origin-container">
<!-- 页面标题 -->
<div class="header">
<h1>
<el-icon class="header-icon"><Location /></el-icon>
生源地分布可视化
</h1>
<p>全面了解学生来源地域分布情况与统计分析</p>
</div>
<!-- 筛选器 -->
<div class="filter-bar">
<div class="filter-group">
<el-icon class="filter-icon" style="color: var(--primary-color)"><Calendar /></el-icon>
<label>学期:</label>
<select v-model="filters.year" @change="onFilterChange">
<option value="2024">2024学年</option>
<option value="2023">2023学年</option>
<option value="2022">2022学年</option>
</select>
</div>
<div class="filter-group">
<el-icon class="filter-icon" style="color: var(--secondary-color)"><School /></el-icon>
<label>年级:</label>
<select v-model="filters.grade" @change="onFilterChange">
<option value="all">全部年级</option>
<option value="1">一年级</option>
<option value="2">二年级</option>
<option value="3">三年级</option>
<option value="4">四年级</option>
</select>
</div>
<div class="filter-group">
<el-icon class="filter-icon" style="color: var(--success-color)"><Grid /></el-icon>
<label>专业:</label>
<select v-model="filters.major" @change="onFilterChange">
<option value="all">全部专业</option>
<option value="cs">计算机科学</option>
<option value="ee">电子工程</option>
<option value="ba">工商管理</option>
<option value="med">医学</option>
</select>
</div>
</div>
<!-- 统计卡片 -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #c21f30 0%, #e94057 100%)">
<el-icon class="stat-icon-inner"><User /></el-icon>
</div>
<div class="stat-content">
<div class="stat-value">{{ stats.totalStudents.toLocaleString() }}</div>
<div class="stat-label">学生总数</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #f59e0b 0%, #fbbf24 100%)">
<el-icon class="stat-icon-inner"><LocationInformation /></el-icon>
</div>
<div class="stat-content">
<div class="stat-value">{{ stats.provinces }}</div>
<div class="stat-label">覆盖省份</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #10b981 0%, #34d399 100%)">
<el-icon class="stat-icon-inner"><OfficeBuilding /></el-icon>
</div>
<div class="stat-content">
<div class="stat-value">{{ stats.cities }}</div>
<div class="stat-label">覆盖城市</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%)">
<el-icon class="stat-icon-inner"><Location /></el-icon>
</div>
<div class="stat-content">
<div class="stat-value">{{ stats.internationalCountries }}</div>
<div class="stat-label">国际学生国家</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon" style="background: linear-gradient(135deg, #8b5cf6 0%, #a78bfa 100%)">
<el-icon class="stat-icon-inner"><TrendCharts /></el-icon>
</div>
<div class="stat-content">
<div class="stat-value">{{ stats.localPercentage }}%</div>
<div class="stat-label">省内生源比例</div>
</div>
</div>
</div>
<!-- 图表区域 -->
<div class="charts-section">
<h2 class="section-title">分布分析</h2>
<div class="charts-grid">
<div class="chart-card">
<h3>
<el-icon class="chart-title-icon"><PieChart /></el-icon> 生源地区域分布
</h3>
<div ref="regionPieChart" class="chart-container"></div>
</div>
<div class="chart-card">
<h3>
<el-icon class="chart-title-icon"><Histogram /></el-icon> 省内城市分布 TOP10
</h3>
<div ref="cityBarChart" class="chart-container"></div>
</div>
</div>
</div>
<!-- 地图可视化 -->
<div class="map-section">
<h2 class="section-title">全国生源地图分布</h2>
<div ref="chinaMapChart" class="map-container"></div>
</div>
<!-- 详细数据表格 -->
<div class="table-section">
<h2 class="section-title">生源地详细数据</h2>
<table class="data-table">
<thead>
<tr>
<th>排名</th>
<th>省份</th>
<th>学生人数</th>
<th>占比</th>
<th>趋势</th>
<th>分布可视化</th>
</tr>
</thead>
<tbody>
<tr v-for="item in provinceData" :key="item.name">
<td>
<span :class="`rank-badge ${getRankClass(item.rank)}`">
{{ item.rank }}
</span>
</td>
<td>
<strong>{{ item.name }}</strong>
</td>
<td>
<strong style="color: var(--primary-color)">
{{ item.value.toLocaleString() }}
</strong>
</td>
<td>
<strong>{{ item.percentage }}%</strong>
</td>
<td :style="{ color: getTrendColor(item.trend) }">
<el-icon class="trend-icon">
<ArrowUp v-if="item.trend.startsWith('+')" />
<ArrowDown v-else-if="item.trend.startsWith('-')" />
<Minus v-else />
</el-icon>
{{ item.trend }}
</td>
<td>
<div class="progress-bar">
<div class="progress-fill" :style="{ width: `${item.percentage}%` }"></div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted, onUnmounted, nextTick } from 'vue'
import * as echarts from 'echarts'
import {
Location,
Calendar,
School,
Grid,
User,
LocationInformation,
OfficeBuilding,
TrendCharts,
PieChart,
Histogram,
ArrowUp,
ArrowDown,
Minus,
} from '@element-plus/icons-vue'
// 类型定义
interface ProvinceData {
name: string
value: number
percentage: number
trend: string
rank: number
}
interface Stats {
totalStudents: number
provinces: number
cities: number
internationalCountries: number
localPercentage: number
}
interface Filters {
year: string
grade: string
major: string
}
// 响应式数据
const regionPieChart = ref<HTMLElement>()
const cityBarChart = ref<HTMLElement>()
const chinaMapChart = ref<HTMLElement>()
const filters = reactive<Filters>({
year: '2024',
grade: 'all',
major: 'all',
})
const stats = reactive<Stats>({
totalStudents: 8650,
provinces: 31,
cities: 256,
internationalCountries: 12,
localPercentage: 68,
})
const provinceData = ref<ProvinceData[]>([
{ name: '广东', value: 5882, percentage: 68, trend: '+5%', rank: 1 },
{ name: '湖南', value: 432, percentage: 5, trend: '+2%', rank: 2 },
{ name: '湖北', value: 389, percentage: 4.5, trend: '+3%', rank: 3 },
{ name: '江西', value: 346, percentage: 4, trend: '+1%', rank: 4 },
{ name: '河南', value: 302, percentage: 3.5, trend: '-1%', rank: 5 },
{ name: '四川', value: 259, percentage: 3, trend: '+4%', rank: 6 },
{ name: '广西', value: 216, percentage: 2.5, trend: '+2%', rank: 7 },
{ name: '福建', value: 173, percentage: 2, trend: '0%', rank: 8 },
{ name: '浙江', value: 156, percentage: 1.8, trend: '+1%', rank: 9 },
{ name: '江苏', value: 138, percentage: 1.6, trend: '+2%', rank: 10 },
{ name: '其他', value: 357, percentage: 4.1, trend: '+1%', rank: 11 },
])
// 图表实例
let regionPieChartInstance: echarts.ECharts | null = null
let cityBarChartInstance: echarts.ECharts | null = null
let chinaMapChartInstance: echarts.ECharts | null = null
// 工具函数
const getRankClass = (rank: number): string => {
return rank <= 3 ? `rank-${rank}` : 'rank-other'
}
const getTrendColor = (trend: string): string => {
if (trend.startsWith('+')) return '#10b981'
if (trend.startsWith('-')) return '#ef4444'
return '#6b7280'
}
// 初始化区域分布饼图
const initRegionPieChart = () => {
if (!regionPieChart.value) return
regionPieChartInstance = echarts.init(regionPieChart.value)
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c}人 ({d}%)',
},
legend: {
orient: 'vertical',
right: 10,
top: 'center',
textStyle: { fontSize: 12 },
},
color: ['#C21F30', '#E94057', '#f59e0b', '#10b981', '#3b82f6', '#8b5cf6'],
series: [
{
name: '区域分布',
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2,
},
label: {
show: true,
formatter: '{b}\n{d}%',
},
emphasis: {
label: {
show: true,
fontSize: 16,
fontWeight: 'bold',
},
},
data: [
{ value: 5882, name: '省内' },
{ value: 1214, name: '华中地区' },
{ value: 518, name: '西南地区' },
{ value: 432, name: '华东地区' },
{ value: 389, name: '华北地区' },
{ value: 215, name: '其他地区' },
],
},
],
}
regionPieChartInstance.setOption(option)
}
// 初始化城市分布柱状图
const initCityBarChart = () => {
if (!cityBarChart.value) return
cityBarChartInstance = echarts.init(cityBarChart.value)
const option = {
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: {
type: 'value',
axisLabel: { fontSize: 11 },
},
yAxis: {
type: 'category',
data: ['惠州', '东莞', '佛山', '中山', '珠海', '江门', '肇庆', '汕头', '湛江', '深圳'],
axisLabel: { fontSize: 11 },
},
series: [
{
name: '学生人数',
type: 'bar',
data: [856, 923, 1245, 678, 534, 489, 412, 367, 325, 1053],
itemStyle: {
borderRadius: [0, 8, 8, 0],
color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [
{ offset: 0, color: '#C21F30' },
{ offset: 1, color: '#E94057' },
]),
},
label: {
show: true,
position: 'right',
fontSize: 11,
},
},
],
}
cityBarChartInstance.setOption(option)
}
// 初始化中国地图
const initChinaMap = async () => {
if (!chinaMapChart.value) return
chinaMapChartInstance = echarts.init(chinaMapChart.value)
const mapData = [
{ name: '广东', value: 5882 },
{ name: '湖南', value: 432 },
{ name: '湖北', value: 389 },
{ name: '江西', value: 346 },
{ name: '河南', value: 302 },
{ name: '四川', value: 259 },
{ name: '广西', value: 216 },
{ name: '福建', value: 173 },
{ name: '浙江', value: 156 },
{ name: '江苏', value: 138 },
{ name: '安徽', value: 125 },
{ name: '山东', value: 112 },
{ name: '重庆', value: 98 },
{ name: '贵州', value: 87 },
{ name: '云南', value: 76 },
]
const option = {
title: {
text: '全国生源分布热力图',
left: 'center',
top: 20,
textStyle: {
fontSize: 16,
color: '#2C3E50',
},
},
tooltip: {
trigger: 'item',
formatter: function (params: any) {
if (params.value) {
return params.name + '<br/>学生人数: ' + params.value + '人'
}
return params.name + '<br/>暂无数据'
},
},
visualMap: {
min: 0,
max: 6000,
text: ['高', '低'],
realtime: false,
calculable: true,
inRange: {
color: ['#fef2f2', '#fecaca', '#f87171', '#dc2626', '#C21F30'],
},
bottom: 50,
left: 20,
},
series: [
{
name: '生源分布',
type: 'scatter',
coordinateSystem: 'geo',
data: [
{ name: '广东', value: [113.23, 23.16, 5882] },
{ name: '湖南', value: [112.59, 28.21, 432] },
{ name: '湖北', value: [114.31, 30.52, 389] },
{ name: '江西', value: [115.89, 28.68, 346] },
{ name: '河南', value: [113.65, 34.76, 302] },
{ name: '四川', value: [104.06, 30.67, 259] },
{ name: '广西', value: [108.33, 22.84, 216] },
{ name: '福建', value: [119.3, 26.08, 173] },
{ name: '浙江', value: [120.19, 30.26, 156] },
{ name: '江苏', value: [118.78, 32.04, 138] },
],
symbolSize: function (val: number[]) {
return Math.sqrt(val[2]) / 2
},
itemStyle: {
color: '#C21F30',
shadowBlur: 10,
shadowColor: 'rgba(194, 31, 48, 0.5)',
},
label: {
formatter: '{b}',
position: 'top',
show: false,
},
emphasis: {
label: {
show: true,
},
},
},
],
geo: {
map: 'china',
roam: true,
scaleLimit: {
min: 1,
max: 3,
},
label: {
show: false,
},
itemStyle: {
areaColor: '#f3f3f3',
borderColor: '#ccc',
},
emphasis: {
itemStyle: {
areaColor: '#e6f2ff',
},
label: {
show: true,
color: '#333',
},
},
},
}
try {
// 尝试加载中国地图数据
const response = await fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json')
const chinaJson = await response.json()
echarts.registerMap('china', chinaJson)
chinaMapChartInstance.setOption(option)
} catch (error) {
// 如果加载失败,显示备用图表
console.log('地图加载失败,使用备用可视化')
const backupOption = {
title: {
text: '省份生源排行',
left: 'center',
top: 20,
},
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
},
grid: {
left: '10%',
right: '10%',
top: '15%',
bottom: '10%',
},
xAxis: {
type: 'category',
data: mapData.map((item) => item.name),
axisLabel: {
interval: 0,
rotate: 45,
fontSize: 11,
},
},
yAxis: {
type: 'value',
name: '学生人数',
},
series: [
{
type: 'bar',
data: mapData.map((item) => item.value),
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: '#C21F30' },
{ offset: 1, color: '#E94057' },
]),
borderRadius: [8, 8, 0, 0],
},
label: {
show: true,
position: 'top',
fontSize: 10,
},
},
],
}
chinaMapChartInstance.setOption(backupOption)
}
}
// 筛选器变化处理
const onFilterChange = () => {
console.log('筛选器变化:', filters)
// 这里可以添加数据刷新逻辑
// 例如:重新获取数据、更新图表等
}
// 窗口大小变化处理
const handleResize = () => {
regionPieChartInstance?.resize()
cityBarChartInstance?.resize()
chinaMapChartInstance?.resize()
}
// 生命周期
onMounted(async () => {
await nextTick()
initRegionPieChart()
initCityBarChart()
await initChinaMap()
window.addEventListener('resize', handleResize)
})
onUnmounted(() => {
regionPieChartInstance?.dispose()
cityBarChartInstance?.dispose()
chinaMapChartInstance?.dispose()
window.removeEventListener('resize', handleResize)
})
</script>
<style scoped>
.origin-container {
max-width: 1400px;
margin: 0 auto;
padding: 2rem;
/* background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); */
min-height: 100vh;
--primary-color: #c21f30;
--secondary-color: #e94057;
--success-color: #10b981;
--warning-color: #f59e0b;
--info-color: #3b82f6;
--dark-color: #333333;
--light-color: #f5f5f5;
--border-color: #e0e0e0;
--shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
--shadow-hover: 0 10px 25px rgba(0, 0, 0, 0.1);
}
.header {
text-align: center;
margin-bottom: 2rem;
padding: 2rem;
background: white;
border-radius: 16px;
box-shadow: var(--shadow);
}
.header h1 {
font-size: 2rem;
color: var(--dark-color);
margin-bottom: 0.5rem;
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
}
.header-icon {
color: var(--primary-color);
font-size: 2.5rem;
margin-right: 0.5rem;
}
.header p {
color: #7f8c8d;
font-size: 1rem;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
.stat-card {
background: white;
padding: 1.5rem;
border-radius: 12px;
box-shadow: var(--shadow);
transition: all 0.3s;
display: flex;
align-items: center;
gap: 1rem;
}
.stat-card:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-hover);
}
.stat-icon {
width: 60px;
height: 60px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.8rem;
flex-shrink: 0;
}
.stat-icon-inner {
color: white;
font-size: 1.8rem;
}
.stat-content {
flex: 1;
}
.stat-value {
font-size: 1.8rem;
font-weight: bold;
color: var(--dark-color);
margin-bottom: 0.25rem;
}
.stat-label {
color: #95a5a6;
font-size: 0.9rem;
}
.section-title {
font-size: 1.25rem;
color: var(--dark-color);
margin-bottom: 1rem;
padding-left: 1rem;
border-left: 4px solid var(--primary-color);
font-weight: 600;
}
.charts-section {
margin-bottom: 2rem;
}
.charts-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 1.5rem;
margin-bottom: 1.5rem;
}
.chart-card {
background: white;
padding: 1.5rem;
border-radius: 12px;
box-shadow: var(--shadow);
}
.chart-card h3 {
font-size: 1.1rem;
color: var(--dark-color);
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 2px solid var(--border-color);
display: flex;
align-items: center;
gap: 0.5rem;
}
.chart-title-icon {
color: var(--primary-color);
font-size: 1.2rem;
}
.chart-container {
width: 100%;
height: 320px;
}
.map-section {
background: white;
padding: 1.5rem;
border-radius: 12px;
box-shadow: var(--shadow);
margin-bottom: 2rem;
}
.map-container {
width: 100%;
height: 500px;
}
.table-section {
background: white;
padding: 1.5rem;
border-radius: 12px;
box-shadow: var(--shadow);
overflow: hidden;
}
.table-section h2 {
margin-bottom: 1.5rem;
}
.data-table {
width: 100%;
border-collapse: collapse;
margin-top: 1rem;
border: 1px solid var(--border-color);
border-radius: 8px;
overflow: hidden;
}
.data-table thead {
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
}
.data-table th,
.data-table td {
padding: 1rem;
text-align: left;
border-bottom: 1px solid var(--border-color);
border-right: 1px solid var(--border-color);
}
.data-table th:last-child,
.data-table td:last-child {
border-right: none;
}
.data-table th {
font-weight: 600;
border-bottom: 2px solid var(--border-color);
}
.data-table tbody tr {
transition: all 0.2s;
}
.data-table tbody tr:hover {
background: rgba(194, 31, 48, 0.05);
}
.data-table tbody tr:last-child td {
border-bottom: none;
}
.data-table tbody tr:nth-child(even) {
background: rgba(0, 0, 0, 0.02);
}
.data-table tbody tr:nth-child(even):hover {
background: rgba(194, 31, 48, 0.05);
}
.trend-icon {
margin-right: 0.25rem;
font-size: 0.9rem;
}
.rank-badge {
display: inline-block;
width: 28px;
height: 28px;
border-radius: 50%;
text-align: center;
line-height: 28px;
font-weight: bold;
color: white;
font-size: 0.9rem;
}
.rank-1 {
background: linear-gradient(135deg, #c21f30, #e94057);
}
.rank-2 {
background: linear-gradient(135deg, #f59e0b, #fbbf24);
}
.rank-3 {
background: linear-gradient(135deg, #10b981, #34d399);
}
.rank-other {
background: linear-gradient(135deg, #6b7280, #9ca3af);
}
.progress-bar {
width: 100%;
height: 12px;
background: #f0f0f0;
border-radius: 6px;
overflow: hidden;
margin-top: 0.5rem;
border: 1px solid #e0e0e0;
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
border-radius: 6px;
transition: width 1s ease;
min-width: 2px;
box-shadow: 0 1px 3px rgba(194, 31, 48, 0.3);
}
.filter-bar {
background: white;
padding: 1.5rem;
border-radius: 12px;
box-shadow: var(--shadow);
margin-bottom: 2rem;
display: flex;
gap: 1rem;
flex-wrap: wrap;
align-items: center;
}
.filter-group {
display: flex;
align-items: center;
gap: 0.5rem;
}
.filter-icon {
font-size: 1.1rem;
}
.filter-group label {
color: var(--dark-color);
font-weight: 500;
font-size: 0.95rem;
}
.filter-group select {
padding: 0.5rem 1rem;
border: 2px solid var(--border-color);
border-radius: 8px;
font-size: 0.95rem;
color: var(--dark-color);
background: white;
cursor: pointer;
transition: all 0.3s;
min-width: 120px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.filter-group select:hover {
border-color: var(--primary-color);
box-shadow: 0 2px 6px rgba(194, 31, 48, 0.15);
}
.filter-group select:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(194, 31, 48, 0.1), 0 2px 6px rgba(194, 31, 48, 0.15);
}
@media (max-width: 768px) {
.origin-container {
padding: 1rem;
}
.header h1 {
font-size: 1.5rem;
}
.stats-grid {
grid-template-columns: 1fr;
}
.charts-grid {
grid-template-columns: 1fr;
}
.map-container {
height: 350px;
}
.data-table {
font-size: 0.9rem;
}
.data-table th,
.data-table td {
padding: 0.75rem;
}
}
</style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论