飞行器管理,飞行器维保记录,飞行器保险记录对接接口;
This commit is contained in:
parent
b37d26ad62
commit
ee698bcf45
@ -1,42 +1,90 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
// 分页查询飞行器设备
|
||||
export function get(params) {
|
||||
return request({
|
||||
url: 'api/aircraft',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(ids) {
|
||||
return request({
|
||||
url: 'api/aircraft',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/aircraft',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function get(id) {
|
||||
return request({
|
||||
url: 'api/aircraft/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getAll(params) {
|
||||
return request({
|
||||
url: 'api/aircraft',
|
||||
url: 'aerocraftAdminApi/aircraft/device/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export default { add, edit, del, get, getAll }
|
||||
// 删除飞行器设备
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: `aerocraftAdminApi/aircraft/device/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增飞行器设备
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'aerocraftAdminApi/aircraft/device',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 编辑飞行器设备
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'aerocraftAdminApi/aircraft/device',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 分页查询飞行器维保记录
|
||||
export function getMaintenanceRecords(params) {
|
||||
return request({
|
||||
url: 'aerocraftAdminApi/aircraft/maintenance/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 分页查询飞行器保险
|
||||
export function getInsuranceRecords(params) {
|
||||
return request({
|
||||
url: 'aerocraftAdminApi/aircraft/insurance/page',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
// 新增飞行器保险
|
||||
export function addInsurance(data) {
|
||||
return request({
|
||||
url: 'aerocraftAdminApi/aircraft/insurance',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
// 获取飞行器保险详情
|
||||
export function getInsuranceDetail(id) {
|
||||
return request({
|
||||
url: `aerocraftAdminApi/aircraft/insurance/${id}`,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除飞行器保险
|
||||
export function deleteInsurance(id) {
|
||||
return request({
|
||||
url: `aerocraftAdminApi/aircraft/insurance/${id}`,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 编辑飞行器保险
|
||||
export function editInsurance(data) {
|
||||
return request({
|
||||
url: 'aerocraftAdminApi/aircraft/insurance',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export default { get, del, add, edit, getMaintenanceRecords, getInsuranceRecords, addInsurance, getInsuranceDetail, deleteInsurance, editInsurance }
|
||||
|
35
src/views/aircraft/aircraftDetail/components/ApiLinks.vue
Normal file
35
src/views/aircraft/aircraftDetail/components/ApiLinks.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div class="api-links">
|
||||
<a href="javascript:void(0)" class="api-link" @click="handleClick('data')">飞行器数据记录</a>
|
||||
<a href="javascript:void(0)" class="api-link" @click="handleClick('fault')">飞行器故障记录</a>
|
||||
<a href="javascript:void(0)" class="api-link" @click="handleClick('video')">飞行器视频记录</a>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ApiLinks',
|
||||
methods: {
|
||||
handleClick(type) {
|
||||
this.$emit('click', type)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.api-links {
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 30px;
|
||||
.api-link {
|
||||
color: #027db4;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
138
src/views/aircraft/aircraftDetail/components/BasicInfo.vue
Normal file
138
src/views/aircraft/aircraftDetail/components/BasicInfo.vue
Normal file
@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<el-card class="box-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="color: #027db4;">飞行器基本信息</span>
|
||||
</div>
|
||||
<el-form :model="form" label-width="100px" class="detail-form">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="名称">
|
||||
<el-input v-model="form.name" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="型号">
|
||||
<el-input v-model="form.model" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="类型">
|
||||
<el-input v-model="form.type" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="区域">
|
||||
<el-input v-model="form.region" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="景区">
|
||||
<el-input v-model="form.scenicArea" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="负责人">
|
||||
<el-input v-model="form.manager" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="form.remarks" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="无人机图片">
|
||||
<div class="image-preview">
|
||||
<div v-for="(url, index) in form.imageUrls" :key="index" class="image-item" @click="handlePreview(url)">
|
||||
<img :src="url" class="preview-image">
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
|
||||
<!-- 图片预览 -->
|
||||
<el-dialog :visible.sync="previewVisible" append-to-body>
|
||||
<img :src="previewUrl" alt="Preview" style="width: 100%">
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BasicInfo',
|
||||
props: {
|
||||
form: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
previewVisible: false,
|
||||
previewUrl: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlePreview(url) {
|
||||
this.previewUrl = url
|
||||
this.previewVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.detail-form {
|
||||
.el-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
::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;
|
||||
}
|
||||
}
|
||||
.image-preview {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
.image-item {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
&:hover {
|
||||
border-color: #409EFF;
|
||||
}
|
||||
.preview-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
.box-card {
|
||||
margin-bottom: 20px;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
background: none;
|
||||
.clearfix {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
440
src/views/aircraft/aircraftDetail/components/InsuranceRecord.vue
Normal file
440
src/views/aircraft/aircraftDetail/components/InsuranceRecord.vue
Normal file
@ -0,0 +1,440 @@
|
||||
<template>
|
||||
<el-card class="box-card" style="margin-top: 20px">
|
||||
<div slot="header">
|
||||
<span style="color: #027db4">飞行器保险记录</span>
|
||||
<el-button
|
||||
style="
|
||||
float: right;
|
||||
padding: 5px;
|
||||
background-color: #02a7f0;
|
||||
color: white;
|
||||
"
|
||||
type="text"
|
||||
icon="el-icon-plus"
|
||||
@click="handleAdd"
|
||||
>新增保险
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table :data="data" style="width: 100%">
|
||||
<el-table-column prop="name" label="保险名称" />
|
||||
<el-table-column prop="insuranceType" label="保险类型">
|
||||
<template slot-scope="scope">
|
||||
{{ getInsuranceTypeName(scope.row.insuranceType) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deadlineTime" label="截止日期" width="180">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.deadlineTime ? scope.row.deadlineTime.split('T')[0] : '' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="200" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click="handleView(scope.row)"
|
||||
>查看详情</el-button
|
||||
>
|
||||
<el-button type="text" size="small" @click="handleEdit(scope.row)"
|
||||
>编辑</el-button
|
||||
>
|
||||
<el-button type="text" size="small" @click="handleDelete(scope.row)"
|
||||
>删除</el-button
|
||||
>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
:current-page.sync="page.page"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="page.size"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="page.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 新增/编辑保险表单 -->
|
||||
<el-dialog
|
||||
:title="dialogTitle"
|
||||
:visible.sync="dialogVisible"
|
||||
width="500px"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
@close="handleDialogClose"
|
||||
>
|
||||
<el-form
|
||||
ref="insuranceForm"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
style="margin-right: 30px"
|
||||
:disabled="isView"
|
||||
>
|
||||
<el-form-item label="保险名称" prop="name">
|
||||
<el-input v-model="form.name" placeholder="请输入保险名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="保险类型" prop="insuranceType">
|
||||
<el-select
|
||||
v-model="form.insuranceType"
|
||||
placeholder="请选择保险类型"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in insuranceTypes"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="截止日期" prop="deadlineTime">
|
||||
<el-date-picker
|
||||
v-model="form.deadlineTime"
|
||||
type="date"
|
||||
placeholder="选择日期"
|
||||
style="width: 100%"
|
||||
value-format="yyyy-MM-dd"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="保险附件" prop="files">
|
||||
<el-upload
|
||||
ref="uploadRef"
|
||||
action="#"
|
||||
:file-list="form.files"
|
||||
:auto-upload="false"
|
||||
:on-change="handleFileChange"
|
||||
:on-remove="handleFileRemove"
|
||||
list-type="text"
|
||||
multiple
|
||||
:disabled="isView"
|
||||
>
|
||||
<el-button size="small" type="primary">
|
||||
<i class="el-icon-plus"></i> 上传
|
||||
</el-button>
|
||||
</el-upload>
|
||||
<div slot="tip" class="el-upload__tip">支持上传多种格式文件(JPEG、PDF、DOCX等),单个文件不超过10MB</div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">{{ isView ? '关闭' : '取 消' }}</el-button>
|
||||
<el-button v-if="!isView" type="primary" @click="submitForm">确 定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { upload } from '@/utils/upload'
|
||||
import { addInsurance, getInsuranceDetail, deleteInsurance, editInsurance } from '@/api/aircraft'
|
||||
|
||||
export default {
|
||||
name: "InsuranceRecord",
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
page: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
aircraftId: {
|
||||
type: [String, Number],
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'fileUploadApi'
|
||||
])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
dialogVisible: false,
|
||||
dialogTitle: "新增保险",
|
||||
uploadDisabled: false,
|
||||
isView: false, // 是否为查看模式
|
||||
form: {
|
||||
id: null,
|
||||
name: "",
|
||||
insuranceType: "",
|
||||
deadlineTime: "",
|
||||
files: [],
|
||||
attachments: [],
|
||||
aircraftId: null
|
||||
},
|
||||
insuranceTypes: [
|
||||
{ value: 0, label: "三方险" },
|
||||
{ value: 1, label: "设备险" },
|
||||
{ value: 2, label: "运营险" },
|
||||
],
|
||||
rules: {
|
||||
name: [{ required: true, message: "请输入保险名称", trigger: "blur" }],
|
||||
insuranceType: [
|
||||
{ required: true, message: "请选择保险类型", trigger: "change" },
|
||||
],
|
||||
deadlineTime: [
|
||||
{ required: true, message: "请选择截止日期", trigger: "change" },
|
||||
],
|
||||
files: [
|
||||
{ required: true, message: "请上传保险附件", trigger: "change" },
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getInsuranceTypeName(type) {
|
||||
const found = this.insuranceTypes.find(t => t.value === type)
|
||||
return found ? found.label : '未知类型'
|
||||
},
|
||||
handleSizeChange(val) {
|
||||
this.$emit("size-change", val);
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.$emit("current-change", val);
|
||||
},
|
||||
handleAdd() {
|
||||
this.dialogTitle = "新增保险";
|
||||
this.isView = false;
|
||||
this.form = {
|
||||
id: null,
|
||||
name: "",
|
||||
insuranceType: "",
|
||||
deadlineTime: "",
|
||||
files: [],
|
||||
attachments: [],
|
||||
aircraftId: this.aircraftId
|
||||
};
|
||||
this.uploadDisabled = false;
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
async handleView(row) {
|
||||
try {
|
||||
const res = await getInsuranceDetail(row.id);
|
||||
this.dialogTitle = "查看保险详情";
|
||||
this.isView = true;
|
||||
this.form = {
|
||||
name: res.name,
|
||||
insuranceType: res.insuranceType,
|
||||
deadlineTime: res.deadlineTime.split(' ')[0],
|
||||
files: res.insuranceAttachment.map(file => ({
|
||||
name: file.sourceFileName,
|
||||
url: file.fileFullPath
|
||||
})),
|
||||
attachments: res.insuranceAttachment
|
||||
};
|
||||
this.uploadDisabled = true;
|
||||
this.dialogVisible = true;
|
||||
} catch (error) {
|
||||
this.$message.error('获取保险详情失败');
|
||||
}
|
||||
},
|
||||
async handleEdit(row) {
|
||||
try {
|
||||
const res = await getInsuranceDetail(row.id);
|
||||
this.dialogTitle = "编辑保险";
|
||||
this.isView = false;
|
||||
this.form = {
|
||||
id: row.id,
|
||||
name: res.name,
|
||||
insuranceType: res.insuranceType,
|
||||
deadlineTime: res.deadlineTime.split(' ')[0],
|
||||
files: res.insuranceAttachment.map(file => ({
|
||||
name: file.sourceFileName,
|
||||
url: file.fileFullPath
|
||||
})),
|
||||
attachments: res.insuranceAttachment,
|
||||
aircraftId: this.aircraftId
|
||||
};
|
||||
this.uploadDisabled = false;
|
||||
this.dialogVisible = true;
|
||||
} catch (error) {
|
||||
this.$message.error('获取保险详情失败');
|
||||
}
|
||||
},
|
||||
handleDelete(row) {
|
||||
this.$confirm('此操作将永久删除该保险记录, 是否继续?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(async () => {
|
||||
try {
|
||||
await deleteInsurance(row.id);
|
||||
this.$message({
|
||||
type: 'success',
|
||||
message: '删除成功!'
|
||||
});
|
||||
this.$emit('refresh');
|
||||
} catch (error) {
|
||||
this.$message.error(error.message || '删除失败');
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: '已取消删除'
|
||||
});
|
||||
});
|
||||
},
|
||||
// 处理文件变更
|
||||
async handleFileChange(file, fileList) {
|
||||
const isLt10M = file.raw.size / 1024 / 1024 < 10;
|
||||
if (!isLt10M) {
|
||||
this.$message.error('文件大小不能超过 10MB');
|
||||
fileList.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await upload(this.fileUploadApi, file.raw);
|
||||
if (res.status === 200) {
|
||||
const data = res.data;
|
||||
// 更新文件列表显示
|
||||
this.form.files = fileList;
|
||||
|
||||
// 组装附件数据
|
||||
if (!this.form.attachments) {
|
||||
this.form.attachments = [];
|
||||
}
|
||||
this.form.attachments.push({
|
||||
fileFullPath: data.fileFullPath || `/file/${data.newFileName}`,
|
||||
fileSize: file.raw.size,
|
||||
fileType: file.raw.name.split('.').pop(),
|
||||
id: 0,
|
||||
newFileName: data.newFileName,
|
||||
sourceFileName: file.raw.name
|
||||
});
|
||||
|
||||
this.$message.success(`${file.name} 上传成功`);
|
||||
} else {
|
||||
fileList.pop();
|
||||
this.$message.error('文件上传失败');
|
||||
}
|
||||
} catch (error) {
|
||||
fileList.pop();
|
||||
this.$message.error('文件上传失败');
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 处理文件移除
|
||||
handleFileRemove(file) {
|
||||
const index = this.form.attachments.findIndex(
|
||||
item => item.sourceFileName === file.name
|
||||
);
|
||||
if (index > -1) {
|
||||
this.form.attachments.splice(index, 1);
|
||||
}
|
||||
},
|
||||
handleDialogClose() {
|
||||
this.$refs.insuranceForm.resetFields();
|
||||
this.$refs.uploadRef.clearFiles();
|
||||
this.form.attachments = [];
|
||||
this.uploadDisabled = false;
|
||||
this.isView = false;
|
||||
},
|
||||
submitForm() {
|
||||
this.$refs.insuranceForm.validate(async (valid) => {
|
||||
if (valid) {
|
||||
try {
|
||||
const baseData = {
|
||||
aircraftId: this.aircraftId,
|
||||
name: this.form.name,
|
||||
insuranceType: this.form.insuranceType,
|
||||
deadlineTime: this.form.deadlineTime,
|
||||
insuranceAttachment: this.form.attachments
|
||||
};
|
||||
|
||||
if (this.form.id) {
|
||||
// 编辑时需要传id
|
||||
await editInsurance({
|
||||
...baseData,
|
||||
id: this.form.id
|
||||
});
|
||||
this.$message.success('保险编辑成功');
|
||||
} else {
|
||||
// 新增时不传id
|
||||
await addInsurance(baseData);
|
||||
this.$message.success('保险添加成功');
|
||||
}
|
||||
this.$emit('refresh');
|
||||
this.dialogVisible = false;
|
||||
} catch (error) {
|
||||
this.$message.error(error.message || '保险添加失败');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box-card {
|
||||
margin-bottom: 20px;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
background: none;
|
||||
.clearfix {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.pagination-container {
|
||||
text-align: right;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.el-upload {
|
||||
::v-deep .el-button {
|
||||
padding: 8px 16px;
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-upload-list {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
::v-deep .el-upload-list__item {
|
||||
transition: all 0.3s;
|
||||
padding: 8px 5px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 5px;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
|
||||
.el-upload-list__item-name {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.el-icon-upload-success {
|
||||
color: #67C23A;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.el-upload__tip {
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
margin-top: 5px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e4e4e4;
|
||||
}
|
||||
</style>
|
@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<el-card class="box-card" style="margin-top: 20px;">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="color: #027db4;">飞行器维保记录</span>
|
||||
</div>
|
||||
<el-table :data="data" style="width: 100%">
|
||||
<el-table-column prop="manager" label="负责人" />
|
||||
<el-table-column prop="type" label="维保类型" />
|
||||
<el-table-column prop="remarks" label="备注" />
|
||||
<el-table-column prop="time" label="维保时间" width="180" />
|
||||
</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"
|
||||
:total="page.total"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'MaintenanceRecord',
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
page: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSizeChange(val) {
|
||||
this.$emit('size-change', val)
|
||||
},
|
||||
handleCurrentChange(val) {
|
||||
this.$emit('current-change', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.box-card {
|
||||
margin-bottom: 20px;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
background: none;
|
||||
.clearfix {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.pagination-container {
|
||||
text-align: right;
|
||||
margin-top: 20px;
|
||||
}
|
||||
</style>
|
@ -1,143 +1,49 @@
|
||||
<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" label-width="100px" class="detail-form">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="名称">
|
||||
<el-input v-model="form.name" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="型号">
|
||||
<el-input v-model="form.model" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="类型">
|
||||
<el-input v-model="form.type" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="区域">
|
||||
<el-input v-model="form.region" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="景区">
|
||||
<el-input v-model="form.scenicArea" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="负责人">
|
||||
<el-input v-model="form.manager" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="备注">
|
||||
<el-input type="textarea" v-model="form.remarks" disabled />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="无人机图片">
|
||||
<div class="image-preview">
|
||||
<div v-for="(url, index) in form.imageUrls" :key="index" class="image-item" @click="handlePreview(url)">
|
||||
<img :src="url" class="preview-image">
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
<basic-info :form="form" />
|
||||
|
||||
<!-- 维护记录表 -->
|
||||
<el-card class="box-card" style="margin-top: 20px;">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="color: #027db4;">飞行器维护记录</span>
|
||||
</div>
|
||||
<el-table :data="maintenanceData" style="width: 100%">
|
||||
<el-table-column prop="manager" label="负责人" />
|
||||
<el-table-column prop="type" label="维护类型" />
|
||||
<el-table-column prop="remarks" label="备注" />
|
||||
<el-table-column prop="time" label="维护时间" width="180" />
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
:current-page.sync="maintenancePage.page"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="maintenancePage.size"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="maintenancePage.total"
|
||||
@size-change="handleMaintenanceSizeChange"
|
||||
@current-change="handleMaintenanceCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 维护记录 -->
|
||||
<maintenance-record
|
||||
:data="maintenanceData"
|
||||
:page="maintenancePage"
|
||||
@size-change="handleMaintenanceSizeChange"
|
||||
@current-change="handleMaintenanceCurrentChange"
|
||||
/>
|
||||
|
||||
<!-- 保险记录表 -->
|
||||
<el-card class="box-card" style="margin-top: 20px;">
|
||||
<div slot="header">
|
||||
<span style="color: #027db4;">飞行器保险记录</span>
|
||||
<el-button
|
||||
style="float: right; padding: 5px; background-color: #02a7f0; color: white;"
|
||||
type="text"
|
||||
icon="el-icon-plus"
|
||||
@click="handleAddInsurance"
|
||||
>新增保险</el-button>
|
||||
</div>
|
||||
<el-table :data="insuranceData" style="width: 100%">
|
||||
<el-table-column prop="name" label="保险名称" />
|
||||
<el-table-column prop="type" label="保险类型" />
|
||||
<el-table-column prop="expireTime" label="截至时间" width="180" />
|
||||
<el-table-column label="操作" width="200" align="center">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click="handleInsuranceView(scope.row)">查看详情</el-button>
|
||||
<el-button type="text" size="small" @click="handleInsuranceEdit(scope.row)">编辑</el-button>
|
||||
<el-button type="text" size="small" @click="handleInsuranceDelete(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
:current-page.sync="insurancePage.page"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="insurancePage.size"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="insurancePage.total"
|
||||
@size-change="handleInsuranceSizeChange"
|
||||
@current-change="handleInsuranceCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
<!-- 保险记录 -->
|
||||
<insurance-record
|
||||
:data="insuranceData"
|
||||
:page="insurancePage"
|
||||
:aircraft-id="Number($route.query.id)"
|
||||
@size-change="handleInsuranceSizeChange"
|
||||
@current-change="handleInsuranceCurrentChange"
|
||||
@view="handleInsuranceView"
|
||||
@edit="handleInsuranceEdit"
|
||||
@delete="handleInsuranceDelete"
|
||||
@refresh="loadInsuranceRecords"
|
||||
/>
|
||||
|
||||
<!-- API模块入口 -->
|
||||
<div class="api-links">
|
||||
<a href="javascript:void(0)" class="api-link" @click="handleApiClick('data')">飞行器数据记录</a>
|
||||
<a href="javascript:void(0)" class="api-link" @click="handleApiClick('fault')">飞行器故障记录</a>
|
||||
<a href="javascript:void(0)" class="api-link" @click="handleApiClick('video')">飞行器视频记录</a>
|
||||
</div>
|
||||
|
||||
<!-- 图片预览 -->
|
||||
<el-dialog :visible.sync="previewVisible" append-to-body>
|
||||
<img :src="previewUrl" alt="Preview" style="width: 100%">
|
||||
</el-dialog>
|
||||
<api-links @click="handleApiClick" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { getMaintenanceRecords, getInsuranceRecords } from '@/api/aircraft'
|
||||
import BasicInfo from './components/BasicInfo'
|
||||
import MaintenanceRecord from './components/MaintenanceRecord'
|
||||
import InsuranceRecord from './components/InsuranceRecord'
|
||||
import ApiLinks from './components/ApiLinks'
|
||||
export default {
|
||||
name: 'aircraftDetail',
|
||||
components: {
|
||||
BasicInfo,
|
||||
MaintenanceRecord,
|
||||
InsuranceRecord,
|
||||
ApiLinks
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
@ -148,82 +54,116 @@ export default {
|
||||
scenicArea: '白云山',
|
||||
manager: '小明',
|
||||
remarks: '设备状态良好',
|
||||
imageUrls: Array(6).fill('https://axure-file.lanhuapp.com/md5__f344f816278c2a3f5164e4571c580ad9.png'),
|
||||
imageUrls: Array(6).fill('https://axure-file.lanhuapp.com/md5__f344f816278c2a3f5164e4571c580ad9.png')
|
||||
},
|
||||
maintenanceData: Array(10).fill({
|
||||
manager: '小明',
|
||||
type: '维修',
|
||||
remarks: '电池损坏',
|
||||
time: '2016-09-21 08:50:08'
|
||||
}),
|
||||
insuranceData: Array(2).fill({
|
||||
name: '安全保险',
|
||||
type: '三方险',
|
||||
expireTime: '2016-09-21 08:50:08'
|
||||
}),
|
||||
maintenanceData: [],
|
||||
insuranceData: [],
|
||||
maintenancePage: {
|
||||
page: 1,
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 20
|
||||
total: 0
|
||||
},
|
||||
insurancePage: {
|
||||
page: 1,
|
||||
current: 1,
|
||||
size: 10,
|
||||
total: 2
|
||||
},
|
||||
previewVisible: false,
|
||||
previewUrl: ''
|
||||
total: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'fileUploadApi',
|
||||
'baseApi'
|
||||
])
|
||||
},
|
||||
created() {
|
||||
// 获取详情数据
|
||||
const id = this.$route.query.id
|
||||
if (id) {
|
||||
this.getDetail(id)
|
||||
}
|
||||
this.loadMaintenanceRecords()
|
||||
this.loadInsuranceRecords()
|
||||
},
|
||||
methods: {
|
||||
getDetail(id) {
|
||||
// 调用接口获取详情
|
||||
console.log('获取详情:', id)
|
||||
// this.loadInsuranceRecords()
|
||||
},
|
||||
handlePreview(url) {
|
||||
this.previewUrl = url
|
||||
this.previewVisible = true
|
||||
async loadInsuranceRecords() {
|
||||
try {
|
||||
const params = {
|
||||
aircraftId: this.$route.query.id || 0,// 0只是暂时测试用
|
||||
current: this.insurancePage.current,
|
||||
size: this.insurancePage.size
|
||||
}
|
||||
const response = await getInsuranceRecords(params)
|
||||
console.log('保险记录:', response)
|
||||
this.insuranceData = response.records
|
||||
this.insurancePage.total = response.total
|
||||
} catch (error) {
|
||||
console.error('Failed to load insurance records:', error)
|
||||
this.$message.error('获取保险记录失败')
|
||||
}
|
||||
},
|
||||
async loadMaintenanceRecords() {
|
||||
try {
|
||||
const params = {
|
||||
aircraftId: this.$route.query.id,
|
||||
current: this.maintenancePage.current,
|
||||
size: this.maintenancePage.size
|
||||
}
|
||||
const response = await getMaintenanceRecords(params)
|
||||
this.maintenanceData = response.records
|
||||
this.maintenancePage.total = response.total
|
||||
} catch (error) {
|
||||
console.error('Failed to load maintenance records:', error)
|
||||
this.$message.error('获取维护记录失败')
|
||||
}
|
||||
},
|
||||
handleMaintenanceSizeChange(val) {
|
||||
this.maintenancePage.size = val
|
||||
// 重新获取维护记录数据
|
||||
this.loadMaintenanceRecords()
|
||||
},
|
||||
handleMaintenanceCurrentChange(val) {
|
||||
this.maintenancePage.page = val
|
||||
// 重新获取维护记录数据
|
||||
this.maintenancePage.current = val
|
||||
this.loadMaintenanceRecords()
|
||||
},
|
||||
handleInsuranceSizeChange(val) {
|
||||
this.insurancePage.size = val
|
||||
// 重新获取保险记录数据
|
||||
this.loadInsuranceRecords()
|
||||
},
|
||||
handleInsuranceCurrentChange(val) {
|
||||
this.insurancePage.page = val
|
||||
// 重新获取保险记录数据
|
||||
},
|
||||
handleAddInsurance() {
|
||||
// 跳转到新增保险页面
|
||||
this.insurancePage.current = val
|
||||
this.loadInsuranceRecords()
|
||||
},
|
||||
handleInsuranceView(row) {
|
||||
// 查看保险详情
|
||||
console.log('查看保险详情:', row)
|
||||
},
|
||||
handleInsuranceEdit(row) {
|
||||
// 编辑保险信息
|
||||
console.log('编辑保险信息:', row)
|
||||
this.handleAdd()
|
||||
this.dialogTitle = '编辑保险'
|
||||
this.form = {
|
||||
name: row.name,
|
||||
insuranceType: row.insuranceType,
|
||||
deadlineTime: row.deadlineTime ? row.deadlineTime.split('T')[0] : '',
|
||||
files: row.insuranceAttachment ? row.insuranceAttachment.map(attachment => ({
|
||||
name: attachment.sourceFileName,
|
||||
url: attachment.fileFullPath
|
||||
})) : []
|
||||
}
|
||||
},
|
||||
handleInsuranceDelete(row) {
|
||||
// 删除保险记录
|
||||
console.log('删除保险记录:', row)
|
||||
},
|
||||
handleInsuranceSubmit(form) {
|
||||
console.log('保存保险记录:', {
|
||||
...form,
|
||||
aircraftId: this.$route.query.id
|
||||
})
|
||||
this.$message.success('保存成功')
|
||||
this.loadInsuranceRecords()
|
||||
},
|
||||
handleApiClick(type) {
|
||||
// 跳转到对应的API模块
|
||||
console.log('跳转到API模块:', type)
|
||||
}
|
||||
}
|
||||
@ -235,67 +175,4 @@ export default {
|
||||
padding: 0;
|
||||
margin-bottom: 33px;
|
||||
}
|
||||
.detail-form {
|
||||
.el-form-item {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
::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;
|
||||
}
|
||||
}
|
||||
.image-preview {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
.image-item {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
cursor: pointer;
|
||||
border: 1px solid #dcdfe6;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
&:hover {
|
||||
border-color: #409EFF;
|
||||
}
|
||||
.preview-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
.box-card {
|
||||
margin-bottom: 20px;
|
||||
box-shadow: none;
|
||||
border: none;
|
||||
background: none;
|
||||
.clearfix {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
.pagination-container {
|
||||
text-align: right;
|
||||
margin-top: 20px;
|
||||
}
|
||||
.api-links {
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 30px;
|
||||
.api-link {
|
||||
color: #027db4;
|
||||
text-decoration: none;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -4,14 +4,20 @@
|
||||
<div class="head-container">
|
||||
<div class="filter-container">
|
||||
<el-input v-model="query.name" clearable size="small" placeholder="请输入飞行器名称" style="width: 200px;" class="filter-item" />
|
||||
<el-input v-model="query.manager" clearable size="small" placeholder="请输入负责人" style="width: 200px;" class="filter-item" />
|
||||
<el-select v-model="query.scenicArea" placeholder="景区" clearable size="small" style="width: 200px" class="filter-item">
|
||||
<el-option label="北京" value="北京" />
|
||||
<el-option label="上海" value="上海" />
|
||||
<el-option label="广州" value="广州" />
|
||||
<el-select v-model="query.employeesId" placeholder="请选择负责人" clearable size="small" style="width: 200px" class="filter-item">
|
||||
<el-option v-for="employee in employeeOptions"
|
||||
:key="employee.id"
|
||||
:label="employee.name"
|
||||
:value="employee.id" />
|
||||
</el-select>
|
||||
<el-select v-model="query.areaId" placeholder="请选择区域" clearable size="small" style="width: 200px" class="filter-item">
|
||||
<el-option v-for="area in areaOptions"
|
||||
:key="area.id"
|
||||
:label="area.name"
|
||||
:value="area.id" />
|
||||
</el-select>
|
||||
<el-button class="filter-item" size="small" type="primary" icon="el-icon-search" @click="crud.toQuery">查询</el-button>
|
||||
<el-button class="filter-item" size="small" type="success" icon="el-icon-plus" @click="crud.toAdd">新增飞行器</el-button>
|
||||
<el-button v-permission="permission.add" class="filter-item" size="small" type="success" icon="el-icon-plus" @click="crud.toAdd" v-if="checkPer(permission.add)">新增飞行器</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<!--表单渲染-->
|
||||
@ -23,31 +29,35 @@
|
||||
<el-form-item label="型号" prop="model">
|
||||
<el-input v-model="form.model" style="width: 150px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="类型" prop="type">
|
||||
<el-select v-model="form.type" style="width: 150px;">
|
||||
<el-option label="载人飞行" value="载人飞行" />
|
||||
<el-option label="无人机" value="无人机" />
|
||||
<el-form-item label="类型" prop="useType">
|
||||
<el-select v-model="form.useType" style="width: 150px;">
|
||||
<el-option :value="0" label="载物飞行" />
|
||||
<el-option :value="1" label="载人飞行" />
|
||||
<el-option :value="2" label="其他" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="角色" prop="role">
|
||||
<el-select v-model="form.role" style="width: 150px;">
|
||||
<el-option label="飞行员" value="飞行员" />
|
||||
<el-option label="技术员" value="技术员" />
|
||||
<el-option label="管理员" value="管理员" />
|
||||
<el-form-item label="区域" prop="areaId">
|
||||
<el-select v-model="form.areaId" style="width: 150px;">
|
||||
<el-option v-for="area in areaOptions"
|
||||
:key="area.id"
|
||||
:label="area.name"
|
||||
:value="area.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="区域" prop="region">
|
||||
<el-select v-model="form.region" style="width: 150px;">
|
||||
<el-option label="北京" value="北京" />
|
||||
<el-option label="上海" value="上海" />
|
||||
<el-option label="广州" value="广州" />
|
||||
<el-form-item label="景区" prop="scenicId">
|
||||
<el-select v-model="form.scenicId" style="width: 150px;">
|
||||
<el-option v-for="scenic in scenicOptions"
|
||||
:key="scenic.id"
|
||||
:label="scenic.name"
|
||||
:value="scenic.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="景区" prop="scenicArea">
|
||||
<el-select v-model="form.scenicArea" style="width: 150px;">
|
||||
<el-option label="白云山" value="白云山" />
|
||||
<el-option label="故宫" value="故宫" />
|
||||
<el-option label="长城" value="长城" />
|
||||
<el-form-item label="负责人" prop="employeesId">
|
||||
<el-select v-model="form.employeesId" style="width: 150px;">
|
||||
<el-option v-for="employee in employeeOptions"
|
||||
:key="employee.id"
|
||||
:label="employee.name"
|
||||
:value="employee.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remarks" :label-width="'100px'">
|
||||
@ -59,25 +69,33 @@
|
||||
style="width: 150px;">
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="无人机图片" prop="imageUrls" v-if="form.type === '载人飞行'" style="width: 100%;">
|
||||
<div class="image-list">
|
||||
<el-upload
|
||||
class="avatar-uploader"
|
||||
action="api/upload"
|
||||
:show-file-list="false"
|
||||
:on-success="handleAvatarSuccess"
|
||||
:before-upload="beforeAvatarUpload"
|
||||
style="background-color: #fafafa; display: inline-block; margin-right: 10px;"
|
||||
>
|
||||
<i class="el-icon-plus avatar-uploader-icon"></i>
|
||||
<el-form-item label="设备图片" prop="deviceImages" style="width: 100%;">
|
||||
<div class="upload-container">
|
||||
<el-upload ref="uploadRef" action="#" list-type="picture-card"
|
||||
:show-file-list="false" :on-change="handleChange" :auto-upload="false" accept="image/*"
|
||||
:class="{ 'upload-item': true }">
|
||||
<div style="display: flex;flex-direction: column;align-items: center;justify-content: center;margin-top: -20px;">
|
||||
<i class="el-icon-plus" style="font-size: 30px;" />
|
||||
<span style="margin: 5px 0 -20px;line-height: 20px">上传</span>
|
||||
</div>
|
||||
</el-upload>
|
||||
<div v-for="(url, index) in form.imageUrls" :key="index" class="image-item">
|
||||
<img :src="url" class="avatar">
|
||||
<span class="delete-icon" @click="handleRemoveImage(index)">
|
||||
<i class="el-icon-delete"></i>
|
||||
</span>
|
||||
<div v-for="(image, index) in form.deviceImages" :key="index" class="preview-item">
|
||||
<img :src="image.fileFullPath" class="preview-image" alt="">
|
||||
<span class="preview-actions">
|
||||
<span class="preview-action" @click="handlePictureCardPreview(image.fileFullPath)">
|
||||
<i class="el-icon-zoom-in" />
|
||||
</span>
|
||||
<span class="preview-action" @click="handleRemoveImage(index)">
|
||||
<i class="el-icon-delete" />
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog append-to-body :visible.sync="dialogVisible" top="20vh">
|
||||
<div>
|
||||
<img :src="dialogImageUrl" style="width: 100%" alt="Preview Image">
|
||||
</div>
|
||||
</el-dialog>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
@ -98,10 +116,14 @@
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="飞行器名称" prop="name" />
|
||||
<el-table-column label="型号" prop="model" />
|
||||
<el-table-column label="类型" prop="type" />
|
||||
<el-table-column label="负责人" prop="manager" />
|
||||
<el-table-column label="区域" prop="region" />
|
||||
<el-table-column label="景区" prop="scenicArea" />
|
||||
<el-table-column label="类型" prop="useType">
|
||||
<template slot-scope="scope">
|
||||
{{ scope.row.useType === 0 ? '载物' : scope.row.useType === 1 ? '载人' : '其他' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="负责人" prop="employeeName" />
|
||||
<el-table-column label="区域" prop="areaName" />
|
||||
<el-table-column label="景区" prop="scenicName" />
|
||||
<el-table-column label="创建时间" prop="createTime" width="180" />
|
||||
<el-table-column label="操作" width="150" align="center" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
@ -116,6 +138,8 @@
|
||||
size="mini"
|
||||
type="text"
|
||||
@click="crud.toEdit(scope.row)"
|
||||
v-permission="permission.edit"
|
||||
v-if="checkPer(permission.edit)"
|
||||
>
|
||||
修改
|
||||
</el-button>
|
||||
@ -123,6 +147,8 @@
|
||||
size="mini"
|
||||
type="text"
|
||||
@click="handleDelete(scope.row)"
|
||||
v-permission="permission.del"
|
||||
v-if="checkPer(permission.del)"
|
||||
>
|
||||
删除
|
||||
</el-button>
|
||||
@ -149,90 +175,92 @@
|
||||
import CRUD, { presenter, header, form, crud } from '@crud/crud'
|
||||
import udOperation from '@crud/UD.operation'
|
||||
import crudAircraft from '@/api/aircraft'
|
||||
|
||||
import areaApi from '@/api/system/area'
|
||||
import { upload } from '@/utils/upload'
|
||||
import { mapGetters } from 'vuex'
|
||||
import rrOperation from '@crud/RR.operation'
|
||||
// crud交由presenter持有
|
||||
const defaultForm = {
|
||||
id: null,
|
||||
id: 0,
|
||||
name: null,
|
||||
brand: null,
|
||||
model: null,
|
||||
type: '载人飞行',
|
||||
manager: null,
|
||||
role: '飞行员',
|
||||
region: '北京',
|
||||
scenicArea: '白云山',
|
||||
imageUrls: [],
|
||||
remarks: '',
|
||||
useType: 0,
|
||||
areaId: null,
|
||||
scenicId: null,
|
||||
employeesId: null,
|
||||
deviceImages: [],
|
||||
remark: '',
|
||||
createTime: null
|
||||
}
|
||||
export default {
|
||||
name: 'aircraft',
|
||||
components: { udOperation },
|
||||
cruds() {
|
||||
return CRUD({ title: '飞行器', url: 'api/aircraft', crudMethod: { ...crudAircraft }})
|
||||
return CRUD({
|
||||
title: '飞行器',
|
||||
url: 'aerocraftAdminApi/aircraft/device',
|
||||
crudMethod: {
|
||||
...crudAircraft,
|
||||
getList: crudAircraft.getDevicePage
|
||||
},
|
||||
optShow: {
|
||||
search: true
|
||||
},
|
||||
queryOnPresenterCreated: false, // 禁止初始化时自动查询
|
||||
query: {
|
||||
current: 1,
|
||||
size: 10,
|
||||
employeesId: undefined,
|
||||
areaId: undefined,
|
||||
name: undefined
|
||||
}
|
||||
})
|
||||
},
|
||||
mixins: [presenter(), header(), form(defaultForm), crud()],
|
||||
data() {
|
||||
return {
|
||||
dialogVisible: false,
|
||||
dialogImageUrl: '',
|
||||
uploadDisabled: false,
|
||||
// ini
|
||||
page: {
|
||||
page: 1,
|
||||
size: 10,
|
||||
total: 5
|
||||
},
|
||||
areaOptions: [],
|
||||
scenicOptions: [],
|
||||
employeeOptions: [],
|
||||
// 默认数据
|
||||
query: {
|
||||
name: '',
|
||||
employeesId: undefined,
|
||||
areaId: undefined,
|
||||
current: 1,
|
||||
size: 10
|
||||
},
|
||||
defaultData: [{
|
||||
id: 1,
|
||||
name: '大疆',
|
||||
model: 'T100',
|
||||
type: '载人飞行',
|
||||
manager: '小明',
|
||||
region: '北京',
|
||||
scenicArea: '白云山',
|
||||
createTime: '2016-09-21 08:50:08',
|
||||
imageUrls: ['https://axure-file.lanhuapp.com/md5__f344f816278c2a3f5164e4571c580ad9.png']
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '大疆',
|
||||
model: 'T100',
|
||||
type: '载人飞行',
|
||||
manager: '小明',
|
||||
region: '北京',
|
||||
scenicArea: '白云山',
|
||||
createTime: '2016-09-21 08:50:08',
|
||||
imageUrls: ['https://axure-file.lanhuapp.com/md5__f344f816278c2a3f5164e4571c580ad9.png']
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '大疆',
|
||||
model: 'T100',
|
||||
type: '载人飞行',
|
||||
manager: '小明',
|
||||
region: '北京',
|
||||
scenicArea: '白云山',
|
||||
createTime: '2016-09-21 08:50:08',
|
||||
imageUrls: ['https://axure-file.lanhuapp.com/md5__f344f816278c2a3f5164e4571c580ad9.png']
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '大疆',
|
||||
model: 'T100',
|
||||
type: '载人飞行',
|
||||
manager: '小明',
|
||||
region: '北京',
|
||||
scenicArea: '白云山',
|
||||
createTime: '2016-09-21 08:50:08',
|
||||
imageUrls: ['https://axure-file.lanhuapp.com/md5__f344f816278c2a3f5164e4571c580ad9.png']
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '大疆',
|
||||
model: 'T100',
|
||||
type: '载人飞行',
|
||||
manager: '小明',
|
||||
region: '北京',
|
||||
scenicArea: '白云山',
|
||||
createTime: '2016-09-21 08:50:08',
|
||||
imageUrls: ['https://axure-file.lanhuapp.com/md5__f344f816278c2a3f5164e4571c580ad9.png']
|
||||
name: '无人机01',
|
||||
brand: 'DJI',
|
||||
model: 'Mavic Air 2',
|
||||
useType: 0,
|
||||
employeesId: 1,
|
||||
employeeName: '张三',
|
||||
areaId: 1,
|
||||
areaName: '北京',
|
||||
scenicId: 1,
|
||||
scenicName: '故宫',
|
||||
createTime: '2025-07-17 08:50:08',
|
||||
deviceImages: [{
|
||||
fileFullPath: 'https://example.com/image1.jpg',
|
||||
fileSize: 102400,
|
||||
fileType: 'jpg',
|
||||
id: 1,
|
||||
newFileName: 'drone_20250717.jpg',
|
||||
sourceFileName: 'DJI_0001.jpg'
|
||||
}]
|
||||
}],
|
||||
permission: {
|
||||
add: ['admin', 'aircraft:add'],
|
||||
@ -246,65 +274,173 @@ export default {
|
||||
model: [
|
||||
{ required: true, message: '请输入型号', trigger: 'blur' }
|
||||
],
|
||||
type: [
|
||||
useType: [
|
||||
{ required: true, message: '请选择类型', trigger: 'change' }
|
||||
],
|
||||
manager: [
|
||||
{ required: true, message: '请输入负责人', trigger: 'blur' }
|
||||
],
|
||||
role: [
|
||||
{ required: true, message: '请选择角色', trigger: 'change' }
|
||||
],
|
||||
region: [
|
||||
areaId: [
|
||||
{ required: true, message: '请选择区域', trigger: 'change' }
|
||||
],
|
||||
scenicArea: [
|
||||
scenicId: [
|
||||
{ required: true, message: '请选择景区', trigger: 'change' }
|
||||
],
|
||||
imageUrls: [
|
||||
{ required: true, message: '请上传无人机图片', trigger: 'change', type: 'array' }
|
||||
employeesId: [
|
||||
{ required: true, message: '请选择负责人', trigger: 'change' }
|
||||
],
|
||||
deviceImages: [
|
||||
{ required: true, message: '请上传设备图片', trigger: 'change', type: 'array' }
|
||||
]
|
||||
},
|
||||
query: {
|
||||
name: '',
|
||||
manager: '',
|
||||
scenicArea: '北京'
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'imagesUploadApi',
|
||||
'baseApi'
|
||||
])
|
||||
},
|
||||
created() {
|
||||
// 获取区域列表
|
||||
this.getAreas()
|
||||
// 获取景区列表
|
||||
this.getScenics()
|
||||
// 获取飞行员列表
|
||||
this.getEmployees()
|
||||
},
|
||||
methods: {
|
||||
// 获取区域列表
|
||||
async getAreas() {
|
||||
try {
|
||||
const res = await areaApi.tree()
|
||||
if (res) {
|
||||
this.areaOptions = [
|
||||
{
|
||||
id: 0,
|
||||
name: res.name,
|
||||
sons: res.sons || []
|
||||
},
|
||||
...(res.sons || [])
|
||||
]
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('获取区域列表失败')
|
||||
console.error('获取区域列表失败:', error)
|
||||
this.areaOptions = []
|
||||
}
|
||||
},
|
||||
|
||||
// 获取景区列表
|
||||
async getScenics() {
|
||||
// try {
|
||||
// const test = {
|
||||
// employeesId: this.query.employeesId || 0
|
||||
// }
|
||||
// const res = await crudAircraft.get(test)
|
||||
// if (res.status === 200) {
|
||||
// this.scenicOptions = res.data
|
||||
// }
|
||||
// } catch (error) {
|
||||
// this.$message.error('获取景区列表失败')
|
||||
// console.error('获取景区列表失败:', error)
|
||||
// this.scenicOptions = []
|
||||
// }
|
||||
},
|
||||
|
||||
// 获取飞行员列表
|
||||
async getEmployees() {
|
||||
try {
|
||||
const test = {
|
||||
employeesId: this.query.employeesId || 0
|
||||
}
|
||||
const res = await crudAircraft.get(test)
|
||||
if (res.status === 200) {
|
||||
this.employeeOptions = res.data
|
||||
}
|
||||
} catch (error) {
|
||||
this.$message.error('获取飞行员列表失败')
|
||||
console.error('获取飞行员列表失败:', error)
|
||||
this.employeeOptions = []
|
||||
}
|
||||
},
|
||||
[CRUD.HOOK.beforeRefresh]() {
|
||||
// 在刷新前将默认数据添加到crud.data中
|
||||
if (this.crud.data.length === 0) {
|
||||
this.crud.data = this.defaultData
|
||||
// this.crud.resetDataStatus()
|
||||
// 检查是否选择了负责人
|
||||
if (!this.query.employeesId) {
|
||||
this.$message.warning('请先选择负责人')
|
||||
return false
|
||||
}
|
||||
// 设置分页参数
|
||||
this.query.current = this.page.page
|
||||
this.query.size = this.page.size
|
||||
return true
|
||||
},
|
||||
[CRUD.HOOK.afterRefresh]() {
|
||||
// 更新分页数据
|
||||
if (this.crud.data.total) {
|
||||
this.page.total = this.crud.data.total
|
||||
}
|
||||
// 将默认数据添加到表格数据中
|
||||
if (Array.isArray(this.crud.data)) {
|
||||
this.crud.data = [...this.defaultData, ...this.crud.data]
|
||||
// 更新总数以包含默认数据
|
||||
this.page.total += this.defaultData.length
|
||||
} else if (this.crud.data && this.crud.data.records) {
|
||||
this.crud.data.records = [...this.defaultData, ...this.crud.data.records]
|
||||
// 更新总数以包含默认数据
|
||||
this.page.total += this.defaultData.length
|
||||
}
|
||||
},
|
||||
handleView(row) {
|
||||
this.$router.push({ path: '/aircraft/aircraftDetail', query: { id: row.id }})
|
||||
},
|
||||
handleAvatarSuccess(res, file) {
|
||||
if (!this.form.imageUrls) {
|
||||
this.form.imageUrls = []
|
||||
}
|
||||
this.form.imageUrls.push(res.url)
|
||||
handlePictureCardPreview(url) {
|
||||
this.dialogImageUrl = url
|
||||
this.dialogVisible = true
|
||||
},
|
||||
// 删除图片
|
||||
handleRemoveImage(index) {
|
||||
this.form.imageUrls.splice(index, 1)
|
||||
this.form.deviceImages.splice(index, 1)
|
||||
},
|
||||
beforeAvatarUpload(file) {
|
||||
const isImage = file.type.startsWith('image/')
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
|
||||
if (!isImage) {
|
||||
this.$message.error('上传文件只能是图片格式!')
|
||||
// 触发图片上传
|
||||
handleChange(file, uploadFiles) {
|
||||
if (file.raw.type.includes('image')) {
|
||||
this.loading = true
|
||||
try {
|
||||
upload(this.imagesUploadApi, file.raw).then(res => {
|
||||
if(res.status === 200){
|
||||
const data = res.data;
|
||||
// 构造deviceImages对象
|
||||
const deviceImage = {
|
||||
fileFullPath: this.baseApi + `/file/图片/` + data.newFileName,
|
||||
fileSize: file.raw.size,
|
||||
fileType: file.raw.type.split('/')[1],
|
||||
id: 0,
|
||||
newFileName: data.newFileName,
|
||||
sourceFileName: file.raw.name
|
||||
};
|
||||
// 将新图像添加到现有数组
|
||||
if (!this.form.deviceImages) {
|
||||
this.form.deviceImages = [];
|
||||
}
|
||||
this.form.deviceImages.push(deviceImage);
|
||||
this.$message.success('图片上传成功!')
|
||||
this.loading = false;
|
||||
}else{
|
||||
this.$message.error('图片上传失败!');
|
||||
this.loading = false;
|
||||
return;
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
this.loading = false
|
||||
this.$message.error('图片上传失败!')
|
||||
}
|
||||
} else {
|
||||
this.$confirm('图片的格式不正确,请重新选择!', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
type: 'warning'
|
||||
})
|
||||
uploadFiles.pop()
|
||||
}
|
||||
if (!isLt2M) {
|
||||
this.$message.error('上传图片大小不能超过 2MB!')
|
||||
}
|
||||
return isImage && isLt2M
|
||||
},
|
||||
|
||||
handleDelete(row) {
|
||||
this.$confirm(`此操作将永久删除飞行器"${row.name}",是否继续?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
@ -324,50 +460,65 @@ export default {
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.avatar-uploader {
|
||||
.el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
&:hover {
|
||||
border-color: #409EFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
.avatar-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
line-height: 120px;
|
||||
text-align: center;
|
||||
}
|
||||
.image-list {
|
||||
.upload-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
.image-item {
|
||||
position: relative;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
.avatar {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upload-item {
|
||||
::v-deep .el-upload--picture-card {
|
||||
width: 110px !important;
|
||||
height: 110px !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-item {
|
||||
position: relative;
|
||||
width: 110px;
|
||||
height: 110px;
|
||||
border: 1px solid #c0ccda;
|
||||
border-radius: 6px;
|
||||
|
||||
.preview-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.preview-actions {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
cursor: default;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 6px;
|
||||
transition: opacity 0.3s;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.delete-icon {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
// background-color: rgba(0,0,0,0.5);
|
||||
// color: white;
|
||||
padding: 5px;
|
||||
border-radius: 50%;
|
||||
|
||||
.preview-action {
|
||||
color: #fff;
|
||||
font-size: 18px;
|
||||
margin: 0 7px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(0,0,0,0.7);
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user