<template>
|
<el-container direction="vertical">
|
<app-header title="交通统计报表审核系统 - 系统配置"></app-header>
|
<el-container>
|
<el-aside width="200px">
|
<el-menu ref="sideMenu" router :default-active="$route.path" @select="onMenuSelect">
|
<el-menu-item index="/dashboard">工作台</el-menu-item>
|
<el-menu-item index="/import">数据导入</el-menu-item>
|
<el-menu-item index="/data">数据查看</el-menu-item>
|
<el-menu-item index="/explain">企业解释</el-menu-item>
|
<el-menu-item index="/audit">审核结果</el-menu-item>
|
<el-menu-item index="/report">报表生成</el-menu-item>
|
<el-submenu index="/special-stats">
|
<template slot="title">专项统计</template>
|
<el-menu-item index="/holiday-stat">节假日</el-menu-item>
|
</el-submenu>
|
<el-menu-item index="/rules">规则管理</el-menu-item>
|
<el-menu-item index="/users">用户管理</el-menu-item>
|
<el-menu-item v-if="operatorIsAdmin" index="/system-config">系统配置</el-menu-item>
|
</el-menu>
|
</el-aside>
|
<el-main>
|
<div class="page-scroll">
|
<h3>系统配置</h3>
|
<el-tabs v-model="activeTab" @tab-click="loadActiveTab">
|
<el-tab-pane label="节假日管理" name="holidays">
|
<div class="toolbar">
|
<el-select v-model="holidayQuery.year" clearable placeholder="年份" style="width:130px" @change="loadHolidays">
|
<el-option v-for="year in years" :key="year" :label="year + '年'" :value="year"></el-option>
|
</el-select>
|
<el-select v-model="holidayQuery.holidayType" clearable placeholder="节假日分类" style="width:150px" @change="loadHolidays">
|
<el-option v-for="item in holidayTypeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
</el-select>
|
<el-button type="primary" icon="el-icon-search" @click="loadHolidays">查询</el-button>
|
<el-button type="success" icon="el-icon-plus" @click="openHolidayDialog()">新增节假日</el-button>
|
</div>
|
<el-table :data="holidays" border stripe size="small" v-loading="loadingHolidays" style="width:100%">
|
<el-table-column prop="year" label="年份" width="100" align="center"></el-table-column>
|
<el-table-column label="节假日分类" width="140">
|
<template slot-scope="scope">{{ labelOf(holidayTypeOptions, scope.row.holidayType) }}</template>
|
</el-table-column>
|
<el-table-column prop="holidayDate" label="日期" width="150" align="center"></el-table-column>
|
<el-table-column prop="dayIndex" label="第几日" width="100" align="center"></el-table-column>
|
<el-table-column label="操作" width="150" align="center">
|
<template slot-scope="scope">
|
<el-button type="text" size="mini" @click="openHolidayDialog(scope.row)">编辑</el-button>
|
<el-button type="text" size="mini" class="danger-text" @click="removeHoliday(scope.row)">删除</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</el-tab-pane>
|
|
<el-tab-pane label="客运系数管理" name="coefficients">
|
<div class="toolbar">
|
<el-select v-model="coefficientQuery.year" clearable placeholder="年份" style="width:130px" @change="loadCoefficients">
|
<el-option v-for="year in years" :key="year" :label="year + '年'" :value="year"></el-option>
|
</el-select>
|
<el-button type="primary" icon="el-icon-search" @click="loadCoefficients">查询</el-button>
|
<el-button type="success" icon="el-icon-plus" @click="openCoefficientDialog()">新增客运系数</el-button>
|
</div>
|
<el-table :data="coefficients" border stripe size="small" v-loading="loadingCoefficients" style="width:100%">
|
<el-table-column prop="year" label="年份" width="120" align="center"></el-table-column>
|
<el-table-column label="日期分类" width="160">
|
<template slot-scope="scope">{{ labelOf(dateCategoryOptions, scope.row.dateCategory) }}</template>
|
</el-table-column>
|
<el-table-column label="客运系数" width="160" align="center">
|
<template slot-scope="scope">{{ formatCoefficient(scope.row.coefficient) }}</template>
|
</el-table-column>
|
<el-table-column label="操作" width="150" align="center">
|
<template slot-scope="scope">
|
<el-button type="text" size="mini" @click="openCoefficientDialog(scope.row)">编辑</el-button>
|
<el-button type="text" size="mini" class="danger-text" @click="removeCoefficient(scope.row)">删除</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
</el-tab-pane>
|
</el-tabs>
|
</div>
|
|
<el-dialog :title="holidayForm.id ? '编辑节假日' : '新增节假日'" :visible.sync="holidayDialog" width="520px" v-dialog-drag>
|
<el-form ref="holidayForm" :model="holidayForm" :rules="holidayRules" label-width="110px">
|
<el-form-item label="年份" prop="year">
|
<el-select v-model="holidayForm.year" style="width:100%" @change="onHolidayYearChange">
|
<el-option v-for="year in years" :key="year" :label="year + '年'" :value="year"></el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="节假日分类" prop="holidayType">
|
<el-select v-model="holidayForm.holidayType" style="width:100%">
|
<el-option v-for="item in holidayTypeOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="日期" prop="holidayDate">
|
<el-date-picker v-model="holidayForm.holidayDate" type="date" value-format="yyyy-MM-dd"
|
style="width:100%" placeholder="选择日期"></el-date-picker>
|
</el-form-item>
|
<el-form-item label="第几日" prop="dayIndex">
|
<el-input-number v-model="holidayForm.dayIndex" :min="1" :max="31" style="width:100%"></el-input-number>
|
</el-form-item>
|
</el-form>
|
<span slot="footer">
|
<el-button @click="holidayDialog = false">取消</el-button>
|
<el-button type="primary" :loading="saving" @click="saveHoliday">保存</el-button>
|
</span>
|
</el-dialog>
|
|
<el-dialog :title="coefficientForm.id ? '编辑客运系数' : '新增客运系数'" :visible.sync="coefficientDialog" width="520px" v-dialog-drag>
|
<el-form ref="coefficientForm" :model="coefficientForm" :rules="coefficientRules" label-width="110px">
|
<el-form-item label="年份" prop="year">
|
<el-select v-model="coefficientForm.year" style="width:100%">
|
<el-option v-for="year in years" :key="year" :label="year + '年'" :value="year"></el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="日期分类" prop="dateCategory">
|
<el-select v-model="coefficientForm.dateCategory" style="width:100%">
|
<el-option v-for="item in dateCategoryOptions" :key="item.value" :label="item.label" :value="item.value"></el-option>
|
</el-select>
|
</el-form-item>
|
<el-form-item label="客运系数" prop="coefficient">
|
<el-input-number v-model="coefficientForm.coefficient" :min="0.01" :precision="4" :step="0.1" style="width:100%"></el-input-number>
|
</el-form-item>
|
</el-form>
|
<span slot="footer">
|
<el-button @click="coefficientDialog = false">取消</el-button>
|
<el-button type="primary" :loading="saving" @click="saveCoefficient">保存</el-button>
|
</span>
|
</el-dialog>
|
</el-main>
|
</el-container>
|
</el-container>
|
</template>
|
|
<script>
|
import api from '@/api'
|
import AppHeader from '@/components/AppHeader.vue'
|
|
export default {
|
components: { AppHeader },
|
name: 'SystemConfig',
|
data() {
|
return {
|
activeTab: 'holidays',
|
years: [2024, 2025, 2026, 2027, 2028, 2029, 2030],
|
holidayTypeOptions: [],
|
dateCategoryOptions: [],
|
holidayQuery: { year: 2026, holidayType: 'NATIONAL_DAY' },
|
coefficientQuery: { year: 2026 },
|
holidays: [],
|
coefficients: [],
|
loadingHolidays: false,
|
loadingCoefficients: false,
|
saving: false,
|
holidayDialog: false,
|
coefficientDialog: false,
|
holidayForm: { id: null, year: 2026, holidayType: 'NATIONAL_DAY', holidayDate: '', dayIndex: 1 },
|
coefficientForm: { id: null, year: 2026, dateCategory: 'HOLIDAY', coefficient: 2.4 },
|
holidayRules: {
|
year: [{ required: true, message: '请选择年份', trigger: 'change' }],
|
holidayType: [{ required: true, message: '请选择节假日分类', trigger: 'change' }],
|
holidayDate: [{ required: true, message: '请选择日期', trigger: 'change' }],
|
dayIndex: [{ required: true, message: '请输入第几日', trigger: 'change' }]
|
},
|
coefficientRules: {
|
year: [{ required: true, message: '请选择年份', trigger: 'change' }],
|
dateCategory: [{ required: true, message: '请选择日期分类', trigger: 'change' }],
|
coefficient: [{ required: true, message: '请输入客运系数', trigger: 'change' }]
|
}
|
}
|
},
|
mounted() {
|
this.loadOptions()
|
this.loadHolidays()
|
this.loadCoefficients()
|
},
|
methods: {
|
loadOptions() {
|
api.get('/holiday/config/options').then(res => {
|
const data = res.data || {}
|
this.holidayTypeOptions = this.mapOptions(data.holidayTypes)
|
this.dateCategoryOptions = this.mapOptions(data.dateCategories)
|
})
|
},
|
mapOptions(map) {
|
if (!map) return []
|
return Object.keys(map).map(key => ({ value: key, label: map[key] }))
|
},
|
labelOf(options, value) {
|
const item = (options || []).find(x => x.value === value)
|
return item ? item.label : value
|
},
|
loadActiveTab() {
|
if (this.activeTab === 'holidays') this.loadHolidays()
|
else this.loadCoefficients()
|
},
|
loadHolidays() {
|
this.loadingHolidays = true
|
api.get('/holiday/config/holidays', { params: this.holidayQuery })
|
.then(res => { this.holidays = res.data || [] })
|
.catch(e => { if (!e || !e._toast) this.$message.error('节假日加载失败') })
|
.finally(() => { this.loadingHolidays = false })
|
},
|
loadCoefficients() {
|
this.loadingCoefficients = true
|
api.get('/holiday/config/coefficients', { params: this.coefficientQuery })
|
.then(res => { this.coefficients = res.data || [] })
|
.catch(e => { if (!e || !e._toast) this.$message.error('客运系数加载失败') })
|
.finally(() => { this.loadingCoefficients = false })
|
},
|
openHolidayDialog(row) {
|
this.holidayDialog = true
|
this.$nextTick(() => {
|
this.holidayForm = row ? Object.assign({}, row) : { id: null, year: 2026, holidayType: 'NATIONAL_DAY', holidayDate: '', dayIndex: 1 }
|
if (this.$refs.holidayForm) this.$refs.holidayForm.clearValidate()
|
})
|
},
|
onHolidayYearChange(year) {
|
if (this.holidayForm.holidayDate && Number(this.holidayForm.holidayDate.slice(0, 4)) !== year) {
|
this.holidayForm.holidayDate = ''
|
}
|
},
|
saveHoliday() {
|
this.$refs.holidayForm.validate(valid => {
|
if (!valid) return
|
this.saving = true
|
api.post('/holiday/config/holidays/save', this.holidayForm)
|
.then(res => {
|
if (res.code !== 200) throw new Error(res.message || '保存失败')
|
this.$message.success('保存成功')
|
this.holidayDialog = false
|
this.loadHolidays()
|
})
|
.catch(err => this.showError(err, '保存失败'))
|
.finally(() => { this.saving = false })
|
})
|
},
|
removeHoliday(row) {
|
this.$confirm('确定删除该节假日日期吗?', '删除确认', { type: 'warning' })
|
.then(() => api.post('/holiday/config/holidays/delete', null, { params: { id: row.id } }))
|
.then(res => {
|
if (res.code !== 200) throw new Error(res.message || '删除失败')
|
this.$message.success('已删除')
|
this.loadHolidays()
|
})
|
.catch(err => { if (err !== 'cancel') this.showError(err, '删除失败') })
|
},
|
openCoefficientDialog(row) {
|
this.coefficientDialog = true
|
this.$nextTick(() => {
|
this.coefficientForm = row ? Object.assign({}, row) : { id: null, year: 2026, dateCategory: 'HOLIDAY', coefficient: 2.4 }
|
if (this.$refs.coefficientForm) this.$refs.coefficientForm.clearValidate()
|
})
|
},
|
saveCoefficient() {
|
this.$refs.coefficientForm.validate(valid => {
|
if (!valid) return
|
this.saving = true
|
api.post('/holiday/config/coefficients/save', this.coefficientForm)
|
.then(res => {
|
if (res.code !== 200) throw new Error(res.message || '保存失败')
|
this.$message.success('保存成功')
|
this.coefficientDialog = false
|
this.loadCoefficients()
|
})
|
.catch(err => this.showError(err, '保存失败'))
|
.finally(() => { this.saving = false })
|
})
|
},
|
removeCoefficient(row) {
|
this.$confirm('确定删除该客运系数吗?', '删除确认', { type: 'warning' })
|
.then(() => api.post('/holiday/config/coefficients/delete', null, { params: { id: row.id } }))
|
.then(res => {
|
if (res.code !== 200) throw new Error(res.message || '删除失败')
|
this.$message.success('已删除')
|
this.loadCoefficients()
|
})
|
.catch(err => { if (err !== 'cancel') this.showError(err, '删除失败') })
|
},
|
formatCoefficient(value) {
|
if (value === null || value === undefined || value === '') return '—'
|
const number = Number(value)
|
if (!Number.isFinite(number)) return value
|
return number.toFixed(15).replace(/0+$/, '').replace(/\.$/, '')
|
},
|
showError(err, fallback) {
|
if (err && err._toast) return
|
const data = err && err.response && err.response.data
|
this.$message.error((data && data.message) || (err && err.message) || fallback)
|
}
|
}
|
}
|
</script>
|
|
<style scoped>
|
.toolbar { margin-bottom: 12px; display: flex; gap: 8px; align-items: center; }
|
.danger-text { color: #f56c6c; }
|
</style>
|