Files
im-uniapp/pages/workbench/construction/detail.vue
2025-07-05 16:48:46 +08:00

702 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="container">
<!-- 基本信息展示 -->
<view class="info-card" v-if="receivedParams.reportTitle">
<view class="info-header">
<u-icon name="info-circle" size="40" color="#409eff"></u-icon>
<text class="info-title">汇报概述信息</text>
</view>
<view class="info-content">
<view class="info-item">
<text class="info-label">汇报标题</text>
<text class="info-value">{{ receivedParams.reportTitle }}</text>
</view>
<view class="info-item">
<text class="info-label">汇报人</text>
<text class="info-value">{{ receivedParams.reporter }}</text>
</view>
<view class="info-item">
<text class="info-label">涉及项目</text>
<text class="info-value">{{ receivedParams.projectName }}</text>
</view>
</view>
</view>
<!-- 操作按钮 -->
<view class="action-buttons">
<u-button type="primary" @click="handleAdd" size="medium">新增</u-button>
<u-button type="error" @click="handleDelete" size="medium" :disabled="!selectedIds.length">删除</u-button>
</view>
<!-- 数据列表 -->
<view class="table-wrapper">
<scroll-view scroll-x class="table-scroll">
<view class="table-container">
<view class="table-header">
<view class="header-cell checkbox">
<u-checkbox v-model="selectAll" @change="handleSelectAll"></u-checkbox>
</view>
<view class="header-cell">设备编号</view>
<view class="header-cell">设备类别</view>
<view class="header-cell">汇报详情内容</view>
<view class="header-cell">图片概况</view>
<view class="header-cell">备注</view>
<view class="header-cell">操作</view>
</view>
<u-checkbox-group v-model="selectedIds" @change="handleSelectionChange">
<view class="table-body">
<view
v-for="(item, index) in reportDetailList"
:key="item.detailId"
class="table-row"
>
<view class="table-cell checkbox">
<u-checkbox
:name="item.detailId"
:value="item.detailId"
></u-checkbox>
</view>
<view class="table-cell">{{ item.deviceCode || '-' }}</view>
<view class="table-cell">{{ item.category || '-' }}</view>
<view class="table-cell content-cell">
<text class="content-text">{{ item.reportDetail || '-' }}</text>
</view>
<view class="table-cell">
<u-image
v-if="item.ossIds"
:src="item.ossIds.split(',')[0]"
width="60rpx"
height="60rpx"
@click="handleImageDetail(item)"
></u-image>
<text v-else>-</text>
</view>
<view class="table-cell">{{ item.remark || '-' }}</view>
<view class="table-cell">
<u-button
type="primary"
size="mini"
@click="handleUpdate(item)"
>修改</u-button>
<u-button
type="error"
size="mini"
@click="handleDelete(item)"
>删除</u-button>
</view>
</view>
</view>
</u-checkbox-group>
</view>
</scroll-view>
</view>
<!-- 分页 -->
<u-loadmore
v-if="total > 0"
:status="loadMoreStatus"
@loadmore="loadMore"
></u-loadmore>
<!-- 新增/修改弹窗 -->
<u-popup v-model="showForm" mode="center" width="600rpx" height="800rpx">
<view class="form-popup">
<view class="popup-header">
<text class="popup-title">{{ title }}</text>
<u-icon name="close" @click="cancel" size="40"></u-icon>
</view>
<scroll-view scroll-y class="form-content">
<u-form :model="form" ref="form" label-width="180rpx">
<u-form-item label="设备编号" prop="deviceCode">
<u-input v-model="form.deviceCode" placeholder="请输入设备唯一编号"></u-input>
</u-form-item>
<u-form-item label="设备类别" prop="category">
<u-input v-model="form.category" placeholder="请输入设备类别"></u-input>
</u-form-item>
<u-form-item label="详情内容" prop="reportDetail">
<u-textarea
v-model="form.reportDetail"
placeholder="请输入内容"
:height="200"
></u-textarea>
</u-form-item>
<u-form-item label="图像" prop="ossIds">
<u-upload
v-model="form.ossIds"
:file-list="fileList"
@after-read="afterRead"
@delete="deleteFile"
:max-count="9"
multiple
></u-upload>
</u-form-item>
<u-form-item label="备注" prop="remark">
<u-input v-model="form.remark" placeholder="请输入备注"></u-input>
</u-form-item>
</u-form>
</scroll-view>
<view class="popup-footer">
<u-button type="primary" @click="submitForm" :loading="buttonLoading">确定</u-button>
<u-button @click="cancel">取消</u-button>
</view>
</view>
</u-popup>
<!-- 图片详情抽屉 -->
<u-popup v-model="imageDrawer" mode="right" width="600rpx" height="100%">
<view class="image-drawer">
<view class="drawer-header">
<text class="drawer-title">图片列表</text>
<u-icon name="close" @click="imageDrawer = false" size="40"></u-icon>
</view>
<scroll-view scroll-y class="image-content">
<view class="image-grid">
<u-image
v-for="(img, index) in srcList"
:key="index"
:src="img"
width="150rpx"
height="150rpx"
@click="previewImage(img, index)"
></u-image>
</view>
</scroll-view>
</view>
</u-popup>
</view>
</template>
<script>
import { listReportDetail, addReportDetail, delReportDetail, getReportDetail, updateReportDetail } from '@/api/oa/reportDetail'
export default {
data() {
return {
// 按钮loading
buttonLoading: false,
// 遮罩层
loading: true,
// 选中数组
selectedIds: [],
// 全选状态
selectAll: false,
// 显示搜索条件
showSearch: false,
// 总条数
total: 0,
// 汇报详情表格数据
reportDetailList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
showForm: false,
// 图片抽屉
imageDrawer: false,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
summaryId: undefined,
deviceCode: undefined,
category: undefined,
reportDetail: undefined,
},
// 表单参数
form: {},
// 文件列表
fileList: [],
// 图片列表
srcList: [],
// 加载更多状态
loadMoreStatus: 'loadmore',
// 接收到的参数
receivedParams: {},
// 表单校验规则
rules: {
deviceCode: [
{ required: true, message: "设备唯一编号不能为空", trigger: "blur" }
],
category: [
{ required: true, message: "设备类别不能为空", trigger: "blur" }
],
reportDetail: [
{ required: true, message: "汇报详情内容不能为空", trigger: "blur" }
],
}
}
},
onLoad(options) {
// 获取路由参数
if (options.summaryId) {
this.queryParams.summaryId = options.summaryId;
this.form.summaryId = options.summaryId;
}
// 接收其他参数并设置页面标题
if (options.reportTitle) {
const title = decodeURIComponent(options.reportTitle);
uni.setNavigationBarTitle({
title: title || '施工进度详情'
});
}
// 保存接收到的参数到data中方便后续使用
this.receivedParams = {
summaryId: options.summaryId,
reportTitle: options.reportTitle ? decodeURIComponent(options.reportTitle) : '',
reporter: options.reporter ? decodeURIComponent(options.reporter) : '',
projectName: options.projectName ? decodeURIComponent(options.projectName) : ''
};
this.getList();
},
methods: {
/** 查询汇报详情列表 */
getList() {
this.loading = true;
listReportDetail(this.queryParams).then(response => {
this.reportDetailList = response.rows || [];
this.total = response.total || 0;
this.loading = false;
// 重置选中状态
this.selectedIds = [];
this.selectAll = false;
}).catch(() => {
this.loading = false;
});
},
// 切换搜索显示
toggleSearch() {
this.showSearch = !this.showSearch;
},
// 全选/取消全选
handleSelectAll(value) {
if (value) {
// 全选
this.selectedIds = this.reportDetailList.map(item => item.detailId);
} else {
// 取消全选
this.selectedIds = [];
}
},
// 选择变化
handleSelectionChange(value) {
// value 是选中的 ID 数组
this.selectedIds = value;
// 检查是否全选
this.selectAll = this.reportDetailList.length > 0 &&
this.selectedIds.length === this.reportDetailList.length;
},
// 取消按钮
cancel() {
this.showForm = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
detailId: undefined,
summaryId: this.queryParams.summaryId,
deviceCode: undefined,
category: undefined,
reportDetail: undefined,
ossIds: undefined,
remark: undefined,
};
this.fileList = [];
this.$refs.form && this.$refs.form.resetFields();
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.queryParams = {
pageNum: 1,
pageSize: 10,
summaryId: this.queryParams.summaryId,
deviceCode: undefined,
category: undefined,
reportDetail: undefined,
};
this.handleQuery();
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
this.showForm = true;
this.title = "添加施工进度汇报详情";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.loading = true;
this.reset();
const id = row.detailId;
getReportDetail(id).then(response => {
this.loading = false;
this.form = response.data || {};
// 处理图片文件列表
if (this.form.ossIds) {
this.fileList = this.form.ossIds.split(',').map((url, index) => ({
url: url,
status: 'success',
message: '上传成功'
}));
}
this.showForm = true;
this.title = "修改施工进度汇报详情";
}).catch(() => {
this.loading = false;
});
},
/** 提交按钮 */
submitForm() {
this.$refs.form.validate(valid => {
if (valid) {
this.buttonLoading = true;
// 处理图片数据
if (this.fileList.length > 0) {
this.form.ossIds = this.fileList.map(file => file.url).join(',');
}
if (this.form.detailId != null) {
updateReportDetail(this.form).then(response => {
uni.showToast({
title: '修改成功',
icon: 'success'
});
this.showForm = false;
this.getList();
}).catch(() => {
uni.showToast({
title: '修改失败',
icon: 'error'
});
}).finally(() => {
this.buttonLoading = false;
});
} else {
addReportDetail(this.form).then(response => {
uni.showToast({
title: '新增成功',
icon: 'success'
});
this.showForm = false;
this.getList();
}).catch(() => {
uni.showToast({
title: '新增失败',
icon: 'error'
});
}).finally(() => {
this.buttonLoading = false;
});
}
}
});
},
/** 删除按钮操作 */
handleDelete(row) {
const ids = row ? row.detailId : this.selectedIds;
if (!ids || (Array.isArray(ids) && ids.length === 0)) {
uni.showToast({
title: '请选择要删除的数据',
icon: 'none'
});
return;
}
uni.showModal({
title: '确认删除',
content: '是否确认删除选中的数据?',
success: (res) => {
if (res.confirm) {
this.loading = true;
const deleteIds = Array.isArray(ids) ? ids.join(',') : ids;
delReportDetail(deleteIds).then(() => {
this.loading = false;
this.getList();
uni.showToast({
title: '删除成功',
icon: 'success'
});
}).catch(() => {
this.loading = false;
uni.showToast({
title: '删除失败',
icon: 'error'
});
});
}
}
});
},
/** 查看图片详情 */
handleImageDetail(row) {
if (row.ossIds) {
this.srcList = row.ossIds.split(',');
this.imageDrawer = true;
}
},
// 预览图片
previewImage(current, index) {
uni.previewImage({
current: current,
urls: this.srcList
});
},
// 文件上传后
afterRead(event) {
const { file } = event;
// 这里可以调用上传接口
// 暂时使用本地路径
this.fileList.push({
url: file.url,
status: 'success',
message: '上传成功'
});
},
// 删除文件
deleteFile(event) {
const { index } = event;
this.fileList.splice(index, 1);
},
// 加载更多
loadMore() {
if (this.loadMoreStatus === 'nomore') return;
this.loadMoreStatus = 'loading';
this.queryParams.pageNum += 1;
listReportDetail(this.queryParams).then(response => {
const newData = response.rows || [];
this.reportDetailList = [...this.reportDetailList, ...newData];
this.total = response.total || 0;
if (newData.length < this.queryParams.pageSize) {
this.loadMoreStatus = 'nomore';
} else {
this.loadMoreStatus = 'loadmore';
}
}).catch(() => {
this.loadMoreStatus = 'loadmore';
this.queryParams.pageNum -= 1;
});
}
}
}
</script>
<style lang="scss" scoped>
.container {
padding: 20rpx;
background-color: #f5f5f5;
min-height: 100vh;
}
.info-card {
background-color: #fff;
padding: 30rpx;
margin-bottom: 20rpx;
border-radius: 10rpx;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
.info-header {
display: flex;
align-items: center;
margin-bottom: 20rpx;
.info-title {
font-size: 32rpx;
font-weight: bold;
margin-left: 20rpx;
color: #333;
}
}
.info-content {
.info-item {
display: flex;
margin-bottom: 15rpx;
&:last-child {
margin-bottom: 0;
}
.info-label {
font-size: 28rpx;
color: #666;
width: 160rpx;
flex-shrink: 0;
}
.info-value {
font-size: 28rpx;
color: #333;
flex: 1;
}
}
}
}
.action-buttons {
display: flex;
gap: 20rpx;
margin-bottom: 20rpx;
}
.table-wrapper {
background-color: #fff;
border-radius: 10rpx;
overflow: hidden;
}
.table-scroll {
width: 100%;
}
.table-container {
min-width: 1400rpx; // 设置最小宽度,确保表格内容不会被压缩
.table-header {
display: flex;
background-color: #f8f9fa;
border-bottom: 1rpx solid #e9ecef;
.header-cell {
width: 200rpx; // 固定列宽
padding: 20rpx 10rpx;
text-align: center;
font-weight: bold;
font-size: 28rpx;
flex-shrink: 0; // 防止列被压缩
&.checkbox {
width: 100rpx; // 复选框列宽度
}
}
}
.table-body {
.table-row {
display: flex;
border-bottom: 1rpx solid #e9ecef;
&:hover {
background-color: #f8f9fa;
}
.table-cell {
width: 200rpx; // 固定列宽
padding: 20rpx 10rpx;
text-align: center;
font-size: 26rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0; // 防止列被压缩
word-break: break-all; // 长文本换行
&.checkbox {
width: 100rpx; // 复选框列宽度
}
&.content-cell {
.content-text {
max-width: 180rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
}
.form-popup {
background-color: #fff;
border-radius: 20rpx;
overflow: hidden;
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #e9ecef;
.popup-title {
font-size: 32rpx;
font-weight: bold;
}
}
.form-content {
padding: 30rpx;
max-height: 600rpx;
}
.popup-footer {
display: flex;
gap: 20rpx;
padding: 30rpx;
border-top: 1rpx solid #e9ecef;
}
}
.image-drawer {
background-color: #fff;
height: 100%;
.drawer-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #e9ecef;
.drawer-title {
font-size: 32rpx;
font-weight: bold;
}
}
.image-content {
padding: 30rpx;
height: calc(100% - 100rpx);
.image-grid {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
}
}
</style>