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

- 新增特种设备使用登记表单组件
- 实现设备信息的查看和编辑功能
- 添加导出为Word的功能
- 集成OCR识别功能,支持营业执照和行驶本的自动识别
- 优化界面样式,增加进度加载和错误提示
master
Tuzki 6 months ago
parent 6467b850c4
commit 404d95891b
  1. BIN
      public/1.pdf
  2. BIN
      public/1_营业执照.jpg
  3. BIN
      public/templates/template.docx
  4. 16
      src/api/ticketing/ticketsort/index.js
  5. 21
      src/views/report/eventHistory/index.vue
  6. 144
      src/views/report/eventList/EquipmentRegistrationForm.vue
  7. 112
      src/views/report/eventList/printDemo.vue

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

Binary file not shown.

@ -93,4 +93,20 @@ export function getEquipmentt(id) {
url: '/special/equipment-registry/get?id=' + id,
method: 'get'
})
}
//获得特种设备登记
export function analyze(url) {
return request({
url: '/analyze',
method: 'POST',
data:{filePath:url}
})
}
//获得特种设备登记
export function createOcr(data) {
return request({
url: '/special/equipment-registry/create',
method: 'POST',
data:data
})
}

@ -37,7 +37,7 @@
<div class="event-history-item-time">创建时间:{{ item.createTime }}</div>
</div>
<div class="event-history-item-right">
<el-button @click="getDetail(item)">下载</el-button>
<el-button @click="getDetail(item)">查看</el-button>
</div>
</div>
</template>
@ -47,6 +47,10 @@
<pagination class="m-pagination" v-show="total > 0" :total="total" :page.sync="queryParams.pageNo"
:limit.sync="queryParams.pageSize" @pagination="getList" />
</div>
<el-dialog class="m-dialog" title="记录详情" :visible.sync="open" width="fit-content" v-dialogDrag append-to-body>
<div v-if="Object.keys(formData).length === 0">加载中...</div>
<EquipmentRegistrationForm :disabled="formDisabled" v-else :initialData="formData" />
</el-dialog>
</div>
</template>
@ -55,14 +59,19 @@
import * as TicketSortApi from '@/api/ticketing/ticketsort'
import VMixins from '@/utils/v-mixins'
import VDefault from '@/views/components/v-default/index.vue'
import EquipmentRegistrationForm from '../eventList/EquipmentRegistrationForm.vue'
export default {
name: 'TicketSort',
mixins: [VMixins],
components: {
VDefault
VDefault,
EquipmentRegistrationForm
},
data() {
return {
open: false,
formDisabled: false,
//
loading: true,
//
@ -79,6 +88,7 @@
createTime: '2021-03-28 10:00:00',
}
],
formData: {},
//
isExpandAll: true,
//
@ -95,7 +105,7 @@
}
},
created() {
// this.getList()
this.getList()
},
methods: {
/** 查询列表 */
@ -110,7 +120,12 @@
}
},
async getDetail(val) {
this.open = true
this.formDisabled = true
const res = await TicketSortApi.getEquipmentt(val.id)
this.formData = res.data
this.formData.infoList = JSON.parse(this.formData.infoList)
this.formData.commissionDate = this.formData.commissionDate.join('-')
console.log(res)
},
/** 搜索按钮操作 */

