From 4fbdf4c6b13d19b9be54900b5dcff29e2ca7ef01 Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期二, 24 六月 2025 17:31:45 +0800
Subject: [PATCH] 巡查单据自动下载功能(待完成)
---
src/utils/doc.js | 25 ++
public/餐饮巡查单据模板.doc | 0
src/views/fysp/check/components/ArbitraryPhoto.vue | 36 ++++
src/views/fysp/task/components/CompMonitorObjEdit.vue | 2
src/components/FYImageSelectDialog.vue | 1
src/views/fysp/check/ProCheckProxy.js | 18 +-
src/views/fysp/check/components/CompSubTaskStatistic.vue | 42 ++++-
src/components.d.ts | 1
public/工地巡查单据模板.docx | 0
src/views/fysp/scene/SceneInspectFile.vue | 252 +++++++++++++++++++++++++++++++
src/views/fysp/task/components/CompSubTaskList.vue | 40 +++-
src/views/fysp/task/TaskManage.vue | 12 +
12 files changed, 388 insertions(+), 41 deletions(-)
diff --git "a/public/\345\267\245\345\234\260\345\267\241\346\237\245\345\215\225\346\215\256\346\250\241\346\235\277.docx" "b/public/\345\267\245\345\234\260\345\267\241\346\237\245\345\215\225\346\215\256\346\250\241\346\235\277.docx"
new file mode 100644
index 0000000..c1a8470
--- /dev/null
+++ "b/public/\345\267\245\345\234\260\345\267\241\346\237\245\345\215\225\346\215\256\346\250\241\346\235\277.docx"
Binary files differ
diff --git "a/public/\351\244\220\351\245\256\345\267\241\346\237\245\345\215\225\346\215\256\346\250\241\346\235\277.doc" "b/public/\351\244\220\351\245\256\345\267\241\346\237\245\345\215\225\346\215\256\346\250\241\346\235\277.doc"
new file mode 100644
index 0000000..b65f9c3
--- /dev/null
+++ "b/public/\351\244\220\351\245\256\345\267\241\346\237\245\345\215\225\346\215\256\346\250\241\346\235\277.doc"
Binary files differ
diff --git a/src/components.d.ts b/src/components.d.ts
index d9c2fb8..2b04de3 100644
--- a/src/components.d.ts
+++ b/src/components.d.ts
@@ -25,6 +25,7 @@
ElCard: typeof import('element-plus/es')['ElCard']
ElCascader: typeof import('element-plus/es')['ElCascader']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
+ ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
ElCol: typeof import('element-plus/es')['ElCol']
ElCollapse: typeof import('element-plus/es')['ElCollapse']
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
diff --git a/src/components/FYImageSelectDialog.vue b/src/components/FYImageSelectDialog.vue
index 6e283c3..4d2602a 100644
--- a/src/components/FYImageSelectDialog.vue
+++ b/src/components/FYImageSelectDialog.vue
@@ -56,6 +56,7 @@
:preview-src-list="
readonly ? typeImgMap.get(activeId).map((v) => v.url) : []
"
+ crossOrigin="Anonymous"
:initial-index="i"
@contextmenu="(e) => showContextMenu(e, i)"
@click="onSelect(img, i)"
diff --git a/src/utils/doc.js b/src/utils/doc.js
index 25115f2..a757cfc 100644
--- a/src/utils/doc.js
+++ b/src/utils/doc.js
@@ -81,10 +81,20 @@
let width = image.width;
let height = image.height;
- if (width > height && horizontalHeight && height > horizontalHeight && scale) {
+ if (
+ width > height &&
+ horizontalHeight &&
+ height > horizontalHeight &&
+ scale
+ ) {
height = horizontalHeight;
width = horizontalHeight * scale;
- } else if (width <= height && verticalWidth && width > verticalWidth && scale) {
+ } else if (
+ width <= height &&
+ verticalWidth &&
+ width > verticalWidth &&
+ scale
+ ) {
width = verticalWidth;
height = verticalWidth * scale;
}
@@ -144,12 +154,15 @@
throw error;
}
const zip = new Pizzip(content);
- const imageOptions = getImageOptions(imageSize);
let doc = new docxtemplater()
.setOptions({ paragraphLoop: true })
- .loadZip(zip)
- .attachModule(new ImageModule(imageOptions))
- .compile();
+ .loadZip(zip);
+
+ if (imageSize) {
+ const imageOptions = getImageOptions(imageSize);
+ doc.attachModule(new ImageModule(imageOptions));
+ }
+ doc.compile();
doc.resolveData(data).then(() => {
try {
doc.render();
diff --git a/src/views/fysp/check/ProCheckProxy.js b/src/views/fysp/check/ProCheckProxy.js
index 938422f..013e0c9 100644
--- a/src/views/fysp/check/ProCheckProxy.js
+++ b/src/views/fysp/check/ProCheckProxy.js
@@ -29,7 +29,7 @@
//鏈�氳繃鏁伴噺
unpassNum: 0,
//鏁存敼鐜�
- changePer: '0%',
+ changePer: '--',
//閫氳繃鐜�
passPer: '0%',
//瀹℃牳鐜�
@@ -49,10 +49,10 @@
status.uncheckNum++;
else status.passNum++;
- if (p.extension3 == proStatus.pass) {
+ if (p.extension3 != proStatus.unCheck) {
status.proCheckedNum++;
}
- if (p.extension3 == proStatus.change_pass) {
+ if (p.extension3 == proStatus.change_pass || p.extension3 == proStatus.change_fail) {
status.changeCheckedNum++;
}
@@ -234,18 +234,18 @@
else if (s.proCheckedNum < s.proNum) {
type = 2;
}
- // 鏈暣鏀�
- else if (s.changeNum < s.proNum) {
- type = 3;
- }
// 鏁存敼鏈鏍�
- else if (s.changeCheckedNum == 0) {
+ else if (s.changeNum > 0 && s.changeCheckedNum == 0) {
type = 4;
}
// 鏁存敼閮ㄥ垎瀹℃牳
- else if (s.changeCheckedNum < s.changeNum) {
+ else if (s.changeNum > 0 && s.changeCheckedNum < s.changeNum) {
type = 5;
}
+ // 鏈暣鏀�
+ else if (s.changeNum < s.proNum) {
+ type = 3;
+ }
// 瀹屽叏瀹℃牳
else {
type = 6;
diff --git a/src/views/fysp/check/components/ArbitraryPhoto.vue b/src/views/fysp/check/components/ArbitraryPhoto.vue
index 55b11a5..703ceda 100644
--- a/src/views/fysp/check/components/ArbitraryPhoto.vue
+++ b/src/views/fysp/check/components/ArbitraryPhoto.vue
@@ -74,6 +74,7 @@
// ],
closeContextMenuListenr: undefined,
// 鍙抽敭閫変腑鐨勫浘鐗�
+ selectedFileElement: undefined,
selectedFile: undefined,
selectedIndex: undefined,
selectedTypeId: undefined
@@ -94,7 +95,7 @@
};
});
return [
- // { label: '澶嶅埗鍥剧墖', action: 'copy' },
+ // { label: '澶嶅埗鍒板壀璐存澘', action: 'copy' },
{ label: '绉诲姩鍒�', children: items }
];
}
@@ -158,6 +159,7 @@
left: `${event.clientX}px`,
top: `${event.clientY}px`
};
+ this.selectedFileElement = event.target;
this.selectedTypeId = typeId;
this.selectedIndex = index;
this.selectedFile = this.typesMap.get(typeId)[index];
@@ -168,6 +170,7 @@
handleMenuItem(item) {
switch (item.action) {
case 'copy':
+ this.drawImageToCanvas();
break;
case 'move':
this.selectedFile.data.businesstypeid = item.value;
@@ -217,6 +220,37 @@
// }
// this.selectedFile.loading = false;
// }, 2000);
+ },
+ drawImageToCanvas() {
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+ const img = this.selectedFileElement; // 鑾峰彇DOM寮曠敤
+ // img.crossOrigin = 'Anonymous';
+ canvas.width = img.naturalWidth;
+ canvas.height = img.naturalHeight;
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
+ // this.copyCanvasToClipboard(canvas);
+ const dataUrl = canvas.toDataURL('image/png'); // 鍙互閫夋嫨鍏朵粬鏍煎紡濡�'image/jpeg'
+ // 鍒涘缓涓�涓复鏃剁殑textarea鍏冪礌鏉ュ鍒舵枃鏈�
+ const tempTextArea = document.createElement('textarea');
+ document.body.appendChild(tempTextArea);
+ tempTextArea.value = dataUrl;
+ tempTextArea.select();
+ document.execCommand('copy');
+ document.body.removeChild(tempTextArea);
+ },
+ copyCanvasToClipboard(canvas) {
+ canvas.toBlob((blob) => {
+ const item = new ClipboardItem({ 'image/png': blob }); // 浣犲彲浠ユ牴鎹渶瑕佹敼鍙樻牸寮忥紝濡� "image/jpeg"
+ navigator.clipboard.write([item]).then(
+ () => {
+ console.log('Image copied to clipboard');
+ },
+ (err) => {
+ console.error('Could not copy image: ', err);
+ }
+ );
+ }, 'image/png'); // 鍚屾牱锛岃繖閲屼篃鍙互鎸囧畾鍏朵粬鏍煎紡锛屽 'image/jpeg'
}
}
};
diff --git a/src/views/fysp/check/components/CompSubTaskStatistic.vue b/src/views/fysp/check/components/CompSubTaskStatistic.vue
index 7f8d3e9..7e30a44 100644
--- a/src/views/fysp/check/components/CompSubTaskStatistic.vue
+++ b/src/views/fysp/check/components/CompSubTaskStatistic.vue
@@ -269,17 +269,39 @@
completedTimes: 0,
reviewTimes: 0
};
- this.monitorObjList.forEach((m) => {
- if (this.sceneType == undefined || m.sceneTypeId == this.sceneType) {
- _res.total++;
- const times = parseInt(m.extension1);
- if (times) {
- _res.completedScenes++;
- _res.completedTimes += times;
- _res.reviewTimes += times - 1;
- }
+
+ // Fixme 2025.5.30: 鐩墠姝ゅ鐨勭洃绠$増鏈俊鎭挓璁板綍鐨勪换鍔″畬鎴愭鏁版湁鍋忓樊锛屾墍浠ユ殏鏃跺厛鏀逛负閫氳繃宸℃煡浠诲姟鏈韩杩涜缁熻
+ /**************************************************************************************/
+ // this.monitorObjList.forEach((m) => {
+ // if (this.sceneType == undefined || m.sceneTypeId == this.sceneType) {
+ // _res.total++;
+ // const times = parseInt(m.extension1);
+ // if (times) {
+ // _res.completedScenes++;
+ // _res.completedTimes += times;
+ // _res.reviewTimes += times - 1;
+ // }
+ // }
+ // });
+ /**************************************************************************************/
+
+ /**************************************************************************************/
+ _res.total = this.monitorObjList.filter(
+ (m) => this.sceneType == undefined || m.sceneTypeId == this.sceneType
+ ).length;
+ _res.completedTimes = this.subtasks.length;
+ const map = new Map();
+ const uniqueArr = [];
+ for (let item of this.subtasks) {
+ if (!map.has(item.data.sceneId)) {
+ map.set(item.data.sceneId, true);
+ uniqueArr.push(item);
}
- });
+ }
+ _res.completedScenes = uniqueArr.length;
+ _res.reviewTimes = _res.completedTimes - _res.completedScenes;
+
+ /**************************************************************************************/
return _res;
}
},
diff --git a/src/views/fysp/scene/SceneInspectFile.vue b/src/views/fysp/scene/SceneInspectFile.vue
new file mode 100644
index 0000000..ddd17c8
--- /dev/null
+++ b/src/views/fysp/scene/SceneInspectFile.vue
@@ -0,0 +1,252 @@
+<template>
+ <el-dialog
+ :model-value="modelValue"
+ @update:model-value="handleDialogChange"
+ title="宸℃煡鍗曟嵁涓嬭浇"
+ class="dialog-wrapper"
+ v-loading="loading"
+ >
+ <el-scrollbar
+ ref="scrollbarRef"
+ height="50vh"
+ v-loading="loading"
+ :always="true"
+ >
+ <el-checkbox-group v-model="checkList">
+ <el-space direction="vertical" alignment="flex-start" fill>
+ <el-checkbox
+ v-for="(item, index) in sceneInfoList"
+ :key="item.scense.guid"
+ :value="index"
+ :class="(item.invalid ? 'checkbox-invalid' : '') + ' checkbox'"
+ >
+ <div>
+ <el-text size="large">{{ item.scense.name }}</el-text>
+ </div>
+ <div class="m-t-4">
+ <el-text size="small">{{
+ '鍦板潃锛�' + item.scense.location
+ }}</el-text>
+ </div>
+ <el-space class="m-t-4">
+ <el-tag>
+ {{
+ item.scense.cityname +
+ item.scense.districtname +
+ item.scense.townname
+ }}
+ <!-- {{ item.scense.districtname }}
+ {{ item.scense.townname }} -->
+ </el-tag>
+ <el-tag>{{ item.scense.type }}</el-tag>
+
+ <!-- {{ item.scense.contacts }}
+ {{ item.scense.contactst }} -->
+ </el-space>
+ </el-checkbox>
+ </el-space>
+ </el-checkbox-group>
+ </el-scrollbar>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button type="danger" @click="cancel">鍙栨秷</el-button>
+ <el-button type="primary" :loading="docLoading" @click="handelDownload">
+ 涓嬭浇
+ </el-button>
+ <el-button type="default" :loading="docLoading" @click="handelPrint">
+ 鎵撳嵃
+ </el-button>
+ </div>
+ </template>
+ </el-dialog>
+</template>
+<script setup>
+/**
+ * 鍦烘櫙宸℃煡鍗曟嵁鑷姩涓嬭浇
+ */
+import { ref, watch } from 'vue';
+import { exportDocx } from '@/utils/doc';
+import sceneApi from '@/api/fysp/sceneApi';
+
+const props = defineProps({
+ // 瀵硅瘽妗嗗紑鍏�
+ modelValue: Boolean,
+ // 鍦烘櫙鍩虹淇℃伅鏁扮粍
+ value: Array
+});
+
+const emits = defineEmits(['update:modelValue']);
+
+const loading = ref(false);
+const scrollbarRef = ref();
+const sceneInfoList = ref([]);
+const checkList = ref([]);
+const docLoading = ref(false);
+
+watch(
+ () => [props.modelValue, props.value],
+ (nV, oV) => {
+ if (nV[0] && nV[1] && nV[1] != oV[1]) {
+ fetchSceneInfo(nV[1]);
+ }
+ }
+);
+
+function fetchSceneInfo(sceneIdList) {
+ loading.value = true;
+ sceneInfoList.value = [];
+ checkList.value = [];
+ sceneIdList.forEach((sid) => {
+ sceneApi
+ .getSceneDetail(sid)
+ .then((res) => {
+ sceneInfoList.value.push(res.data);
+ checkList.value.push(sceneInfoList.value.length - 1);
+
+ //鍦烘櫙
+ // if (res.data.scense) sceneInfoList.value = res.data.scense;
+ // if (res.data.subScene) {
+ // formSubScene.value = res.data.subScene;
+ // } else {
+ // formSubScene.value = {
+ // sGuid: formScene.value.guid
+ // };
+ // }
+ })
+ .finally(() => {
+ loading.value = false;
+ scrollbarRef.value.setScrollTop(0);
+ });
+ });
+}
+
+function handleDialogChange(value) {
+ emits('update:modelValue', value);
+}
+
+// 鏍煎紡鍖栧満鏅俊鎭紝鐢熸垚鍙傛暟缁撴瀯
+function parseParam() {
+ const selected = sceneInfoList.value.filter((v, i) => {
+ return checkList.value.indexOf(i) != -1;
+ });
+ const param = selected.map((v) => {
+ switch (v.scense.typeid) {
+ // 宸ュ湴
+ case 1:
+ return {
+ type: v.scense.typeid,
+ params: {
+ district: v.scense.districtname,
+ name: v.scense.name,
+ employerUnit: v.scense.csEmployerUnit,
+ constructionUnit: v.subScene.csConstructionUnit,
+ timeRange: v.subScene.csStartTime
+ ? `${v.subScene.csStartTime}鑷�${v.subScene.csEndTime}`
+ : undefined,
+ stage: v.subScene.siExtension1,
+ contacts: v.subScene.csConstructionContacts,
+ contactsTel: v.subScene.csConstructionContactsTel,
+ location: v.scense.location
+ }
+ };
+ // 椁愰ギ
+ case 5:
+ return {
+ type: v.scense.typeid,
+ params: {
+ district: v.scense.districtname,
+ location: v.scense.location,
+ name: v.scense.name,
+ contacts: v.scense.contacts,
+ contactsTel: v.scense.contactst
+ }
+ };
+ // default:
+ // v.invalid = true;
+ // return undefined;
+ }
+ });
+
+ param.forEach((p) => {
+ for (const key in p.params) {
+ let value = p.params[key];
+ if (value == undefined) {
+ // 鑻ュ睘鎬х己澶憋紝鍒欐敼涓�20涓┖鏍肩锛屽搴攚ord涓�10涓腑鏂囧瓧绗︾殑闀垮害
+ p.params[key] = ' ';
+ }
+ }
+ });
+
+ return param;
+}
+
+// 鏍规嵁鍦烘櫙绫诲瀷锛岀敓鎴愬搴旂殑word鏂囨。
+function generateDoc(param) {
+ param.forEach((p) => {
+ let template, _param;
+ switch (p.type) {
+ // 宸ュ湴
+ case 1:
+ template = '/宸ュ湴宸℃煡鍗曟嵁妯℃澘.docx';
+ _param = p.params;
+ break;
+ // 椁愰ギ
+ case 5:
+ break;
+ default:
+ break;
+ }
+
+ exportDocx(template, _param, `${_param.name}宸℃煡鍗曟嵁.docx`).finally(
+ () => (docLoading.value = false)
+ );
+ });
+}
+
+// 涓嬭浇word鏂囨。
+function download(file) {}
+
+// 鎵撳嵃word鏂囨。
+function print(file) {}
+
+function filePrepare() {
+ const param = parseParam();
+ if (param) {
+ return generateDoc(param);
+ }
+}
+
+// 鐐瑰嚮涓嬭浇鎸夐挳鎿嶄綔
+function handelDownload() {
+ const file = filePrepare();
+ if (file) {
+ download(file);
+ }
+}
+
+// 鐐瑰嚮鎵撳嵃鎸夐挳鎿嶄綔
+function handelPrint() {
+ const file = filePrepare();
+ if (file) {
+ print(file);
+ }
+}
+
+// 鍙栨秷鎿嶄綔
+function cancel() {
+ // 鍏抽棴瀵硅瘽妗�
+ handleDialogChange(false);
+}
+</script>
+<style scoped>
+.checkbox {
+ border: var(--el-border);
+ padding: 8px;
+}
+.checkbox-invalid {
+ border-color: var(--el-color-error);
+}
+:deep(.el-checkbox) {
+ height: auto;
+}
+</style>
diff --git a/src/views/fysp/task/TaskManage.vue b/src/views/fysp/task/TaskManage.vue
index f844b5e..24129b6 100644
--- a/src/views/fysp/task/TaskManage.vue
+++ b/src/views/fysp/task/TaskManage.vue
@@ -202,10 +202,16 @@
computed: {
// 鎬讳换鍔$姸鎬佺粺璁�
taskStatus() {
+ let total = 0,
+ inspected = 0;
+ this.curMonitorObjList.forEach((obj) => {
+ total += parseInt(obj.monitornum);
+ inspected += obj.extension1 ? parseInt(obj.extension1) : 0;
+ });
return [
- { name: '鍦烘櫙鏁�', value: 100 },
- { name: '鏈贰鏌�', value: 0 },
- { name: '宸插贰鏌�', value: 0 }
+ { name: '鍦烘櫙鏁�', value: total },
+ { name: '鏈贰鏌�', value: total - inspected },
+ { name: '宸插贰鏌�', value: inspected }
];
}
},
diff --git a/src/views/fysp/task/components/CompMonitorObjEdit.vue b/src/views/fysp/task/components/CompMonitorObjEdit.vue
index 517f03b..cccd5ea 100644
--- a/src/views/fysp/task/components/CompMonitorObjEdit.vue
+++ b/src/views/fysp/task/components/CompMonitorObjEdit.vue
@@ -274,7 +274,7 @@
});
},
deleteMov(item) {
- if (item.extension1) {
+ if (!(item.extension1 == null || item.extension1 == undefined || item.extension1 == '0')) {
ElMessage({
message: '宸茬洃绠″満鏅棤娉曠Щ闄�',
type: 'error'
diff --git a/src/views/fysp/task/components/CompSubTaskList.vue b/src/views/fysp/task/components/CompSubTaskList.vue
index 03ef062..2ff7199 100644
--- a/src/views/fysp/task/components/CompSubTaskList.vue
+++ b/src/views/fysp/task/components/CompSubTaskList.vue
@@ -1,13 +1,22 @@
<template>
<el-row justify="space-between">
<el-text>鍗曟棩璁″垝</el-text>
- <el-button
- v-show="create && data && data.length > 0"
- type="success"
- size="small"
- @click="add"
- >浠诲姟璋冩暣</el-button
- >
+ <div>
+ <el-button
+ type="success"
+ size="small"
+ plain
+ @click="handleInspectFileDownload"
+ >鍗曟嵁涓嬭浇</el-button
+ >
+ <el-button
+ v-show="create && data && data.length > 0"
+ type="success"
+ size="small"
+ @click="add"
+ >浠诲姟璋冩暣</el-button
+ >
+ </div>
</el-row>
<el-divider />
<div>
@@ -70,11 +79,13 @@
@cancel="dialogVisible = false"
></CompSubTaskEdit>
</el-dialog>
+ <SceneInspectFile v-model="downloadDialog" :value="downloadSceneList"></SceneInspectFile>
</template>
<script setup>
import { ref, computed, watch, onMounted, onUnmounted } from 'vue';
import { ElMessageBox, ElNotification, ElMessage } from 'element-plus';
import CompSubTaskEdit from './CompSubTaskEdit.vue';
+import SceneInspectFile from "@/views/fysp/scene/SceneInspectFile.vue";
import subtaskApi from '@/api/fysp/subtaskApi';
const props = defineProps({
@@ -86,12 +97,14 @@
// 鏄惁鏄剧ず娣诲姞浠诲姟鎸夐挳
create: Boolean,
loading: Boolean,
- createLoading:Boolean,
+ createLoading: Boolean
});
const dialogVisible = ref(false);
const activeItem = ref(null);
const data = computed(() => props.modelValue);
+const downloadDialog = ref(false);
+const downloadSceneList = ref([])
const emit = defineEmits(['submit', 'add', 'remove', 'update:modelValue']);
@@ -102,7 +115,7 @@
cancelButtonText: '鍙栨秷',
type: 'warning'
}).then(() => {
- return subtaskApi.deleteSubtask(item.stguid).then(res=>{
+ return subtaskApi.deleteSubtask(item.stguid).then((res) => {
if (res == 1) {
const index = data.value.indexOf(item);
data.value.splice(index, 1);
@@ -110,9 +123,9 @@
emit('update:modelValue', data.value);
emit('remove', item);
} else {
- Promise.reject('鍒犻櫎宸℃煡浠诲姟澶辫触')
+ Promise.reject('鍒犻櫎宸℃煡浠诲姟澶辫触');
}
- })
+ });
});
}
}
@@ -139,4 +152,9 @@
onUnmounted(() => {
dialogVisible.value = false;
});
+
+function handleInspectFileDownload() {
+ downloadSceneList.value = data.value.map(v=>v.scenseid)
+ downloadDialog.value = true
+}
</script>
--
Gitblit v1.9.3