路线管理

This commit is contained in:
Double-_-Z 2025-08-14 18:07:57 +08:00
parent 0aba0aabb6
commit bad36fc706
6 changed files with 220 additions and 535 deletions

View File

@ -2,10 +2,10 @@ ENV = 'production'
# 如果使用 Nginx 代理后端接口,那么此处需要改为 '/',文件查看 Docker 部署篇Nginx 配置
# 接口地址,注意协议,如果你没有配置 ssl需要将 https 改为 http
# VUE_APP_BASE_API = 'http://8.138.171.103/aerocraftAdminApi'
VUE_APP_BASE_API = 'https://webapi.aishangfeixing.com/aerocraftAdminApi/'
VUE_APP_BASE_API = 'http://8.138.171.103/aerocraftAdminApi'
# VUE_APP_BASE_API = 'https://webapi.aishangfeixing.com/aerocraftAdminApi/'
# 运行基本路径
# VUE_APP_BASE_PATH = 'http://8.138.171.103/aerocraftAdmin'
VUE_APP_BASE_PATH = 'https://webapi.aishangfeixing.com/aerocraftAdmin'
VUE_APP_BASE_PATH = 'http://8.138.171.103/aerocraftAdmin'
# VUE_APP_BASE_PATH = 'https://webapi.aishangfeixing.com/aerocraftAdmin'
# 如果接口是 http 形式, wss 需要改为 ws
VUE_APP_WS_API = 'wss://eladmin.vip'

View File