@ -8,21 +8,21 @@
<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.equipmentType" /></td>
<td class="w25"><el-input :disabled="disabled" class="custom-input" v-model="formData.equipmentType" /></td>
<td class="line-label">产品名称</td>
<td class="w25"><el-input class="custom-input" v-model="formData.productName" /></td>
<td class="w25"><el-input :disabled="disabled" class="custom-input" v-model="formData.productName" /></td>
</tr>
<tr>
<td class="line-label">气瓶数量</td>
<td><el-input class="custom-input" v-model="formData.cylinderQuantity" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.cylinderQuantity" /></td>
<td class="line-label">充装介质</td>
<td><el-input class="custom-input" v-model="formData.fillingMedium" /></td>
<td><el-input :disabled="disabled" 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.nominalWorkingPressure" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.nominalWorkingPressure" /></td>
<td class="line-label">气瓶容积 (L)</td>
<td><el-input class="custom-input" v-model="formData.cylinderVolume" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.cylinderVolume" /></td>
</tr>
<tr>
<td class="line-label ">制造单位名称</td>
@ -31,64 +31,64 @@
<td class="line-label ">单位内编号</td>
</tr>
<tr v-for="(item, index) in formData.infoList" :key="index">
<td><el-input class="custom-input" v-model="item.manufacturer" /></td>
<td><el-input class="custom-input" v-model="item.productionDate" /></td>
<td><el-input class="custom-input" v-model="item.productId" /></td>
<td><el-input class="custom-input" v-model="item.internalId" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="item.manufacturer" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="item.productionDate" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="item.productId" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="item.internalId" /></td>
</tr>
<!-- <tr>
<td><el-input class="custom-input" v-model="formData.manufacturer" /></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>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.manufacturer" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.productionDate" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.productId" /></td>
<td><el-input :disabled="disabled" 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.productionDate" /></td>
<td><el-input class="custom-input" v-model="formData.productId" /></td>
<td><el-input class="custom-input" v-model="formData.internalId" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.manufacturer" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.productionDate" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.productId" /></td>
<td><el-input :disabled="disabled" 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.contractor" /></td>
<td colspan="3"><el-input :disabled="disabled" 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.supervisionAgency" /></td>
<td colspan="3"><el-input :disabled="disabled" class="custom-input" v-model="formData.supervisionAgency" /></td>
</tr>
<tr>
<td colspan="1" rowspan="6" class="line-label wd10">设备使用情况</td>
<td colspan="1" class="line-label">使用单位名称</td>
<td colspan="3"><el-input class="custom-input" v-model="formData.userUnit" /></td>
<td colspan="3"><el-input :disabled="disabled" class="custom-input" v-model="formData.userUnit" /></td>
</tr>
<tr>
<td colspan="1" class="line-label">使用单位地址</td>
<td colspan="3"><el-input class="custom-input" v-model="formData.userAddress" /></td>
<td colspan="3"><el-input :disabled="disabled" class="custom-input" v-model="formData.userAddress" /></td>
</tr>
<tr>
<td class="line-label">使用单位统一社会信用代码</td>
<td><el-input class="custom-input" v-model="formData.unifiedSocialCode" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.unifiedSocialCode" /></td>
<td class="line-label">邮政编码</td>
<td><el-input class="custom-input" v-model="formData.postalCode" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.postalCode" /></td>
</tr>
<tr>
<td class="line-label">车牌号</td>
<td><el-input class="custom-input" v-model="formData.licensePlate" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.licensePlate" /></td>
<td class="line-label">车辆VIN码</td>
<td><el-input class="custom-input" v-model="formData.vehicleVin" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.vehicleVin" /></td>
</tr>
<tr>
<td class="line-label">投入使用日期</td>
<td><el-input class="custom-input" v-model="formData.commissionDate" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.commissionDate" /></td>
<td class="line-label">单位固定电话</td>
<td> <el-input class="custom-input" v-model="formData.telephone" /></td>
<td> <el-input :disabled="disabled" class="custom-input" v-model="formData.telephone" /></td>
</tr>
<tr>
<td class="line-label">安全管理员</td>
<td><el-input class="custom-input" v-model="formData.safetyManager" /></td>
<td><el-input :disabled="disabled" class="custom-input" v-model="formData.safetyManager" /></td>
<td class="line-label">移动电话</td>
<td> <el-input class="custom-input" v-model="formData.mobilePhone" /></td>
<td> <el-input :disabled="disabled" class="custom-input" v-model="formData.mobilePhone" /></td>
</tr>
<tr>
<td class="dark-text" colspan="5">
@ -111,7 +111,7 @@
</table>
<div class="dark-text tation">本式样适用于车用气瓶使用登记</div>
<div class="footer">
<el-button type="primary" @click="exportToWord">导出为Word</el-button>
<el-button type="primary" @click="handleSubmit">{{disabled?'下载':'保存并下载'}}</el-button>
</div>
</div>
</template>
@ -121,16 +121,22 @@
import JSZipUtils from 'jszip-utils' //JS
import Docxtemplater from 'docxtemplater'
import { saveAs } from 'file-saver'
import * as TicketSortApi from '@/api/ticketing/ticketsort'
export default {
props: {
initialData: {
type: Object,
default: () => ({})
},
disabled:{
type: Boolean,
default: false
}
},
data() {
return {
isout:false,
formData: {
"registrationCategory": "",//
"equipmentType": "",//
@ -169,10 +175,74 @@
},
created() {
if (this.initialData) {
if(this.initialData.infoList.length <3){
const requiredLength = 3;
const emptyItem = {
manufacturer: '',
productionDate: '',
productId: '',
internalId: ''
};
while (this.initialData.infoList.length < requiredLength) {
this.initialData.infoList.push({ ...emptyItem });
}
}
this.formData = { ...this.initialData }
}
},
methods: {
async handleSubmit() {
debugger
if(!this.isout){
this.exportToWord()
}
if(this.disabled){
this.exportToWord()
}
if(!this.disabled){
try {
console.log(this.formData)
let appendDate = {...this.formData}
//
appendDate.manufacturer = "XX制造有限公司"
appendDate.productionDate = "2025-04-11"
appendDate.productId = new Date().getTime();
appendDate.internalId = new Date().toLocaleDateString().split('/').join('-')
//
if(appendDate.infoList.length <3){
const requiredLength = 3;
const emptyItem = {
manufacturer: '',
productionDate: '',
productId: '',
internalId: ''
};
while (appendDate.infoList.length < requiredLength) {
appendDate.infoList.push({ ...emptyItem });
}
}
appendDate.infoList = JSON.stringify(appendDate.infoList)
await TicketSortApi.createOcr(appendDate).then(res => {
console.log(res)
if (res.code === 0) {
this.$modal.msgSuccess('记录保存成功')
this.$tab.closeAllPage();
const ss = { path: "/report/eventList/index", name: "事项清单" };
this.$tab.refreshPage(ss);
}else{
this.$modal.msgError('记录保存失败')
}
})
} catch (error) {
console.log(error)
} finally {
this.$modal.closeLoading();
}
}
},
async exportToWord() {
// public/templates
let _this = this;
@ -180,7 +250,6 @@
//
JSZipUtils.getBinaryContent("/templates/template.docx", function (error, content) {
debugger
// input.docx
//
if (error) {
@ -221,13 +290,8 @@
});
//
saveAs(out, "特种设备使用登记表(式样二).docx");
_this.$modal.closeLoading();
_this.$modal.notify("文件已导出,请注意查看浏览器下载的文件");
setTimeout(() => {
_this.$tab.closeAllPage();
const ss = { path: "/eventList", name: "事项清单" };
_this.$tab.refreshPage(ss);
}, 2000);
_this.isout = true
});
// this.$tab.closeAllPage();
// const ss = { path: "/eventList", name: "" };
@ -351,4 +415,8 @@
line-height: 24px;
border: none;
}
.custom-input.is-disabled .el-input__inner{
color: #000;
background-color: transparent;
}
</style>

@ -53,13 +53,20 @@
<div v-if="Object.keys(formData).length === 0">Loading data...</div>
<EquipmentRegistrationForm v-else :initialData="formData" />
</div>
<div class="masks" v-if="progress.visible">
<div class="progress-box">
<i class="el-icon-loading"></i>
<div>{{ progress.text }}</div>
</div>
</div>
</div>
</template>
<script>
import EquipmentRegistrationForm from './EquipmentRegistrationForm.vue'
import pdf from 'vue-pdf';
import * as TicketSortApi from '@/api/ticketing/ticketsort'
import axios from 'axios'
export default {
components: { EquipmentRegistrationForm, pdf },
data() {
@ -83,7 +90,15 @@
startY: 0, // Y
initialX: 0, // X
initialY: 0, // Y
centerOffset: { x: 0, y: 0 } //
centerOffset: { x: 0, y: 0 }, //
progress: {
visible: false,
current: 0,
total: 0,
text: ''
},
basicFiles:[],
usageFiles:[]
}
},
computed: {
@ -118,6 +133,8 @@
this.fileList = newFileList
console.log(newFileList)
this.bigView(newFileList[0])
this.basicFiles = [{ url: '1.pdf' }, { url: '1_营业执照.jpg' }]
this.usageFiles = [{ url: '1.pdf' }, { url: '1_行驶本.pdf' }]
this.mockFetchData()
},
methods: {
@ -128,7 +145,7 @@
this.rotate = (this.rotate - 90 + 360) % 360;
},
//
mockFetchData() {
async mockFetchData() {
setTimeout(() => {
this.formData = {
"registrationCategory": "首次启用",//
@ -138,10 +155,10 @@
"fillingMedium": "氧气",//
"nominalWorkingPressure": 1,//
"cylinderVolume": 1,//
"manufacturer": "XX制造有限公司",//
"productionDate": "2025-04-11",//
"productId": "SN123456",//
"internalId": "IN7890",//
// "manufacturer": "XX",//
// "productionDate": "2025-04-11",//
// "productId": "SN123453",//
// "internalId": "IN7890",//
"contractor": "XX工程公司",//
"supervisionAgency": "XX监督检验所",//
"userUnit": "XX科技有限公司",//使
@ -166,16 +183,60 @@
"productionDate": "2025-04-11",//
"productId": "SN123456",//
"internalId": "IN7890",//
},
{
"manufacturer": "",
"productionDate": "",//
"productId": "",//
"internalId": "",//
}
]
}
}, 1000) // 1
// try {
// this.progress = {
// visible: true,
// current: 0,
// total: this.basicFiles.length + this.usageFiles.length,
// text: '...'
// };
// //
// const createRequests = (apiPath,files ) => {
// return files.map(file => {
// //
// return axios.post(apiPath, { filePath: file.url })
// .then(res => {
// this.progress.current++;
// this.progress.text = ` ${this.progress.current}/${this.progress.total}`;
// return res.data;
// })
// .catch(e => {
// console.error(`${file.url}:`, e);
// this.progress.current++; //
// return null;
// });
// });
// };
// const [basicResults] = await Promise.all([
// Promise.all(createRequests(process.env.VUE_APP_BASE_API + '/analyze', this.basicFiles))
// ]);
// const [usageResults] = await Promise.all([
// Promise.all(createRequests(process.env.VUE_APP_BASE_API + '/analyze', this.usageFiles))
// ]);
// console.log(basicResults, usageResults)
// // 3.
// const merger = (results) => results.filter(Boolean).reduce((acc, cur) => ({
// ...acc,
// ...cur,
// infoList: [...(acc.infoList || []), ...(cur.infoList || [])]
// }), {});
// // 4. formDatamock
// const aa = {
// //
// ...[basicResults],
// ...[usageResults],
// };
// console.log(aa)
// } catch (error) {
// console.error(':', error);
// this.formData = {}; //
// } finally {
// this.progress.visible = false;
// }
},
bigView(val) {
this.showUrl = ''
@ -346,4 +407,29 @@
overflow-y: scroll;
}
}
.masks {
/* 原有样式保持不变 */
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
position: fixed;
z-index: 99999;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
.progress-box {
text-align: center;
font-size: 18px;
.el-icon-loading {
font-size: 40px;
margin-bottom: 10px;
}
}
}
</style>
Loading…
Cancel
Save