feat(report): 特种设备使用登记表功能

- 新增特种设备使用登记表单组件
- 实现设备信息、单位信息等字段的填写和展示
- 添加文件上传和预览功能
- 优化打印样式和布局
master
Tuzki 6 months ago
parent ca184d15a1
commit 4a50e4d3a1
  1. BIN
      public/favicon.ico
  2. BIN
      public/favicon1.ico
  3. BIN
      public/logo.png
  4. 8
      src/api/ticketing/ticketsort/index.js
  5. BIN
      src/assets/logo/logo.png
  6. 2
      src/assets/styles/login.scss
  7. 4
      src/layout/components/Sidebar/Logo.vue
  8. 18
      src/views/report/eventHistory/index.vue
  9. 76
      src/views/report/eventList/EquipmentRegistrationForm.vue
  10. 309
      src/views/report/eventList/printDemo.vue
  11. 29
      src/views/report/eventList/uploadFile.vue

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

@ -79,3 +79,11 @@ export function ticketSortCheckDuplicates(name) {
method: 'get'
})
}
//获得特种设备登记分页
export function getEquipmenttPage(params) {
return request({
url: '/special/equipment-registry/page',
method: 'get',
params
})
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

@ -66,7 +66,7 @@ $buttonHeight: $buttonH * 1px;
// 元素
width: $logoWidth;
height: 100vh;
background-image: url($logoImage);
background-size: contain;
// 定位
position: absolute;

@ -1,11 +1,11 @@
<template>
<div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
<transition name="sidebarLogoFade">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/report/eventList/index">
<img v-if="logo" :src="logo" class="sidebar-logo" />
<h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
</router-link>
<router-link v-else key="expand" class="sidebar-logo-link" to="/">
<router-link v-else key="expand" class="sidebar-logo-link" to="/report/eventList/index">
<img v-if="logo" :src="logo" class="sidebar-logo" />
<h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
</router-link>

@ -7,8 +7,8 @@
<div class="m-pages-search row">
<el-form class="m-search-form" :class="searchState ? 'col' : ''" :model="queryParams" ref="queryForm"
:inline="true" v-show="showSearch" label-width="">
<el-form-item label="单位名称/姓名" prop="sortName">
<el-input v-model="queryParams.sortName" placeholder="请输入单位名称/姓名" clearable
<el-form-item label="单位名称/姓名" prop="userUnit">
<el-input v-model="queryParams.userUnit" placeholder="请输入单位名称/姓名" clearable
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="创建时间" prop="createTime">
@ -35,11 +35,11 @@
<template v-else>
<div class="event-history-item" v-for="item in list">
<div class="event-history-item-left">
<div class="enent-name">{{ item.name }}</div>
<div class="enent-name">{{ item.userUnit ||'--'}}</div>
<div class="event-history-item-time">创建时间:{{ item.createTime }}</div>
</div>
<div class="event-history-item-right">
<el-button @click="">下载</el-button>
<el-button @click="getDetail(item)">下载</el-button>
</div>
</div>
</template>
@ -91,14 +91,8 @@
queryParams: {
pageNo: 1,
pageSize: 10,
belongingScenic: null,
ticketType: null,
scenicName: null,
sortName: null,
parentTenantId: null,
revision: null,
userUnit: null,
createTime: [],
remark: null
}
}
},
@ -110,7 +104,7 @@
async getList() {
try {
this.loading = true
const res = await TicketSortApi.getTicketSortPage(this.queryParams)
const res = await TicketSortApi.getEquipmenttPage(this.queryParams)
this.list = res.data.list
this.total = res.data.total
} finally {

@ -1,28 +1,28 @@
<template>
<div class="a4-container">
<div class="form-title">特种设备使用登记表式样二</div>
<div class="form-subtitle dark-text fz26">登记类别<span>首次启用</span></div>
<div class="form-subtitle dark-text fz26">登记类别<span>{{formData.registrationCategory}}</span></div>
<table class="registration-table">
<!-- 设备基本情况 -->
<tr>
<td colspan="1" rowspan="9" class="line-label wd10">设备基本情况</td>
<td class="line-label">设备品种</td>
<td class="w25"><el-input class="custom-input" v-model="formData.deviceType" /></td>
<td class="w25"><el-input class="custom-input" v-model="formData.equipmentType" /></td>
<td class="line-label">产品名称</td>
<td class="w25"><el-input class="custom-input" v-model="formData.deviceName" /></td>
<td class="w25"><el-input class="custom-input" v-model="formData.productName" /></td>
</tr>
<tr>
<td class="line-label">气瓶数量</td>
<td><el-input class="custom-input" v-model="formData.gasNumber" /></td>
<td><el-input class="custom-input" v-model="formData.cylinderQuantity" /></td>
<td class="line-label">充装介质</td>
<td><el-input class="custom-input" v-model="formData.fillingMedium" /></td>
</tr>
<tr>
<td class="line-label">气瓶公称工作压力 (MPa)</td>
<td><el-input class="custom-input" v-model="formData.pressure" /></td>
<td><el-input class="custom-input" v-model="formData.nominalWorkingPressure" /></td>
<td class="line-label">气瓶容积 (L)</td>
<td><el-input class="custom-input" v-model="formData.volume" /></td>
<td><el-input class="custom-input" v-model="formData.cylinderVolume" /></td>
</tr>
<tr>
<td class="line-label ">制造单位名称</td>
@ -32,30 +32,30 @@
</tr>
<tr>
<td><el-input class="custom-input" v-model="formData.manufacturer" /></td>
<td><el-input class="custom-input" v-model="formData.manufactureDate" /></td>
<td><el-input class="custom-input" v-model="formData.productionDate" /></td>
<td><el-input class="custom-input" v-model="formData.productId" /></td>
<td><el-input class="custom-input" v-model="formData.internalId" /></td>
</tr>
<tr>
<td><el-input class="custom-input" v-model="formData.manufacturer" /></td>
<td><el-input class="custom-input" v-model="formData.manufactureDate" /></td>
<td><el-input class="custom-input" v-model="formData.productionDate" /></td>
<td><el-input class="custom-input" v-model="formData.productId" /></td>
<td><el-input class="custom-input" v-model="formData.internalId" /></td>
</tr>
<tr>
<td><el-input class="custom-input" v-model="formData.manufacturer" /></td>
<td><el-input class="custom-input" v-model="formData.manufactureDate" /></td>
<td><el-input class="custom-input" v-model="formData.productionDate" /></td>
<td><el-input class="custom-input" v-model="formData.productId" /></td>
<td><el-input class="custom-input" v-model="formData.internalId" /></td>
</tr>
<!-- 其他字段 -->
<tr>
<td class="line-label" >施工单位名称</td>
<td colspan="3"><el-input class="custom-input" v-model="formData.constructionUnit" /></td>
<td colspan="3"><el-input class="custom-input" v-model="formData.contractor" /></td>
</tr>
<tr>
<td class="line-label" colspan="1">监督检验机构名称</td>
<td colspan="3"><el-input class="custom-input" v-model="formData.inspectionAgency" /></td>
<td colspan="3"><el-input class="custom-input" v-model="formData.supervisionAgency" /></td>
</tr>
<tr>
<td colspan="1" rowspan="6" class="line-label wd10">设备使用情况</td>
@ -68,7 +68,7 @@
</tr>
<tr>
<td class="line-label">使用单位统一社会信用代码</td>
<td><el-input class="custom-input" v-model="formData.creditCode" /></td>
<td><el-input class="custom-input" v-model="formData.unifiedSocialCode" /></td>
<td class="line-label">邮政编码</td>
<td><el-input class="custom-input" v-model="formData.postalCode" /></td>
</tr>
@ -76,11 +76,11 @@
<td class="line-label">车牌号</td>
<td><el-input class="custom-input" v-model="formData.licensePlate" /></td>
<td class="line-label">车辆VIN码</td>
<td><el-input class="custom-input" v-model="formData.vin" /></td>
<td><el-input class="custom-input" v-model="formData.vehicleVin" /></td>
</tr>
<tr>
<td class="line-label">投入使用日期</td>
<td><el-input class="custom-input" v-model="formData.useDate" /></td>
<td><el-input class="custom-input" v-model="formData.commissionDate" /></td>
<td class="line-label">单位固定电话</td>
<td> <el-input class="custom-input" v-model="formData.telephone" /></td>
</tr>
@ -88,7 +88,7 @@
<td class="line-label">安全管理员</td>
<td><el-input class="custom-input" v-model="formData.safetyManager" /></td>
<td class="line-label">移动电话</td>
<td> <el-input class="custom-input" v-model="formData.mobile" /></td>
<td> <el-input class="custom-input" v-model="formData.mobilePhone" /></td>
</tr>
<tr>
<td class="dark-text" colspan="5">
@ -132,27 +132,29 @@
data() {
return {
formData: {
deviceType: '',
gasNumber: '',
fillingMedium: '',
pressure: '',
volume: '',
manufacturer: '',
manufactureDate: '',
productId: '',
internalId: '',
constructionUnit: '',
inspectionAgency: '',
userUnit: '',
userAddress: '',
creditCode: '',
postalCode: '',
licensePlate: '',
vin: '',
useDate: '',
telephone: '',
safetyManager: '',
mobile: ''
"registrationCategory": "",//
"equipmentType": "",//
"productName": "",//
"cylinderQuantity": 1,//
"fillingMedium": "",//
"nominalWorkingPressure": 1,//
"cylinderVolume": 1,//
"manufacturer": "",//
"productionDate": "2025-04-11",//
"productId": "",//
"internalId": "",//
"contractor": "",//
"supervisionAgency": "",//
"userUnit": "",//使
"userAddress": "",//使
"unifiedSocialCode": "",//使
"postalCode": "",//
"licensePlate": "",//
"vehicleVin": "",//VIN
"commissionDate": "2025-04-11",//使
"telephone": "",//
"safetyManager": "",//
"mobilePhone": ""//
}
}
},
@ -224,7 +226,7 @@
.a4-container {
width: 210mm;
min-height: 297mm;
margin: 20px auto;
margin: 0 auto;
padding: 20px;
background: white;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);

@ -1,53 +1,276 @@
<template>
<div>
<div v-if="Object.keys(formData).length === 0">Loading data...</div>
<EquipmentRegistrationForm v-else :initialData="formData" />
<div class="m-pages m-pages-bg">
<div class="file-view-box">
<div class="list-scroll-nomore">
<div class="list-scroll-box">
<div v-for="item in fileList" class="file-item" @click="bigView(item)">
<img v-if="item.type === 'image'" :src="item.url" class="preview-image">
<pdf v-if="item.type === 'pdf'" :src="item.url"></pdf>
</div>
</div>
</div>
<div class="file-view-content">
<div class="btn-box">
<div class="pagination">
<el-button style="font-size: 22px;padding: 5px 15px;" @click="zoomIn">+</el-button>
<el-button style="font-size: 22px;padding: 5px 15px;" @click="zoomOut">-</el-button>
</div>
<div class="pagination" v-if="showType === 'pdf' && pageCount <= 1">
<el-button @click="rotate += 90" style="font-size: 22px;padding: 5px 15px;">&#x27F3;</el-button>
<el-button @click="rotate -= 90" style="font-size: 22px;padding: 5px 15px;">&#x27F2;</el-button>
</div>
<div class="pagination" v-if="showType === 'pdf' && pageCount > 1">
<el-button @click="rotate += 90" style="font-size: 22px;padding: 5px 15px;">&#x27F3;</el-button>
<el-button @click="rotate -= 90" style="font-size: 22px;padding: 5px 15px;">&#x27F2;</el-button>
<el-button @click="currentPage = currentPage - 1" :disabled="currentPage <= 1"
style="font-size: 14px;padding: 10px 15px;">上一页</el-button>
<span> {{ currentPage }} / {{ pageCount }} </span>
<el-button @click="currentPage = currentPage + 1" :disabled="currentPage >= pageCount"
style="font-size: 14px;padding: 10px 15px;">下一页</el-button>
</div>
</div>
<div class="nomore-view">
<div class="pdf-img-box drag-box" :style="boxStyle" @mousedown="startDrag">
<img v-if="showType === 'image'" :src="showUrl" class="preview-image">
<pdf v-if="showType === 'pdf'" :src="showUrl" :rotate="rotate" :page="currentPage"
@num-pages="pageCount = $event" @progress="isLoading = true" @loaded="isLoading = false"></pdf>
</div>
<div class="mask" v-if="isLoading">加载中...</div>
</div>
</div>
</div>
<div class="word-view-box">
<div v-if="Object.keys(formData).length === 0">Loading data...</div>
<EquipmentRegistrationForm v-else :initialData="formData" />
</div>
</div>
</template>
<script>
import EquipmentRegistrationForm from './EquipmentRegistrationForm.vue'
import EquipmentRegistrationForm from './EquipmentRegistrationForm.vue'
import pdf from 'vue-pdf';
export default {
components: { EquipmentRegistrationForm },
data() {
return {
formData: {} //
export default {
components: { EquipmentRegistrationForm, pdf },
data() {
return {
currentPage: 1, //
pageCount: 0, //
isLoading: false, //
rotate: 0,
formData: {}, //
fileList: [],
showUrl: '',
showType: '',
scale: 1, //
position: { //
x: 0,
y: 0
},
dragging: false, //
startX: 0, // X
startY: 0, // Y
initialX: 0, // X
initialY: 0 // Y
}
},
computed: {
//
boxStyle() {
return {
transform: `translate(${this.position.x}px, ${this.position.y}px) scale(${this.scale})`,
transformOrigin: '0 0', //
position: 'absolute',
cursor: this.dragging ? 'grabbing' : 'grab'
};
}
},
created() {
console.log(this.$route.query)
const data = this.$route.query.data
const newFileList = [...data.basicFiles, ...data.usageFiles]
this.fileList = newFileList
console.log(newFileList)
this.mockFetchData()
},
methods: {
//
mockFetchData() {
setTimeout(() => {
this.formData = {
"registrationCategory": "首次启用",//
"equipmentType": "高压气瓶",//
"productName": "车用气瓶",//
"cylinderQuantity": 1,//
"fillingMedium": "氧气",//
"nominalWorkingPressure": 1,//
"cylinderVolume": 1,//
"manufacturer": "XX制造有限公司",//
"productionDate": "2025-04-11",//
"productId": "SN123456",//
"internalId": "IN7890",//
"contractor": "XX工程公司",//
"supervisionAgency": "XX监督检验所",//
"userUnit": "XX科技有限公司",//使
"userAddress": "北京市海淀区",//使
"unifiedSocialCode": "91230103MA1BUFLX45",//使
"postalCode": "100000",//
"licensePlate": "京A12345",//
"vehicleVin": "LVSHJCAM6AE012345",//VIN
"commissionDate": "2025-04-11",//使
"telephone": "010-12345678",//
"safetyManager": "张三",//
"mobilePhone": "13800138000"//
}
}, 1000) // 1
},
bigView(val) {
this.showUrl = ''
this.showUrl = val.url;
this.showType = val.type;
},
//
zoomIn() {
this.scale = Math.min(this.scale * 1.2, 4); //
},
//
zoomOut() {
this.scale = Math.max(this.scale * 0.8, 0.5); //
},
//
startDrag(e) {
this.dragging = true;
this.startX = e.clientX;
this.startY = e.clientY;
this.initialX = this.position.x;
this.initialY = this.position.y;
document.addEventListener('mousemove', this.onDrag);
document.addEventListener('mouseup', this.stopDrag);
},
//
onDrag(e) {
if (!this.dragging) return;
const dx = e.clientX - this.startX;
const dy = e.clientY - this.startY;
this.position.x = this.initialX + dx;
this.position.y = this.initialY + dy;
},
//
stopDrag() {
this.dragging = false;
document.removeEventListener('mousemove', this.onDrag);
document.removeEventListener('mouseup', this.stopDrag);
}
}
},
created() {
console.log(this.$route.query)
this.mockFetchData()
},
methods: {
//
mockFetchData() {
setTimeout(() => {
this.formData = {
deviceType: '高压气瓶',
gasNumber: '50',
fillingMedium: '氧气',
pressure: '15',
volume: '40',
manufacturer: 'XX制造有限公司',
manufactureDate: '2023-01-01',
productId: 'SN123456',
internalId: 'IN7890',
constructionUnit: 'XX工程公司',
inspectionAgency: 'XX监督检验所',
userUnit: 'XX科技有限公司',
userAddress: '北京市海淀区',
creditCode: '91230103MA1BUFLX45',
postalCode: '100000',
licensePlate: '京A12345',
vin: 'LVSHJCAM6AE012345',
useDate: '2023-03-01',
telephone: '010-12345678',
safetyManager: '张三',
mobile: '13800138000'
}
</script>
<style scoped lang="scss">
.m-pages-bg {
display: flex;
align-items: flex-start;
width: 100%;
justify-content: space-between;
overflow-y: scroll;
.file-view-box {
flex: 1;
display: flex;
align-items: flex-start;
justify-content: space-between;
overflow-y: scroll;
height: calc(100vh - 86px);
overflow-y: scroll;
background-color: #fff;
padding: 15px;
.list-scroll-nomore {
margin-top: 55px;
height: 98vh;
overflow-y: scroll;
scrollbar-width: none;
width: 10%;
}
.list-scroll-box {
height: fit-content;
background-color: #eef1f9;
padding: 5px;
.file-item:not(:last-child) {
margin-bottom: 10px;
cursor: pointer;
}
}
.file-view-content {
flex: 1;
margin-left: 10px;
position: relative;
.btn-box {
display: flex;
align-items: center;
justify-content: center;
.pagination {
margin: 10px;
text-align: center;
display: flex;
align-items: center;
}
}
.nomore-view {
width: 100%;
height: calc(100vh - 16px);
background-color: #eef1f9;
overflow: hidden;
position: relative;
.pdf-img-box {
overflow: scroll;
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* Internet Explorer 10+ */
}
.drag-box {
height: fit-content;
background: #f0f0f0;
display: flex;
align-items: center;
justify-content: center;
user-select: none;
/* 防止文字被选中 */
}
.mask {
background-color: rgba(0, 0, 0, 0.5);
height: 100%;
width: 100%;
color: #fff;
text-align: center;
line-height: 100vh;
z-index: 9999;
position: relative;
}
}
}, 1000) // 1
}
}
.word-view-box {
width: 50%;
height: calc(100vh - 86px);
overflow-y: scroll;
}
}
}
</script>
</style>

@ -1,8 +1,8 @@
<template>
<div class="smart-form-container ">
<div class="smart-form-container m-pages m-pages-bg">
<!-- 页面 标题 -->
<div class="m-pages-title"><span class="inner">智能填单</span></div>
<div class="page-data">
<div class="page-data m-pages-data ">
<!-- 登记类别选择 -->
<el-form ref="form" style="width: 60%;" :model="formData">
@ -23,7 +23,8 @@
<div class="upload-section">
<el-upload class="upload-area" :action="uploadFileUrl" :headers="headers" :multiple="true"
:file-list="basicFiles" :on-preview="handlePreview" :before-upload="beforeUpload"
:http-request="uploadFileFactory('basic')" :on-remove="handleRemoveBasic" :on-success="handleBasicUploadSuccess">
:http-request="uploadFileFactory('basic')" :on-remove="handleRemoveBasic"
:on-success="handleBasicUploadSuccess">
<el-button type="primary">选择文件</el-button>
</el-upload>
</div>
@ -40,7 +41,8 @@
<div class="upload-section">
<el-upload class="upload-area" :action="uploadFileUrl" :headers="headers" :multiple="true"
:file-list="usageFiles" :on-preview="handlePreview" :before-upload="beforeUpload"
:http-request="uploadFileFactory('usage')" :on-remove="handleRemoveUsage" :on-success="handlUsageeUploadSuccess">
:http-request="uploadFileFactory('usage')" :on-remove="handleRemoveUsage"
:on-success="handlUsageeUploadSuccess">
<el-button type="primary">选择文件</el-button>
</el-upload>
</div>
@ -91,14 +93,20 @@
<!-- 渲染 PDF 当前页 -->
<pdf :src="previewUrl" :page="currentPage" @num-pages="pageCount = $event" @loading="isLoading = true"
<pdf :src="previewUrl" :rotate="rotate" :page="currentPage" @num-pages="pageCount = $event" @loading="isLoading = true"
@loaded="isLoading = false"></pdf>
<!-- 加载状态提示 -->
<div v-if="isLoading" class="loading">加载中...</div>
</div>
<span slot="footer" class="dialog-footer">
<div class="pagination" v-if="previewType === 'pdf'&& pageCount > 1">
<div class="pagination" v-if="previewType === 'pdf'&& pageCount <= 1">
<el-button @click="rotate += 90">&#x27F3;</el-button>
<el-button @click="rotate -= 90">&#x27F2;</el-button>
</div>
<div class="pagination" v-if="previewType === 'pdf' && pageCount > 1">
<el-button @click="rotate += 90">&#x27F3;</el-button>
<el-button @click="rotate -= 90">&#x27F2;</el-button>
<el-button @click="currentPage = currentPage - 1" :disabled="currentPage <= 1">上一页</el-button>
<span> {{ currentPage }} / {{ pageCount }} </span>
<el-button @click="currentPage = currentPage + 1" :disabled="currentPage >= pageCount">下一页</el-button>
@ -114,7 +122,7 @@
import service from '@/utils/request'
import pdf from 'vue-pdf';
import fileUpload from '@/components/FileUpload/index.vue'
import { data } from "qrcode.vue";
import { data } from "qrcode.vue";
export default {
components: {
fileUpload, pdf
@ -124,6 +132,7 @@ import { data } from "qrcode.vue";
currentPage: 1, //
pageCount: 0, //
isLoading: false, //
rotate: 0,
formData: {
category: ''
},
@ -273,7 +282,7 @@ import { data } from "qrcode.vue";
usageFiles: this.usageFiles
}
this.$message.success('文件上传成功,开始识别!');
this.$router.push({path:'/report/eventList/printDemo',query:{data:obj}})
this.$router.push({ path: '/report/eventList/printDemo', query: { data: obj } })
}
}
};
@ -281,9 +290,6 @@ import { data } from "qrcode.vue";
<style scoped>
.smart-form-container {
margin: 20px 10px;
padding: 30px;
background: #fff;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
display: flex;
@ -292,7 +298,6 @@ import { data } from "qrcode.vue";
.page-data {
display: flex;
margin-top: 20px;
}
.form-title {

Loading…
Cancel
Save