@ -1,82 +1,26 @@
import request from '@/utils/request'
// 分页查询路线(支持路线名模糊查询)
export function getRoutesByPage(params) {
export function add(data) {
return request({
url: 'cpRoute',
method: 'get',
params
})
}
// 添加路线
export function createRoute(data) {
return request({
url: 'cpRoute',
url: 'aerocraftAdminApi/cpRoute',
method: 'post',
data
})
}
// 修改路线
export function updateRoute(data) {
export function del(id) {
return request({
url: 'cpRoute',
url: `aerocraftAdminApi/cpRoute/${id}`,
method: 'delete',
})
}
export function edit(data) {
return request({
url: 'aerocraftAdminApi/cpRoute',
method: 'put',
data
})
}
// 全部路线
export function getAllRoutes(params) {
return request({
url: 'cpRoute/all',
method: 'get',
params
})
}
// 根据景区获取景区下的所有路线
export function getRoutesByAreaId(params) {
return request({
url: 'cpRoute/getByAreaId',
method: 'get',
params
})
}
// 根据景区名称模糊查询路线
export function searchRoutesByName(params) {
return request({
url: 'cpRoute/searchRoutesByName',
method: 'get',
params
})
}
// 查询单个路线
export function getRouteDetail(id) {
return request({
url: `cpRoute/${id}`,
method: 'get'
})
}
// 删除路线
export function deleteRoute(id) {
return request({
url: `cpRoute/${id}`,
method: 'delete'
})
}
export default {
getRoutesByPage,
createRoute,
updateRoute,
getAllRoutes,
getRoutesByAreaId,
searchRoutesByName,
getRouteDetail,
deleteRoute
}
export default { add, edit, del }

204
src/views/route/index.vue Normal file
View File

@ -0,0 +1,204 @@
<template>
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<div>
<!-- 搜索 -->
<el-select
v-model="query.scenicId "
placeholder="请选择景区"
clearable
filterable
class="filter-item"
style="width: 200px"
>
<el-option
v-for="scenic in scenicOptions"
:key="scenic.id"
:label="scenic.name"
:value="scenic.id"
/>
</el-select>
<el-input
v-model="query.name"
clearable
size="small"
placeholder="输入路线名称"
style="width: 200px;"
class="filter-item"
@keyup.enter.native="crud.toQuery"
/>
<rrOperation />
<el-button v-permission="permission.add" class="filter-item" size="mini" type="primary"
icon="el-icon-plus" @click="crud.toAdd">
添加{{ crud.title }}
</el-button>
</div>
</div>
<!--表单渲染-->
<el-dialog append-to-body :before-close="crud.cancelCU" :visible.sync="crud.status.cu > 0"
:title="crud.status.title" width="400px">
<el-form ref="form" :model="form" :rules="rules" size="small" label-width="80px">
<el-row :gutter="10">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" placeholder="请输入路线名称"/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="区域名称" prop="areaId">
<el-select v-model="form.areaId" placeholder="请选择区域" clearable @change="changeArea">
<el-option v-for="item in areas" :key="item.name" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="景区名称" prop="scenicId">
<el-select v-model="form.scenicId" placeholder="请选择景区">
<el-option v-for="item in scenics" :key="item.name"
:label="item.name" :value="Number(item.id)"/>
</el-select>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="起飞点" prop="startPoint">
<el-input v-model="form.startPoint" placeholder="请输入起飞点"/>
</el-form-item>
</el-col>
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24" class="mb20">
<el-form-item label="降落点" prop="endPoint">
<el-input v-model="form.endPoint" placeholder="请输入降落点"/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div slot="footer" class="dialog-footer" style="margin-top: -30px;">
<el-button type="text" @click="crud.cancelCU">取消</el-button>
<el-button :loading="crud.status.cu === 2" type="primary" @click="crud.submitCU">保存</el-button>
</div>
</el-dialog>
<!--表格渲染-->
<el-table ref="table" v-loading="crud.loading" :data="crud.data" style="width: 100%;">
<el-table-column :show-overflow-tooltip="true" prop="areaName" label="区域名称" :formatter="commonFormatter" />
<el-table-column :show-overflow-tooltip="true" prop="scenicName" label="景区名称" :formatter="commonFormatter" />
<el-table-column :show-overflow-tooltip="true" prop="name" label="路线名称" :formatter="commonFormatter" />
<el-table-column :show-overflow-tooltip="true" prop="createTime" label="创建时间" :formatter="commonFormatter" />
<el-table-column v-if="checkPer(['admin', 'route:edit', 'route:del'])" label="操作" align="center"
fixed="right">
<template slot-scope="scope">
<udOperation :data="scope.row" :permission="permission"/>
</template>
</el-table-column>
</el-table>
<!--分页组件-->
<pagination />
</div>
</template>
<script>
import crudRoute from '@/api/route'
import CRUD, { presenter, header, form, crud } from '@crud/crud'
import rrOperation from '@crud/RR.operation'
import udOperation from '@crud/UD.operation'
import pagination from '@crud/Pagination'
import { allAreas } from '@/api/system/area'
import { allScenic } from "@/api/system/scenic";
const defaultForm = { areaId: null, endPoint: null, name: null, remark: null, scenicId: null, startPoint: null }
export default {
name: 'Route',
components: { udOperation, rrOperation, pagination },
cruds() {
return CRUD({ title: '路线', url: '/aerocraftAdminApi/cpRoute', crudMethod: { ...crudRoute }, optShow: { add: true, reset: true },
// data
initData:(crud,data)=>{
crud.page.total = data.total
crud.data = data.records
}})
},
mixins: [presenter(), header(), form(defaultForm), crud()],
data(){
return {
permission: {
add: ['admin', 'route:add'],
edit: ['admin', 'route:edit'],
del: ['admin', 'route:del']
},
rules: {
name: [
{ required: true, message: '请输入路线名称', trigger: 'blur' },
],
areaId: [
{ required: true, message: '区域不能为空', trigger: 'change' }
],
scenicId: [
{ required: true, message: '景区不能为空', trigger: 'change' }
],
startPoint: [
{ required: true, message: '起飞点不能为空', trigger: 'blur' },
],
endPoint: [
{ required: true, message: '降落点不能为空', trigger: 'blur' },
]
},
scenicOptions: [],
areas: [],
scenics: [],
}
},
created() {
this.getScenics();
},
methods: {
//
getScenics(){
//
allScenic().then((res) => {
if (res) {
this.scenicOptions = (res || []).map((scenic) => ({
id: scenic.id,
name: scenic.name,
}));
} else {
this.scenicOptions = [];
}
});
}, //
commonFormatter(row, column) {
return row[column.property] || '暂无';
},
//
changeArea(value){
this.form.scenicId = '';
allScenic({areaId: value}).then(res=>{
this.scenics = res || [];
})
},
//
getAreas(){
allAreas().then(res => {
this.areas = res;
})
},
//
[CRUD.HOOK.afterToCU](crud, form) {
this.getAreas()
if(form.scenicId&&form.areaId){
allScenic({areaId: form.areaId}).then(res=>{
this.scenics = res || [];
})
}
},
//
[CRUD.HOOK.beforeToEdit](crud, form) {
if(form.scenicId) form.scenicId = Number(form.scenicId);
},
[CRUD.HOOK.beforeRefresh](crud, form) {
crud.query.current = crud.page.page;
}
}
}
</script>
<style scoped>
::v-deep .el-select{
width: 100%;
}
</style>

View File

@ -1,143 +0,0 @@
<template>
<div class="app-container">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span style="color: #027db4;">新增路线</span>
</div>
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px" class="detail-form">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="路线名称" prop="routeName">
<el-input v-model="form.routeName" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="景区名称" prop="scenicArea">
<el-select v-model="form.scenicArea" placeholder="请选择景区">
<el-option label="白云山" value="白云山" />
<el-option label="丹霞山" value="丹霞山" />
<el-option label="西樵山" value="西樵山" />
<el-option label="罗浮山" value="罗浮山" />
<el-option label="鼎湖山" value="鼎湖山" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="起飞点" prop="takeoffPoint">
<el-input v-model="form.takeoffPoint" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="降落点" prop="landingPoint">
<el-input v-model="form.landingPoint" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="16">
<el-form-item label="路线描述" prop="routeDesc">
<el-input type="textarea" v-model="form.routeDesc" :rows="4" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<div class="btn-container">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSubmit">保存</el-button>
</div>
</div>
</template>
<script>
import { ElMessage } from 'element-ui'
import routeApi from '@/api/system/route'
export default {
name: 'AddRoute',
data() {
return {
form: {
routeName: '',
scenicArea: '',
takeoffPoint: '',
landingPoint: '',
routeDesc: '',
routeType: 'normal'
},
rules: {
routeName: [
{ required: true, message: '请输入路线名称', trigger: 'blur' }
],
scenicArea: [
{ required: true, message: '请选择景区', trigger: 'change' }
],
takeoffPoint: [
{ required: true, message: '请输入起飞点', trigger: 'blur' }
],
landingPoint: [
{ required: true, message: '请输入降落点', trigger: 'blur' }
]
}
}
},
methods: {
handleCancel() {
this.$router.go(-1)
},
handleSubmit() {
this.$refs.formRef.validate(valid => {
if (valid) {
this.submitForm()
} else {
return false
}
})
},
async submitForm() {
try {
await routeApi.createRoute(this.form)
ElMessage.success('新增成功')
this.$router.push({ path: '/route/manageroute' })
} catch (error) {
ElMessage.error('新增失败')
}
}
}
}
</script>
<style lang="scss" scoped>
.app-container {
padding: 20px;
}
.detail-form {
.el-form-item {
margin-bottom: 20px;
}
::v-deep .el-input {
width: 240px;
}
::v-deep .el-select {
width: 240px;
}
::v-deep .el-input.is-disabled .el-input__inner {
background-color: white;
color: #686868;
}
::v-deep .el-textarea.is-disabled .el-textarea__inner {
background-color: white;
color: #686868;
}
}
.btn-container {
margin-top: 20px;
text-align: right;
padding-right: 40px;
}
</style>

View File

@ -1,159 +0,0 @@
<template>
<div class="app-container">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span style="color: #027db4;">修改路线</span>
</div>
<el-form :model="form" :rules="rules" ref="formRef" label-width="100px" class="detail-form">
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="路线名称" prop="name">
<el-input v-model="form.name" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="景区ID" prop="scenicId">
<el-input v-model="form.scenicId" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="起点" prop="startPoint">
<el-input v-model="form.startPoint" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="终点" prop="endPoint">
<el-input v-model="form.endPoint" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="16">
<el-form-item label="路线描述" prop="link">
<el-input type="textarea" v-model="form.link" :rows="4" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-card>
<div class="btn-container">
<el-button @click="handleCancel">取消</el-button>
<el-button type="primary" @click="handleSubmit">修改</el-button>
</div>
</div>
</template>
<script>
import { ElMessage } from 'element-ui'
import routeApi from '@/api/system/route'
export default {
name: 'EditRoute',
data() {
return {
form: {
id: null,
name: '',
scenicId: null,
startPoint: '',
endPoint: '',
link: ''
},
rules: {
name: [
{ required: true, message: '请输入路线名称', trigger: 'blur' }
],
scenicId: [
{ required: true, message: '请输入景区ID', trigger: 'blur' }
],
startPoint: [
{ required: true, message: '请输入起点', trigger: 'blur' }
],
endPoint: [
{ required: true, message: '请输入终点', trigger: 'blur' }
]
}
}
},
created() {
this.getRouteDetail()
},
methods: {
async getRouteDetail() {
const id = this.$route.query.id
if (!id) {
ElMessage.error('缺少路线ID请从列表页进入修改')
this.$router.go(-1)
return
}
try {
const res = await routeApi.getRouteDetail(id)
this.form = {
...this.form,
...res.data
}
} catch (error) {
ElMessage.error('获取路线详情失败,请重试')
this.$router.go(-1)
}
},
handleCancel() {
this.$router.go(-1)
},
handleSubmit() {
this.$refs.formRef.validate(valid => {
if (valid) {
this.submitForm()
} else {
return false
}
})
},
async submitForm() {
try {
await routeApi.updateRoute(this.form)
ElMessage.success('修改成功')
this.$router.push({ path: '/route/manageroute' })
} catch (error) {
ElMessage.error('修改失败,请重试')
}
}
}
}
</script>
<style lang="scss" scoped>
.app-container {
padding: 20px;
}
.detail-form {
.el-form-item {
margin-bottom: 20px;
}
::v-deep .el-input {
width: 240px;
}
::v-deep .el-select {
width: 240px;
}
::v-deep .el-input.is-disabled .el-input__inner {
background-color: white;
color: #686868;
}
::v-deep .el-textarea.is-disabled .el-textarea__inner {
background-color: white;
color: #686868;
}
}
.btn-container {
margin-top: 20px;
text-align: right;
padding-right: 40px;
}
</style>

View File

@ -1,161 +0,0 @@
<template>
<div class="app-container">
<!-- 搜索栏 -->
<el-card class="box-card">
<div class="filter-container">
<el-input
v-model="query.name"
placeholder="请输入路线名称"
class="filter-item"
style="width: 200px;"
clearable
/>
<el-button type="primary" class="filter-item" @click="handleSearch">
<i class="fa fa-search mr-1"></i>查询
</el-button>
<el-button type="success" class="filter-item" @click="handleAdd">
<i class="fa fa-plus mr-1"></i>新增路线
</el-button>
</div>
</el-card>
<!-- 表格 -->
<el-table
ref="table"
:data="tableData"
style="width: 100%"
@selection-change="handleSelectionChange"
>
<el-table-column prop="scenicId" label="景区ID" align="left" />
<el-table-column prop="name" label="路线名称" align="left" />
<el-table-column prop="createTime" label="创建时间" align="left" />
<el-table-column label="操作" width="120" align="center" fixed="right">
<template slot-scope="scope">
<el-button type="text" size="small" @click="handleEdit(scope.row)">修改</el-button>
<el-button type="text" size="small" class="text-danger" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div class="pagination-container">
<el-pagination
:current-page.sync="page.current"
:page-sizes="[10, 20, 50, 100]"
:page-size="page.size"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
</div>
</div>
</template>
<script>
import { ElMessage, ElMessageBox } from 'element-ui'
import routeApi from '@/api/system/route'
export default {
name: 'RouteManager',
data() {
return {
tableData: [],
selection: [],
query: {
name: ''
},
page: {
current: 1,
size: 10,
total: 0
}
}
},
mounted() {
this.fetchData()
},
methods: {
async fetchData() {
try {
const params = {
...this.query,
pageNum: this.page.current,
pageSize: this.page.size
}
const res = await routeApi.getAllRoutes(params)
this.tableData = res.data
this.page.total = res.totalElements
} catch (error) {
ElMessage.error('获取路线列表失败,请重试')
}
},
handleSearch() {
this.page.current = 1
this.fetchData()
},
handleAdd() {
this.$router.push({ path: '/route/manageroute/add-route' })
},
handleEdit(row) {
this.$router.push({
path: '/route/manageroute/edit-route',
query: { id: row.id }
})
},
async handleDelete(row) {
this.$confirm(
`确定要删除路线 "${row.name}" 吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(async () => {
try {
await routeApi.deleteRoute(row.id)
ElMessage.success('删除成功')
this.fetchData()
} catch (error) {
ElMessage.error('删除失败,请重试')
}
}).catch(() => {})
},
handleSelectionChange(val) {
this.selection = val
},
handleSizeChange(val) {
this.page.size = val
this.fetchData()
},
handleCurrentChange(val) {
this.page.current = val
this.fetchData()
}
}
}
</script>
<style lang="scss" scoped>
.app-container {
padding: 20px;
}
.filter-container {
display: flex;
align-items: center;
margin-bottom: 20px;
gap: 10px;
.filter-item {
margin-right: 10px;
}
}
.el-table {
margin-top: 20px;
::v-deep .el-table__body-wrapper {
overflow-x: auto;
}
}
</style>