表格数据的增删改查代码
实现组件化开发;分为根组件、子组件(查询组件、表格组件、新增编辑组件、详情组件)
index.vue
<template>
<!-- etDeviceLease/et-equipmentLeaseReturn/index 租赁归还 -->
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<equipment-return-seach
ref="queryRef"
:isLoading="isLoading"
:showSearch="showSearch"
:selectObjs="selectObjs"
:multiple="multiple"
@resetQuery="resetQuery"
@checkUp="getData"
></equipment-return-seach>
<equipment-return-page
@handleDelete="handleDelete"
:formDialogRef="formDialogRef"
:detailDialogRef="detailDialogRef"
@selectionChangHandle="selectionChangHandle"
@handleShow="handleShow"
:dataList="state.dataList"
>
<template v-slot:pagination>
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
</template>
</equipment-return-page>
</div>
<!-- 编辑、新增 -->
<equipment-return-card ref="formDialogRef" @refresh="getDataList(false)" />
<el-dialog v-model="dialogVisible" :title="'租赁单查看'" :close-on-click-modal="false" draggable>
<detail-card ref="formDetailRef" :dialogVisibleType="dialogVisible" :data-id="dataId" />
<!-- <template #footer>
<span class="dialog-footer">
<el-button type="primary">发起流程</el-button>
</span>
</template> -->
</el-dialog>
</div>
</template>
<script setup lang="ts" name="systemEtFaultExperience">
import * as archives from '/@/api/archives/et-archives';
import { BasicTableProps, useTable } from "/@/hooks/table";
import { fetchList, delObjs } from "/@/api/equipment/etDeviceLeaseReturn";
import { useMessage, useMessageBox } from "/@/hooks/message";
import { useDict } from '/@/hooks/dict';
// 引入组件
const equipmentReturnPage = defineAsyncComponent(() => import('./equipmentReturnPage.vue'));
const DetailCard = defineAsyncComponent(() => import('./detailCard.vue'));
const equipmentReturnSeach = defineAsyncComponent(() => import('./equipmentReturnSeach.vue'));
const equipmentReturnCard = defineAsyncComponent(() => import('./equipmentReturnCard.vue'));
// 定义查询字典
// 定义变量内容
const formDialogRef = ref(null);
const detailDialogRef = ref(null);
// 搜索变量
const queryRef = ref(null);
const showSearch = ref(true);
// 多选变量
const selectObjs = ref([]) as any;
const multiple = ref(true);
// 定义懒加载
const options = ref([]);
const isLoading = ref(false);
const hasMore = ref(true); // 判断是否还有更多数据
const pageSize = ref(20); // 每次加载的数量
const currentPage = ref(1); // 当前页数
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
pageList: fetchList,
});
// table hook
const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, downBlobFile, tableStyle } = useTable(state);
// 清空搜索条件
const resetQuery = (e) => {
state.queryForm = e;
// 清空多选
selectObjs.value = [];
options.value = []; // 重置选项
isLoading.value = false;
hasMore.value = true;
currentPage.value = 1; // 如果有分页逻辑,重置当前页
queryRef.value?.resetFields();
getDataList();
};
// 点击查询
const getData = (e) => {
state.queryForm = e;
getDataList();
};
// 导出excel
const exportExcel = () => {
downBlobFile('/equipment/etFaultExperience/export', Object.assign(state.queryForm, { ids: selectObjs }), 'etFaultExperience.xlsx');
};
// 多选事件
const selectionChangHandle = (objs: { id: string }[]) => {
selectObjs.value = objs.map(({ id }) => id);
multiple.value = !objs.length;
};
const dataId = ref();
const billStatus = ref();
const nodeStatus = ref();
const createBy = ref();
const dialogVisible = ref();
// 查看
function handleShow(row) {
dataId.value = row.id;
billStatus.value = row.billStatus;
nodeStatus.value = row.status;
createBy.value = row.createBy;
dialogVisible.value = true;
}
// 删除操作
const handleDelete = async (ids: string[]) => {
try {
await useMessageBox().confirm('此操作将永久删除');
} catch {
return;
}
try {
await delObjs(ids);
useMessage().success('删除成功');
getDataList();
} catch (err: any) {
useMessage().error(err.msg);
}
};
</script>
equipmentReturnSeach.vue
实现表格查询,重置表格选项
<template>
<el-row >
<el-form :model="state.queryForm" label-width="90px" ref="queryRef" :inline="true" @keyup.enter="getDataList">
<el-col :span="24">
<el-form-item label="归还编号:" prop="leaseReturnNum">
<el-input placeholder="请输入归还编号" v-model="state.queryForm.leaseReturnNum" />
</el-form-item>
<el-form-item label="归还名称:" prop="leaseReturnName">
<el-input placeholder="请输入归还名称" v-model="state.queryForm.leaseReturnName" />
</el-form-item>
<el-form-item label="归还方" prop="tenantry">
<el-input v-model="state.queryForm.tenantry" placeholder="请输入归还方" />
</el-form-item>
<el-form-item label="联系方式" prop="tenantryPhone">
<el-input v-model="state.queryForm.tenantryPhone" placeholder="请输入联系方式" />
</el-form-item>
<el-form-item label="设备名称:" prop="archives">
<el-input placeholder="请输入设备名称" v-model="state.queryForm.archives" />
</el-form-item>
<el-form-item label="归还时间:" prop="startTime">
<el-date-picker
format="YYYY-MM-DD"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="租赁时间"
style="width: 220px !important; text-align: left !important"
v-model="value1"
editable
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</el-form-item>
<el-form-item label="审批状态:" prop="billStatus">
<el-select v-model="state.queryForm.billStatus" filterable clearable placeholder="请选择审批状态">
<el-option v-for="item in DIC_PROP.ORDER_STATUS" :key="item.value" :label="item.label" :value="item.value"></el-option>
</el-select>
</el-form-item>
<el-form-item label="">
<el-button style="margin-left: 2rem" icon="Search" type="primary" v-auth="'equipment_etDeviceLease_view'" @click="checkUp">{{
$t('common.queryBtn')
}}</el-button>
<el-button icon="Refresh" v-auth="'equipment_etDeviceLease_view'" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
</el-form-item>
</el-col>
</el-form>
</el-row>
</template>
<script setup lang="ts">
import { reactive, ref, defineProps, defineEmits, onMounted } from 'vue';
import { DIC_PROP } from '/@/flow/support/dict-prop';
const state = reactive({
queryForm: {
// equipmentName: '',
// planNum: '',
// planName: '',
// planTypeCode: '',
// billStatus: '',
// planStart: '',
// planEnd: '',
// items: [],
},
});
const emit = defineEmits(['getDataList', 'checkUp']);
const value1 = ref([]);
const getDataList = async (value: any) => {
emit('getDataList');
};
const checkUp = async (value: any) => {
if (Array.isArray(value1.value) && value1.value.length !== 0) {
// 修改时间
state.queryForm.leaseReturnStartTime = value1.value[0] ; //租赁归还开始时间
state.queryForm.leaseReturnEndTime = value1.value[1]; //租赁归还结束时间
} else {
state.queryForm.leaseReturnStartTime = ''; //租赁归还开始时间
state.queryForm.leaseReturnEndTime = ''; //租赁归还结束时间
}
emit('checkUp', state.queryForm);
};
// 搜索变量
const queryRef = ref();
// 多选变量
const selectObjs = ref([]) as any;
// 清空搜索条件
const resetQuery = () => {
// 清空搜索条件
queryRef.value?.resetFields();
state.queryForm = {};
// 清空多选
selectObjs.value = [];
value1.value=[]
emit('checkUp', {});
};
</script>
<style scoped></style>
equipmentReturnPage.vue
实现点击编辑弹窗出现,点击删除判断删除权限 进行删除,使用sort具名插槽放置分页组件,点击查看显示弹窗数据回显展示,点击新增和编辑使用同一弹窗组件
<template>
<div class="mb8" style="width: 100%">
<el-button icon="folder-add" type="primary" class="ml10" @click="props.formDialogRef.openDialog()" v-auth="'equipment_etDeviceLeaseReturn_add'">
新 增
</el-button>
<el-button plain :disabled="multiple" icon="Delete" type="primary" v-auth="'equipment_etDeviceLeaseReturn_del'" @click="handleDelete(selectObjs)">
删除
</el-button>
</div>
<el-table
:data="dataList"
v-loading="vLoading"
:cell-style="cellStyle"
:header-cell-style="headerCellStyle"
@selection-change="selectionChangHandle"
@sort-change="sortChangeHandle"
>
<el-table-column type="selection" width="40" align="center" />
<!-- <el-table-column type="index" label="#" width="40" /> -->
<el-table-column prop="leaseReturnNum" label="归还编号" show-overflow-tooltip />
<el-table-column prop="leaseReturnName" label="归还名称" show-overflow-tooltip />
<el-table-column prop="archives" label="设备名称" show-overflow-tooltip />
<el-table-column prop="tenantry" label="归还方" show-overflow-tooltip />
<el-table-column prop="tenantryPhone" label="归还方联系方式" show-overflow-tooltip />
<el-table-column prop="leaseReturnTime" label="归还时间" show-overflow-tooltip />
<el-table-column prop="remarks" label="归还说明" show-overflow-tooltip />
<el-table-column prop="billStatus" label="业务审批状态" show-overflow-tooltip>
<template #default="scope">
<dict-tag
:options="DIC_PROP.ORDER_STATUS"
:value="scope.row.billStatus"
:elTagStyle="{
color: orderStatusItem(scope.row) ? orderStatusItem(scope.row).color : '',
'border-color': orderStatusItem(scope.row) ? orderStatusItem(scope.row).color : '',
'background-color': '#fff',
}"
></dict-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200">
<template #default="scope">
<el-button
icon="edit-pen"
text
type="primary"
@click="formDialogRef.openDialog(scope.row.id)"
v-if="editShow(scope)"
v-auth="'equipment_etDeviceLeaseReturn_edit'"
>编辑</el-button
>
<el-button icon="el-icon-search" text type="primary" v-auth="'equipment_etDeviceLeaseReturn_view'" @click="handleShow(scope.row)">查看</el-button>
<el-button
icon="delete"
v-auth="'equipment_etDeviceLeaseReturn_del'"
v-if="delShow(scope)"
text
type="primary"
@click="handleDelete([scope.row.id])"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
<slot name="pagination"></slot>
</template>
<script setup lang="ts">
import { reactive, ref, defineProps, defineEmits, onMounted } from 'vue';
import { useMessage, useMessageBox } from '/@/hooks/message';
import { DIC_PROP } from '/@/flow/support/dict-prop';
const props = defineProps({
dataList: {
type: Array,
default: [
{
id: '',
leaseReturnName: '',
leaseReturnNum: '',
flowKey: '',
flowInstId: '',
leaseReturnTime: '2024-12-12',
leaseId: '',
remarks: '',
billStatus: '',
chargeDeptId: '',
userId: '',
deptId: '',
revision: '',
createBy: '',
createTime: '2024-12-12T09:48:10.605Z',
updateBy: '',
updateTime: '2024-12-12T09:48:10.605Z',
delFlag: '',
tenantId: '',
},
],
},
vLoading: {
type: String,
default: 'false',
},
cellStyle: {
type: Object,
},
headerCellStyle: {
type: Object,
},
pagination: {
type: Object,
},
formDialogRef: {
type: Object,
required: true,
},
lastParam: {
type: String,
default: '0',
},
userId: {
type: String,
},
});
// 多选变量
const selectObjs = ref([]) as any;
const multiple = ref(true);
// 多选事件
const selectionChangHandle = (objs: { id: string }[]) => {
selectObjs.value = objs.map(({ id }) => id);
multiple.value = !objs.length;
};
const emit = defineEmits(['handleDelete', 'sortChangeHandle', 'handleShow']);
const sortChangeHandle = () => {
emit('sortChangeHandle');
};
const orderStatusItem = computed(() => {
return (row) => {
return DIC_PROP.ORDER_STATUS.find((item) => item.value === row.billStatus);
};
});
const editShow = (scope) => {
// 当前状态为未发起时 任何人都可以删除修改
if (scope.row.billStatus === '-2') {
return true;
} else {
// 当前用户为创建人且当前状态为办理中、被驳回时,可以修改
if ((scope.row.status === '0' || scope.row.status === '9') && props.userId == scope.row.createBy) {
return true;
}
}
return false;
};
const delShow = (scope) => {
return scope.row.billStatus === '-2';
};
// 删除操作
const handleDelete = async (ids: string[]) => {
emit('handleDelete', ids);
};
function handleShow(row) {
emit('handleShow', row);
}
onMounted(() => {
console.log(props.formDialogRef, 'page');
});
</script>
equipmentReturnCard.vue 新增、编辑弹窗(使用同一组件)
点击编辑调用openDialog(id) 函数传参,点击新增调用openDialog()函数,判断id是否存在,true:编辑,false:新增
实现编辑数据回显 id存在,调用接口请求数据,再次打开弹框,表单数据清空
// 重置表单数据
nextTick(() => {
dataFormRef.value?.resetFields();
})
<template>
<el-dialog :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable width="60%">
<el-form ref="dataFormRef" :model="form" :rules="dataRules" formDialogRef label-width="110px">
<el-row :gutter="24">
<el-col :span="8" class="mb20">
<el-form-item label="归还名称" prop="leaseReturnName">
<el-input v-model="form.leaseReturnName" placeholder="请输入租赁名称" />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="归还方" prop="tenantry">
<el-select v-model="form.tenantry" clearable filterable placeholder="请选择归还人" @change="userChange">
<el-option v-for="item in userList" :key="item.tenantry" :label="item.tenantry" :value="item.tenantry" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="联系方式" prop="tenantryPhone">
<el-input v-model="form.tenantryPhone" placeholder="归还方联系方式" type="tel" />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="归还时间" prop="leaseReturnTime">
<el-date-picker v-model="form.leaseReturnTime" value-format="YYYY-MM-DD HH:mm:ss" type="date" placeholder="选择归还时间">
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="16" class="mb20">
<el-form-item label="归还说明" prop="remarks">
<el-input v-model="form.remarks" placeholder="请输入归还说明" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-upload
class="upload-demo"
action="/api/equipment/minio/upload"
:headers="uploadHeaders"
:file-list="form.deviceLeaseReturnFileEntityList"
list-type="text"
:on-remove="handleFileRemove"
:on-success="handleFileSuccess"
:auto-upload="true"
:before-upload="beforeFileUpload"
multiple
:limit="10"
>
<el-button icon="folder-add" type="primary" class="ml10" v-auth="'pigx_etDeviceLeaseFile_add'"> 上传文件 </el-button>
</el-upload>
</el-col>
</el-row>
</el-form>
<el-form ref="dataFormRefs" :model="form.deviceLeaseEntity" :rules="dataRule" formDialogRef label-width="120px">
<el-row>
<el-col :span="7" class="mb20">
<el-form-item label="租赁编号:" prop="leaseNum">
<el-select
@change="receiveChange"
clearable
filterable
v-model="form.deviceLeaseEntity.leaseNum"
value-key="id"
placeholder="请选择领用编号"
>
<el-option v-for="item in userListAll" :key="item.id" :label="item.leaseNum" :value="item.leaseNum"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="5" class="mb20">
<el-form-item label="开始时间:" prop="startTime">
{{ form.deviceLeaseEntity.startTime }}
</el-form-item>
</el-col>
<el-col :span="5" class="mb20">
<el-form-item label="结束时间:" prop="endTime">
{{ form.deviceLeaseEntity.endTime }}
</el-form-item>
</el-col>
<el-col :span="5" class="mb20">
<el-form-item label="时长:" prop="duration">
{{ form.deviceLeaseEntity.duration ? form.deviceLeaseEntity.duration + '天' : '---天' }}
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-row>
<el-col :span="24" class="mb20">
<el-table
ref="tableRefs"
:data="form.deviceLeaseDetailEntityList"
border
:cell-style="tableStyle.cellStyle"
@selection-change="selectionChangHandle"
:header-cell-style="tableStyle.headerCellStyle"
:row-key="(row) => row.leaseId"
>
<el-table-column type="selection" label="#" width="40" align="center" />
<el-table-column prop="equipmentNum" label="设备编号" show-overflow-tooltip />
<el-table-column prop="equipmentName" label="设备名称" show-overflow-tooltip />
<el-table-column prop="specificationModel" label="规格型号" show-overflow-tooltip />
<el-table-column prop="typeName" label="设备类型" show-overflow-tooltip />
<el-table-column prop="assetCategoryName" label="资产类型" show-overflow-tooltip />
<el-table-column prop="buyPrice" label="设备原值" show-overflow-tooltip />
<el-table-column prop="leasePrise" label="租赁价格" show-overflow-tooltip />
<el-table-column prop="depreciationPrise" label="折旧价格" show-overflow-tooltip>
<template #default="{ row }">
<el-input type="number" v-model="row.depreciationPrise" placeholder="请输入折旧价格" />
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
<template #footer>
<span class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" v-if="isShowInitiateProcess" @click="initiateProcess" :disabled="loading">确认并发起流程</el-button>
<el-button type="primary" @click="onSubmit" :disabled="loading">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script setup lang="ts" name="equipmentReturnCard">
import { useMessage, useMessageBox } from '/@/hooks/message';
// updateStartWorkFlow, startWorkFlow
import { getObj, addObj, putObj, updateStartWorkFlow, startWorkFlow } from '/@/api/equipment/etDeviceLeaseReturn';
import { ref, reactive, nextTick } from 'vue';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { rule as rules } from '/@/utils/validate';
import { Session } from '/@/utils/storage';
import { getAllTenantry, getAllByTenantry } from '/@/api/equipment/etDeviceLease';
import _ from 'lodash';
const emit = defineEmits(['refresh']);
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
dataList: [],
});
// table hook
const { tableStyle } = useTable(state);
// 定义变量内容
const dataFormRef = ref();
const dataFormRefs = ref();
const visible = ref(false);
const loading = ref(false);
const tableRefs = ref();
const isShowInitiateProcess = ref(true);
// 出租归还方
const tenantry = ref('');
const userList = ref([]);
// 租赁数据
const userListAll = ref([]);
// 定义表单数据模型
const form = reactive<{
id: string;
leaseReturnName: string;
leaseReturnNum: string;
flowKey: string;
flowInstId: string;
leaseReturnTime: string;
leaseReturnStartTime: string;
leaseReturnEndTime: string;
leaseId: string;
remarks: string;
billStatus: string;
chargeDeptId: string;
userId: string;
deptId: string;
revision: string;
createBy: string;
createTime: string;
updateBy: string;
updateTime: string;
delFlag: string;
tenantId: string;
archives: string;
tenantry: string;
tenantryPhone: string;
deviceLeaseEntity: Object;
deviceLeaseDetailEntityList: {}[];
deviceLeaseReturnDetailEntityList: {}[];
deviceLeaseReturnFileEntityList: {}[];
}>({
id: '',
leaseReturnName: '',
leaseReturnNum: '',
flowKey: '',
flowInstId: '',
leaseReturnTime: '',
leaseReturnStartTime: '',
leaseReturnEndTime: '',
leaseId: '',
remarks: '',
billStatus: '',
chargeDeptId: '',
userId: '',
deptId: '',
revision: '',
createBy: '',
createTime: '',
updateBy: '',
updateTime: '',
delFlag: '',
tenantId: '',
archives: '',
tenantry: '',
tenantryPhone: '',
deviceLeaseEntity: {},
deviceLeaseDetailEntityList: [],
deviceLeaseReturnDetailEntityList: [],
deviceLeaseReturnFileEntityList: [],
});
//选中编号的数据 归还数据
// const form.deviceLeaseEntity = ref({});
//选择归还人处理函数
const userChange = async (value) => {
let arr = await getAllByTenantry(value);
userListAll.value = arr.data;
form.deviceLeaseEntity = {};
form.tenantry = value;
};
//选择租赁编号时获取tableData数据
const receiveChange = async (value) => {
form.deviceLeaseEntity = userListAll.value.find((x, y) => {
return x.leaseNum === value;
});
// 计算天数
calculateDuration(form.deviceLeaseEntity.startTime, form.deviceLeaseEntity.endTime);
form.leaseId = form.deviceLeaseEntity.id;
// 表格数据
form.deviceLeaseDetailEntityList = JSON.parse(JSON.stringify(form.deviceLeaseEntity.archivesList));
};
// 多选变量
const selectObjs = ref([]) as any;
const multiple = ref(true);
// 多选事件
const selectionChangHandle = (objs: { id: string }[]) => {
selectObjs.value = objs.map((item) => item);
multiple.value = !objs.length;
};
//文件上传
const handleFileRemove = async (file: any, fileLists: Ref<[]>) => {
const transformedArray = fileLists.forEach((x) => ({
fileUrl: x.fileUrl,
fileId: x.uid,
}));
form.deviceLeaseReturnFileEntityList = transformedArray;
};
// 设备档案文档
const handleFileSuccess = async (response: any, file: any, files: Ref<[]>) => {
// 上传成功后的回调,可以更新后端返回的文件信息到本地state
if (response.code == 1) {
useMessage().error(response.msg);
} else {
form.deviceLeaseReturnFileEntityList?.push({
fileUrl: response.data.url,
fileId: response.data.id,
});
}
};
const beforeFileUpload = (file: File) => {
// 获取文件扩展名
const fileExtension = file.name.split('.').pop();
// 允许上传的文件扩展名列表
const acceptableExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'txt', 'rar'];
// 判断文件扩展名是否在允许的列表中
if (!acceptableExtensions.includes(fileExtension.toLowerCase())) {
useMessage().error(`只能上传PDF、.doc、.docx、.xls、.xlsx、.txt、.rar格式的文件!`);
return false;
}
// 这里还可以添加其他条件判断,如文件大小限制等
return true;
};
// 计算租赁时长
const calculateDuration = (startTime: string, endTime: string) => {
// 新增
let start = new Date(startTime);
let end = new Date(endTime);
const timeDiff = end - start;
const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
return Math.floor(timeDiff / oneDay) ? Math.floor(timeDiff / oneDay) : '---';
};
// 打开弹窗
const openDialog = (id: string) => {
visible.value = true;
form.id = '';
userList.value = [];
form.deviceLeaseReturnFileEntityList = [];
(form.deviceLeaseEntity = {}), (form.deviceLeaseDetailEntityList = []), (form.deviceLeaseReturnDetailEntityList = []), (userListAll.value = []);
form.value = _.clone({});
// 获取所有承租方
getAllTenantry(tenantry.value).then((res) => {
userList.value = res.data;
});
// 重置表单数据
nextTick(() => {
dataFormRef.value?.resetFields();
});
// 获取etCheckItemPlan信息
if (id) {
form.id = id;
getetDeviceLeaseData(id);
}
};
// 初始化表单数据
const getetDeviceLeaseData = (id: string) => {
// 获取数据
loading.value = true;
getObj(id)
.then((res: any) => {
Object.assign(form, res.data);
form.tenantry = form.deviceLeaseEntity.tenantry;
form.tenantryPhone = form.deviceLeaseEntity.tenantryPhone;
form.leaseReturnTime = form.leaseReturnTime + ' 00:00:00';
form.deviceLeaseReturnFileEntityList.forEach((item) => {
item.name = item.fileName
});
// 回显所有表格数据
getAllByTenantry(form.tenantry)
.then(async (result) => {
userListAll.value = result.data;
// receiveChange(form.deviceLeaseEntity.leaseNum);
setTimeout(() => {
handleSetValue(form.deviceLeaseDetailEntityList, form.deviceLeaseReturnDetailEntityList);
}, 800);
})
.catch((err) => {});
isShowInitiateProcess.value = res.data.billStatus === '-2';
})
.finally(() => {
loading.value = false;
});
};
function handleSetValue(arr, list) {
console.log('list', list);
list = list.map((item) => item.archivesId);
if (arr) {
arr.forEach((item, index) => {
if (list.includes(item.archivesId)) {
form.deviceLeaseReturnDetailEntityList.forEach((x,y) => {
if (item.archivesId === x.archivesId) {
console.log(y);
item.depreciationPrise = x.depreciationPrise
}
});
tableRefs.value.toggleRowSelection(item, true);
} else {
tableRefs.value.toggleRowSelection(item, false);
}
});
} else {
tableRefs.value.clearSelection();
}
}
// 提交
const onSubmit = async () => {
const valid = await dataFormRef.value.validate().catch(() => {});
if (!valid) {
console.log('校验失败valid');
return false;
}
const valids = await dataFormRefs.value.validate().catch(() => {});
if (!valids) {
console.log('校验失败valids');
return false;
}
// 选中的归还设备
let selectList = selectObjs.value.length;
if (!selectList) {
useMessage().error('请选择归还设备');
return false;
}
let isvalid = true;
// 校验价格是否填写
selectObjs.value.some((item) => {
if (item.depreciationPrise === null || item.depreciationPrise === undefined) {
useMessage().error('请输入折旧价格');
return (isvalid = false); // 停止循环
} else if (item.depreciationPrise < 0) {
useMessage().error('折旧价格不能小于0');
return (isvalid = false); // 停止循环
}
});
if (!isvalid) return false;
try {
// // 归还设备数据
form.deviceLeaseReturnDetailEntityList = _.cloneDeep(selectObjs.value);
// 租赁设备集合
form.deviceLeaseDetailEntityList=== null? form.deviceLeaseDetailEntityList = _.cloneDeep(form.deviceLeaseEntity.archivesList) :form.deviceLeaseDetailEntityList;
form.deviceLeaseEntity.tenantry = form.tenantry;
loading.value = true;
const responseData = form.id ? await putObj(form) : await addObj(form);
useMessage().success(form.id ? '修改成功' : '添加成功');
visible.value = false;
emit('refresh');
return true;
} catch (err: any) {
useMessage().error(err.msg);
} finally {
loading.value = false;
}
return false;
};
// 发起流程
const initiateProcess = async () => {
const yesOrNo = await onSubmit();
console.log(yesOrNo, 'yesOrNo');
if (yesOrNo) {
loading.value = true;
await updateStartWorkFlow({ id: form.id }).then((response) => {
startWorkFlow(response.data).then((res) => {
loading.value = false;
if (res.code === 0) {
useMessage().success('发起成功');
} else {
useMessage().error('发起失败,请联系管理员!');
}
loading.value = false;
visible.value = false;
emit('refresh');
});
});
}
};
// 定义校验规则
const dataRules = ref({
leaseReturnName: [{ required: true, message: '归还名称不能为空', trigger: 'blur' }],
tenantry: [{ required: true, message: '归还方不能为空', trigger: 'blur' }],
leaseReturnTime: [{ required: true, message: '请选择归还时间', trigger: 'blur' }],
tenantryPhone: [
{ required: true, message: '请输入联系方式', trigger: 'blur' },
{
validator: (rule, value, callback) => {
rules.validatePhone(rule, value, callback);
},
trigger: 'blur',
},
],
});
const dataRule = ref({
leaseNum: [{ required: true, message: '请选择租赁编号', trigger: 'blur' }],
});
// 暴露变量
defineExpose({
openDialog,
});
const uploadHeaders = ref({});
onMounted(() => {
// 图片上传
uploadHeaders.value = {
Authorization: 'Bearer ' + Session.get('token'),
'TENANT-ID': Session.getTenant(),
};
});
</script>
<style scoped>
:deep(.el-collapse-item__header) {
font-size: 18px !important; /* 添加 '!important' 来提高样式的优先级 */
font-weight: 500; /* 如果需要加粗也可以在这里设置 */
}
:deep(.el-select__selection.is-near) {
flex-wrap: nowrap !important;
}
:deep(.el-select .el-select-tags-wrapper.has-prefix) {
margin-left: 0px;
}
:deep(.el-select__tags) {
margin-left: 2px;
}
.custom-popper {
max-height: 1000px; /* 设置最大高度 */
overflow-y: auto; /* 添加滚动条 */
}
</style>
detailCard.vue
点击查看-tab展示数据、工作流状态、上传文档展示、文件下载
<template>
<div>
<el-tabs v-model="activeName">
<el-tab-pane label="租赁信息" name="first">
<el-form :model="form" label-width="120px" ref="queryRef" :inline="true">
<el-row :gutter="12">
<el-col :span="8">
<el-form-item label="归还名称:" prop="leaseName">
{{ form.leaseReturnName }}
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="归还方:" prop="lessor">
{{ form.deviceLeaseEntity?.tenantry }}
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系方式:" props="tenantryPhone"> {{ form.deviceLeaseEntity?.tenantryPhone }} </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="归还时间:" prop="leaseReturnTime"> {{ form.leaseReturnTime}} </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="归还说明:" prop="remarks"> {{ form.remarks }} </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="租赁编号:" prop="leaseNum"> {{ form.deviceLeaseEntity?.leaseNum }} </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="开始时间:" prop="startTime"> {{ form.deviceLeaseEntity?.startTime }} </el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="结束时间:" prop="endTime">{{ form.deviceLeaseEntity?.endTime }}</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="时长:" prop="duration">
{{ calculateDuration(form.deviceLeaseEntity?.startTime, form.deviceLeaseEntity?.endTime)? calculateDuration(form.deviceLeaseEntity.startTime, form.deviceLeaseEntity.endTime)+'天' :'---' }}
<!-- {{ form.duration+ '天' }} -->
</el-form-item>
</el-col>
</el-row>
</el-form>
<el-table
ref="tableRefs"
:data="form.deviceLeaseReturnDetailEntityList"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
>
<el-table-column prop="equipmentNum" label="设备编号" show-overflow-tooltip />
<el-table-column prop="equipmentName" label="设备名称" show-overflow-tooltip />
<el-table-column prop="specificationModel" label="规格型号" show-overflow-tooltip />
<el-table-column prop="typeName" label="设备类型" show-overflow-tooltip />
<el-table-column prop="assetCategoryName" label="资产类型" show-overflow-tooltip />
<el-table-column prop="buyPrice" label="设备原值" show-overflow-tooltip />
<el-table-column prop="leasePrise" label="租赁价格" show-overflow-tooltip />
<el-table-column prop="depreciationPrise" label="折旧价格" show-overflow-tooltip />
</el-table>
<!-- <Equipment :form="viewDeviceReceiveDetailList" :loading="isLoading"></Equipment> -->
<!-- <Equipment :form="form.archivesList"></Equipment> -->
</el-tab-pane>
<el-tab-pane label="关联文档" name="text">
<div class="fileDiv" v-if="form.deviceLeaseReturnFileEntityList?.length">
<div class="fileView" v-for="(item, index) in form.deviceLeaseReturnFileEntityList" :key="item.fileUrl">
<template v-if="item.fileSuffix === 'doc' || item.fileSuffix === 'word'">
<img style="width: 4rem" src="/@/assets/word.png" alt="" />
</template>
<template v-else-if="item.fileSuffix === 'xls' || item.fileSuffix === 'xlsx'">
<img style="width: 4rem" src="/@/assets/excel.png" alt="" />
</template>
<template v-else-if="item.fileSuffix === 'txt'">
<img style="width: 4rem" src="/@/assets/txt.png" alt="" />
</template>
<template v-else-if="item.fileSuffix === 'pdf'">
<img style="width: 4rem" src="/@/assets/pdf.png" alt="" />
</template>
<template v-else-if="item.fileSuffix === 'ppt'">
<img style="width: 4rem" src="/@/assets/ppt.png" alt="" />
</template>
<text class="fileName">{{ item.fileName }}</text>
<dl class="fileData">
<dd>文件类型: {{ item.fileSuffix }}</dd>
<dd>大小: {{ parseInt(item.fileSize, 10) / 1024 / 1024 }} MB</dd>
<dd>上传人:{{ item.userName }}</dd>
<dd>
<text>{{ item.createdTime ? formatDate(item.createdTime) : '' }}</text>
<el-button type="primary" size="small" @click="unload(item)" style="margin-left: 10px"> 下载</el-button>
</dd>
</dl>
</div>
</div>
<div v-else style="padding: 60px 0">
<el-empty :image-size="80" description="还没有文件哦,快去上传吧!" />
</div>
</el-tab-pane>
<el-tab-pane label="查看审批流程" name="third" v-if="props.showExamineAndApprove">
<flow :currJob="{ flowInstId: form.flowInstId, flowKey: form.flowKey }"></flow>
</el-tab-pane>
<!-- <el-tab-pane label="查看流程图" name="tu"> 查看流程图 </el-tab-pane> -->
</el-tabs>
</div>
</template>
<script setup lang="ts" name="EtUpkeepItemDialog">
import { useMessage } from '/@/hooks/message';
import { getObj ,getByFlowInstId } from '/@/api/equipment/etDeviceLeaseReturn';
import { BasicTableProps, useTable } from '/@/hooks/table';
import { downloadFile } from '/@/components/downloadFile/downloadFile'; // 导入封装的下载文件方法
const emit = defineEmits(['refresh']);
const flow = defineAsyncComponent(() => import('/@/views/jsonflow/comment/flow.vue'));
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
dataList: [],
});
// table hook
const { tableStyle } = useTable(state);
// 定义变量内容
const dataFormRef = ref();
const visible = ref(false);
const loading = ref(false);
const activeName = ref('first');
// 计算租赁时长
const calculateDuration = (startTime: string, endTime: string) => {
// 新增
let start = new Date(startTime);
let end = new Date(endTime);
const timeDiff = end - start;
const oneDay = 24 * 60 * 60 * 1000; // 一天的毫秒数
return Math.floor(timeDiff / oneDay) ? Math.floor(timeDiff / oneDay) : '---';
};
// 下载文件
const unload = (e) => {
let { fileName ,fileUrl} =e
downloadFile(fileUrl, fileName)
};
// 提交表单数据
// 定义表单数据模型
const form = reactive<{
id: String;
startTime: String;
endTime: String;
billStatus: String;
tenantry: String;
tenantryPhone: String;
lessor: string;
duration: string;
leaseName: string;
leaseNum: String;
flowKey: String;
flowInstId: String;
lessorPhone: String;
tenantId: String;
createBy: String;
createTime: string;
updateBy: String;
updateTime: string;
delFlag: String;
archives: String;
archivesList: {
id: number;
leaseId: String;
archivesId: String;
leasePrise: String;
isReturn: String;
equipmentNum: String;
equipmentName: String;
specificationModel: String;
typeName: String;
assetCategoryName: String;
buyPrice: String;
}[];
fileVOList: {
id: number;
leaseId: number;
fileId: number;
fileUrl: String;
chargeDeptId: String;
deptId: String;
userId: String;
createBy: String;
createTime: String;
updateBy: String;
updateTime: String;
fileType: String;
fileName: String;
fileSize: String;
fileSuffix: String;
userName: String;
fileUserName: String;
createdTime: String;
}[];
}>({
id: '',
startTime: '',
endTime: '',
billStatus: '',
tenantry: '',
tenantryPhone: '',
lessor: '',
duration: '',
leaseName: '',
leaseNum: '',
flowKey: '',
flowInstId: '',
lessorPhone: '',
tenantId: '',
createBy: '',
createTime: '',
updateBy: '',
updateTime: '',
delFlag: '',
archives: '',
archivesList: [
{
id: NaN,
leaseId: '',
archivesId: '',
leasePrise: '',
isReturn: '',
equipmentNum: '',
equipmentName: '',
specificationModel: '',
typeName: '',
assetCategoryName: '',
buyPrice: '',
},
],
fileVOList: [
{
id: NaN,
leaseId: NaN,
fileId: NaN,
fileUrl: '',
chargeDeptId: '',
deptId: '',
userId: '',
createBy: '',
createTime: '',
updateBy: '',
updateTime: '',
fileType: '',
fileName: '',
fileSize: '',
fileSuffix: '',
userName: '',
fileUserName: '',
createdTime: '',
},
],
});
const props = defineProps({
checkTypeCode: {
type: String,
default: '',
},
dataId: {
type: String,
default: '',
},
flowInstId: {
type: String,
default: null,
},
dialogVisibleType: {
type: Boolean,
default: false,
},
showExamineAndApprove: {
type: Boolean,
default: true,
},
});
const tableData = ref([]);
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
if (columnIndex === 0) {
if (rowIndex > 0 && row.specificationModel === tableData.value[rowIndex - 1].specificationModel) {
return { rowspan: 0, colspan: 0 }; // Return 0 to hide the cell
}
let rowspan = 1;
for (let i = rowIndex + 1; i < tableData.value.length; i++) {
if (row.specificationModel === tableData.value[i].specificationModel) {
rowspan++;
} else {
break;
}
}
return { rowspan: rowspan, colspan: 1 };
}
};
const formatDate = (dateString) => {
if (dateString !== null && dateString !== '' && dateString !== undefined) {
const date = new Date(dateString);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // January is month 0
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
} else {
return '';
}
};
// 打开弹窗
const openDialog = (id: string) => {
visible.value = true;
form.id = '';
// 重置表单数据
nextTick(() => {
dataFormRef.value?.resetFields();
});
// 获取etUpkeepItem信息
if (id) {
form.id = id;
getetUpkeepItemPlanData(id);
}
};
// 初始化表单数据
const getetUpkeepItemPlanData = (id: string) => {
// 获取数据
loading.value = true;
tableData.value = [];
getObj(id)
.then((res: any) => {
Object.assign(form, res.data);
})
.finally(() => {
loading.value = false;
});
};
watch(
() => props.dialogVisibleType,
(newId) => {
if (newId) {
form.id = '';
form.flowInstId = '';
activeName.value = 'first';
tableData.value = [];
nextTick(() => {
dataFormRef.value?.resetFields();
});
getetUpkeepItemPlanData(props.dataId);
}
},
{ immediate: true } // 添加immediate选项以在初始渲染时立即触发watcher
);
// 新增:监听 flowInstId 的变化
watch(
() => props.flowInstId,
(newFlowInstId) => {
if (newFlowInstId) {
form.id = '';
form.flowInstId = '';
tableData.value = [];
nextTick(() => {
dataFormRef.value?.resetFields();
});
// 获取数据
loading.value = true;
}
},
{ immediate: true } // 同样添加immediate以在初始渲染时立即触发watcher
);
// 暴露变量
defineExpose({
openDialog,
});
</script>
<style scoped>
.fileName {
color: #545454;
font-size: 16px;
font-weight: 600;
}
.fileView {
margin: 15px 24px;
background-color: #fff;
width: 14rem;
height: 18rem;
/* border-radius: 40px 40px 40px 40px; */
border: 1px solid #ededed;
display: flex;
flex-direction: column;
text-align: center;
justify-content: space-around;
align-items: center;
}
.fileView:hover {
background: #eef3fa;
}
.fileData {
height: 9rem;
display: flex;
flex-direction: column;
text-align: center;
justify-content: space-around;
align-items: center;
}
.fileDiv {
width: 100%;
display: flex;
flex-direction: row;
flex: 5;
flex-wrap: wrap;
}
</style>