aircraft-admin/src/views/aircraft/index.vue

739 lines
21 KiB
Vue

<template>
<div class="app-container">
<!--工具栏-->
<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-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="请选择区域"
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
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>
<!--表单渲染-->
<el-dialog
append-to-body
:close-on-click-modal="false"
:before-close="crud.cancelCU"
:visible.sync="crud.status.cu > 0"
:title="crud.status.title"
width="580px"
>
<el-form
ref="form"
:inline="true"
:model="form"
:rules="rules"
size="small"
label-width="100px"
>
<el-form-item label="飞行器名称" prop="name">
<el-input v-model="form.name" style="width: 150px" />
</el-form-item>
<el-form-item label="型号" prop="model">
<el-input v-model="form.model" style="width: 150px" />
</el-form-item>
<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="areaId">
<el-select
v-model="form.areaId"
@change="changeArea"
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="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="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'">
<el-input
type="textarea"
:rows="2"
placeholder="请输入备注"
v-model="form.remarks"
style="width: 150px"
>
</el-input>
</el-form-item>
<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="(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">
<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"
row-key="id"
@select="crud.selectChange"
@select-all="crud.selectAllChange"
@selection-change="crud.selectionChangeHandler"
>
<el-table-column type="selection" width="55" />
<el-table-column label="飞行器名称" prop="name" />
<el-table-column label="型号" prop="model" />
<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="username" />
<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">
<el-button size="mini" type="text" @click="handleView(scope.row)">
查看
</el-button>
<el-button
size="mini"
type="text"
@click="crud.toEdit(scope.row)"
v-permission="permission.edit"
v-if="checkPer(permission.edit)"
>
修改
</el-button>
<el-button
size="mini"
type="text"
@click="handleDelete(scope.row)"
v-permission="permission.del"
v-if="checkPer(permission.del)"
>
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!--分页-->
<div class="pagination-container">
<el-pagination
:background="true"
:current-page.sync="page.page"
:page-size.sync="page.size"
:layout="'total, sizes, prev, pager, next, jumper'"
:page-sizes="[10, 20, 50, 100]"
:total="page.total"
@size-change="crud.sizeChangeHandler"
@current-change="crud.pageChangeHandler"
/>
</div>
</div>
</template>
<script>
import CRUD, { presenter, header, form, crud } from "@crud/crud";
import udOperation from "@crud/UD.operation";
import crudAircraft from "@/api/aircraft";
import { allAreas } from "@/api/system/area";
import { getList, getDetail } from "@/api/system/pilot";
import { allScenic } from "@/api/system/scenic";
import { upload } from "@/utils/upload";
import { mapGetters } from "vuex";
import rrOperation from "@crud/RR.operation";
// crud交由presenter持有
const defaultForm = {
id: 1,
name: null,
brand: null,
model: null,
useType: 0,
areaId: null,
scenicId: null,
employeesId: null,
deviceImages: [],
remark: "",
createTime: null,
};
export default {
name: "aircraft",
components: { udOperation },
cruds() {
return CRUD({
title: "飞行器",
url: "aerocraftAdminApi/aircraft/device/page",
crudMethod: {
...crudAircraft,
getList: crudAircraft.getDevicePage,
},
optShow: {
search: true,
},
queryOnPresenterCreated: true, // 启用初始化时自动查询
page: {
// 配置分页参数名称
page: "current",
size: "size",
},
// 配置查询参数
query: {
employeesId: undefined,
areaId: undefined,
name: undefined,
},
initData: (crud, data) => {
crud.page.total = data.total;
// 确保每条记录的id是字符串类型
const records = data.records || [];
crud.data = records.map(item => ({
...item,
id: item.id ? item.id.toString() : ''
}));
// username字段需要通过getList()获取
crud.data.forEach((item) => {
if (item.employeesId) {
getList().then((res) => {
res.content.forEach((employee) => {
if (employee.id === item.employeesId) {
item.username = employee.username;
}
});
});
} else {
item.username = "未知";
}
});
},
});
},
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: [],
permission: {
add: ["admin", "aircraft:add"],
edit: ["admin", "aircraft:edit"],
del: ["admin", "aircraft:del"],
},
rules: {
name: [
{ required: true, message: "请输入飞行器名称", trigger: "blur" },
],
brand: [{ required: true, message: "品牌不能为空", trigger: "blur" }],
model: [{ required: true, message: "请输入型号", trigger: "blur" }],
useType: [{ required: true, message: "请选择类型", trigger: "change" }],
areaId: [{ required: true, message: "请选择区域", trigger: "change" }],
scenicId: [
{ required: true, message: "请选择景区", trigger: "change" },
],
employeesId: [
{ required: true, message: "请选择负责人", trigger: "change" },
],
deviceImages: [
{
required: true,
message: "请上传设备图片",
trigger: "change",
type: "array",
},
],
},
};
},
computed: {
...mapGetters(["imagesUploadApi", "baseApi"]),
},
created() {
// 获取区域列表
this.getAreas();
// 获取飞行员列表
this.getEmployees();
},
methods: {
// 获取区域列表
async getAreas() {
try {
const res = await allAreas();
if (res) {
this.areaOptions = res.map((area) => ({
id: area.id,
name: area.name,
}));
}
} catch (error) {
this.$message.error("获取区域列表失败");
console.error("获取区域列表失败:", error);
this.areaOptions = [];
}
},
// 切换区域时获取景区列表
changeArea(value) {
// 清空景区选择
this.query.scenicId = undefined;
// 获取对应区域的景区列表
allScenic({ areaId: value }).then((res) => {
if (res) {
this.scenicOptions = (res || []).map((scenic) => ({
id: scenic.id,
name: scenic.name,
}));
} else {
this.scenicOptions = [];
}
});
},
// 获取负责人列表
async getEmployees() {
try {
const res = await getList();
if (res) {
this.employeeOptions = res.content.map((employee) => ({
id: employee.id,
name: employee.username,
}));
}
} catch (error) {
this.$message.error("获取负责人列表失败");
console.error("获取负责人列表失败:", error);
this.employeeOptions = [];
}
},
[CRUD.HOOK.beforeToEdit](crud, form) {
// 获取对应的景区列表
if (form.areaId) {
allScenic({ areaId: form.areaId }).then((res) => {
if (res) {
this.scenicOptions = (res || []).map((scenic) => ({
id: scenic.id,
name: scenic.name,
}));
} else {
this.scenicOptions = [];
}
});
} else {
this.scenicOptions = [];
}
// 获取对应的负责人列表
if (form.employeesId) {
getList().then((res) => {
if (res) {
this.employeeOptions = res.content.map((employee) => ({
id: employee.id,
name: employee.username,
}));
} else {
this.employeeOptions = [];
}
});
} else {
this.employeeOptions = [];
}
},
[CRUD.HOOK.beforeSubmit]() {
// 设置brand的值与name相同
this.form.brand = this.form.name;
return true;
},
[CRUD.HOOK.beforeRefresh]() {
// 设置分页参数
this.crud.params.current = this.page.page;
this.crud.params.size = this.page.size;
// 设置查询参数
this.crud.params.employeesId = this.query.employeesId;
this.crud.params.areaId = this.query.areaId;
this.crud.params.name = this.query.name;
return true;
},
[CRUD.HOOK.afterRefresh]() {
// 更新分页数据
const response = this.crud.data;
if (response) {
// 确保有total字段
if (response.total !== undefined) {
this.page.total = Number(response.total);
}
// 确保records数组存在且是数组类型
if (response && Array.isArray(response)) {
// 创建一个Promise数组来存储所有的详情请求
const detailPromises = response.map(item => {
if (!item || !item.id) return Promise.resolve(null);
const stringId = item.id.toString();
return crudAircraft.getDeviceDetail(stringId).then(res => {
if (!res) return null;
return {
...item,
...res,
id: stringId
};
});
});
// 等待所有详情请求完成后再更新数据
Promise.all(detailPromises).then(detailedData => {
// 过滤掉空值并确保每个项都有一个有效的字符串id
this.crud.data = detailedData.filter(item => item && item.id && typeof item.id === 'string');
}).catch(error => {
console.error('获取设备详情失败:', error);
this.$message.error('获取设备详情失败');
});
} else {
// 如果没有records字段或不是数组,设置为空数组避免报错
this.crud.data = [];
}
} else {
// 如果响应为空,也设置为空数组
this.crud.data = [];
this.page.total = 0;
}
},
handleView(row) {
const tempRow = { areaName: row.areaName, scenicName: row.scenicName, username: row.username };
this.$router.push({
path: "/system/aircraftDetail/index",
query: {
id: row.id,
data: JSON.stringify(tempRow)
},
});
},
// 预览图片
handlePictureCardPreview(url) {
this.dialogImageUrl = url;
this.dialogVisible = true;
},
// 删除图片
handleRemoveImage(index) {
this.form.deviceImages.splice(index, 1);
},
// 触发图片上传
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: data.fileFullPath,
fileSize: file.raw.size,
fileType: file.raw.type.split("/")[1],
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();
}
},
handleDelete(row) {
this.$confirm(`此操作将永久删除飞行器"${row.name}",是否继续?`, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
crudAircraft.del(row.id).then(() => {
this.$notify({
title: "成功",
type: "success",
message: "删除成功!",
});
this.crud.refresh();
});
})
.catch(() => {
this.$message({
type: "info",
message: "已取消删除",
});
});
},
},
};
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
.upload-container {
display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: flex-start;
}
.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;
}
.preview-action {
color: #fff;
font-size: 18px;
margin: 0 7px;
cursor: pointer;
&:hover {
opacity: 0.8;
}
}
}
}
// .pagination-container {
// position: fixed;
// bottom: 0;
// right: 0;
// left: 200px;
// height: 150px;
// background: white;
// padding: 10px;
// text-align: left;
// box-shadow: 0 -2px 4px rgba(0, 0, 0, 0.08);
// }
// .el-pagination {
// padding: 2px 25px;
// }
.app-container {
padding-bottom: 60px;
}
::v-deep .el-input-number .el-input__inner {
text-align: left;
}
::v-deep .vue-treeselect__control,
::v-deep .vue-treeselect__placeholder,
::v-deep .vue-treeselect__single-value {
height: 30px;
line-height: 30px;
}
</style>