From 2323c93baf009d2f60acaec545622611673203cb Mon Sep 17 00:00:00 2001 From: gaoluyang <2820782392@qq.com> Date: 星期三, 18 六月 2025 16:48:13 +0800 Subject: [PATCH] 1.巡检上传页面开发、联调 --- src/views/salesOutbound/index.vue | 2 src/api/inspectionManagement/index.js | 27 ++ src/main.js | 2 src/views/inspectionUpload/index.vue | 100 ++++++++++ package.json | 6 src/views/inspectionUpload/components/formDia.vue | 158 +++++++++++++++ src/views/inspectionManagement/components/formDia.vue | 96 +++++++++ src/views/inspectionManagement/index.vue | 50 +++-- src/views/inspectionManagement/components/qrCodeDia.vue | 113 +++++++++++ 9 files changed, 532 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index 3548462..d916e6c 100644 --- a/package.json +++ b/package.json @@ -16,13 +16,14 @@ "url": "https://gitee.com/y_project/RuoYi-Vue.git" }, "dependencies": { + "@chenfengyuan/vue-qrcode": "^2.0.0", "@element-plus/icons-vue": "2.3.1", "@vueup/vue-quill": "1.2.0", "@vueuse/core": "10.11.0", "axios": "0.28.1", "clipboard": "2.0.11", - "echarts": "5.5.1", "default-passive-events": "^4.0.0", + "echarts": "5.5.1", "element-china-area-data": "^6.1.0", "element-plus": "2.7.6", "file-saver": "2.0.5", @@ -32,9 +33,12 @@ "jsencrypt": "3.3.2", "nprogress": "0.2.0", "pinia": "2.1.7", + "print-js": "^1.6.0", + "qrcode": "^1.5.4", "splitpanes": "3.1.5", "vue": "3.4.31", "vue-cropper": "1.1.1", + "vue-qrcode": "^2.2.2", "vue-router": "4.4.0", "vuedraggable": "4.1.0" }, diff --git a/src/api/inspectionManagement/index.js b/src/api/inspectionManagement/index.js new file mode 100644 index 0000000..0fb8caf --- /dev/null +++ b/src/api/inspectionManagement/index.js @@ -0,0 +1,27 @@ +// 宸℃绠$悊 +import request from '@/utils/request' + +// 宸℃浠诲姟琛ㄨ〃鏌ヨ +export function inspectionTaskList(query) { + return request({ + url: '/inspectionTask/list', + method: 'get', + params: query + }) +} +// 宸℃浠诲姟琛ㄦ柊澧炰慨鏀� +export function addOrEditInspectionTask(query) { + return request({ + url: '/inspectionTask/addOrEditInspectionTask', + method: 'post', + data: query + }) +} +// 宸℃浠诲姟琛ㄦ柊澧炰慨鏀� +export function delInspectionTask(query) { + return request({ + url: '/inspectionTask/delInspectionTask', + method: 'delete', + data: query + }) +} \ No newline at end of file diff --git a/src/main.js b/src/main.js index 117280e..5fb87f2 100644 --- a/src/main.js +++ b/src/main.js @@ -45,6 +45,7 @@ import DictTag from '@/components/DictTag' import {summarizeTable} from "@/utils/summarizeTable.js"; import {getCurrentDate} from "@/utils/getCurrentDate.js"; +import VueQrcode from '@chenfengyuan/vue-qrcode'; const app = createApp(App) @@ -68,6 +69,7 @@ app.component('ImagePreview', ImagePreview) app.component('RightToolbar', RightToolbar) app.component('Editor', Editor) +app.component('vue-qrcode', VueQrcode) app.use(router) app.use(store) diff --git a/src/views/inspectionManagement/components/formDia.vue b/src/views/inspectionManagement/components/formDia.vue new file mode 100644 index 0000000..8da91ef --- /dev/null +++ b/src/views/inspectionManagement/components/formDia.vue @@ -0,0 +1,96 @@ +<template> + <div> + <el-dialog :title="operationType === 'add' ? '鏂板宸℃浠诲姟' : '缂栬緫閿�鍞嚭搴�'" + v-model="dialogVisitable" width="800px" @close="cancel"> + <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> + <el-row> + <el-col :span="12"> + <el-form-item label="浠诲姟鍚嶇О" prop="taskName"> + <el-input v-model="form.taskName" placeholder="璇疯緭鍏ヤ换鍔″悕绉�" maxlength="30" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="鍦扮偣" prop="port"> + <el-input v-model="form.port" placeholder="璇疯緭鍏ュ湴鐐�" maxlength="30" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="12"> + <el-form-item label="宸℃浜�" prop="inspector"> + <el-input v-model="form.inspector" placeholder="宸℃浜�" maxlength="30" /> + </el-form-item> + </el-col> + <el-col :span="12"> + <el-form-item label="澶囨敞" prop="remarks"> + <el-input v-model="form.remarks" placeholder="璇疯緭鍏ュ娉�" type="textarea" /> + </el-form-item> + </el-col> + </el-row> + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button @click="cancel">鍙栨秷</el-button> + <el-button type="primary" @click="submitForm">淇濆瓨</el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup> +import {reactive, ref} from "vue"; +import useUserStore from '@/store/modules/user' +import {addOrEditInspectionTask} from "@/api/inspectionManagement/index.js"; + +const { proxy } = getCurrentInstance() +const emit = defineEmits() +const userStore = useUserStore() +const dialogVisitable = ref(false); +const operationType = ref('add'); +const data = reactive({ + form: { + taskName: '', + port: '', + inspector: '', + remarks: '', + }, + rules: { + taskName: [{ required: true, message: "璇疯緭鍏ヤ换鍔″悕绉�", trigger: "blur" },], + port: [{ required: true, message: "璇疯緭鍏ュ湴鐐�", trigger: "blur" },], + inspector: [{ required: true, message: "璇疯緭鍏ュ贰妫�浜�", trigger: "blur" },], + } +}) + +const { form, rules } = toRefs(data) + +// 鎵撳紑寮规 +const openDialog = async (type, row) => { + dialogVisitable.value = true + if (type === 'edit') { + form.value = {...row} + } +} +// 鎻愪氦鍚堝苟琛ㄥ崟 +const submitForm = () => { + proxy.$refs["formRef"].validate(valid => { + if (valid) { + addOrEditInspectionTask(form.value).then(() => { + cancel() + proxy.$modal.msgSuccess('鎻愪氦鎴愬姛') + }) + } + }) +} +// 鍏抽棴鍚堝苟琛ㄥ崟 +const cancel = () => { + proxy.resetForm("formRef") + dialogVisitable.value = false + emit('closeDia') +} +defineExpose({ openDialog }) +</script> + +<style scoped> + +</style> \ No newline at end of file diff --git a/src/views/inspectionManagement/components/qrCodeDia.vue b/src/views/inspectionManagement/components/qrCodeDia.vue new file mode 100644 index 0000000..119d9c5 --- /dev/null +++ b/src/views/inspectionManagement/components/qrCodeDia.vue @@ -0,0 +1,113 @@ +<template> + <div> + <el-dialog :title="operationType === 'add' ? '鏂板浜岀淮鐮�' : '缂栬緫浜岀淮鐮�'" + v-model="dialogVisitable" width="500px" @close="cancel"> + <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> + <el-row> + <el-col :span="24"> + <el-form-item label="璁惧鍚嶇О" prop="name"> + <el-input v-model="form.name" placeholder="璇疯緭鍏ヨ澶囧悕绉�" maxlength="30" /> + </el-form-item> + </el-col> + </el-row> + <el-row> + <el-col :span="24"> + <el-form-item label="鍦扮偣" prop="taxTrans"> + <el-input v-model="form.taxTrans" placeholder="璇疯緭鍏ュ湴鐐�" maxlength="30"/> + </el-form-item> + </el-col> + </el-row> + </el-form> + <div> + <el-button type="primary" @click="submitForm">鐢熸垚骞舵墦鍗颁簩缁寸爜</el-button> + </div> + <div v-if="isShowQrCode" class="print-section" ref="qrCodeContainer" id="qrCodeContainer"> + <vue-qrcode :value="qrCodeValue" :width="qrCodeSize"></vue-qrcode> + </div> + </el-dialog> + </div> +</template> + +<script setup> +import useUserStore from "@/store/modules/user.js"; +import {reactive, ref} from "vue"; +import printJS from 'print-js'; // 寮曞叆 print.js + +const { proxy } = getCurrentInstance() +const emit = defineEmits() +const userStore = useUserStore() +const dialogVisitable = ref(false); +const isShowQrCode = ref(false); +const operationType = ref('add'); + +const qrCodeValue = ref('https://example.com'); +const qrCodeSize = ref(100); +const data = reactive({ + form: { + name: '', + taxTrans: '', + }, + rules: { + name: [{ required: true, message: '璇疯緭鍏ヨ澶囧悕绉�', trigger: 'blur' }], + taxTrans: [{ required: true, message: '璇疯緭鍏ュ湴鐐�', trigger: 'blur' }] + } +}) +const { form, rules } = toRefs(data) + + +// 鎵撳紑寮规 +const openDialog = async (type, row) => { + dialogVisitable.value = true +} +// 鎻愪氦鍚堝苟琛ㄥ崟 +const submitForm = () => { + proxy.$refs["formRef"].validate(valid => { + if (valid) { + // 灏嗚〃鍗曟暟鎹浆涓� JSON 瀛楃涓蹭綔涓轰簩缁寸爜鍐呭 + qrCodeValue.value = JSON.stringify(form.value); + isShowQrCode.value = true; + + // 寤惰繜鎵ц鎵撳嵃锛岄伩鍏� DOM 鏇存柊鍓嶅氨璋冪敤鎵撳嵃 + setTimeout(() => { + printJS({ + printable: 'qrCodeContainer',//椤甸潰 + type: "html",//鏂囨。绫诲瀷 + maxWidth: 360, + style: `@page { + margin:0; + size: 400px 75px collapse; + margin-top:3px; + &:first-of-type{ + margin-top:0 !important; + } + } + html{ + zoom:100%; + } + @media print{ + width: 400px; + height: 75px; + margin:0; + }`, + targetStyles: ["*"], // 浣跨敤dom鐨勬墍鏈夋牱寮忥紝寰堥噸瑕� + font_size: '0.20cm', + }); + }, 300); + } + }) +} +// 鍏抽棴鍚堝苟琛ㄥ崟 +const cancel = () => { + proxy.resetForm("formRef") + dialogVisitable.value = false + emit('closeDia') +} +defineExpose({ openDialog }) +</script> + +<style scoped> +.print-section { + text-align: center; + margin-top: 30px; +} +</style> \ No newline at end of file diff --git a/src/views/inspectionManagement/index.vue b/src/views/inspectionManagement/index.vue index e3eaff1..bb313fd 100644 --- a/src/views/inspectionManagement/index.vue +++ b/src/views/inspectionManagement/index.vue @@ -63,15 +63,23 @@ /> </div> </el-card> + <form-dia ref="formDia" @closeDia="handleQuery"></form-dia> + <qr-code-dia ref="qrCodeDia" @closeDia="handleQuery"></qr-code-dia> </div> </template> <script setup> import {Download, Delete, Plus} from "@element-plus/icons-vue"; import {onMounted, ref} from "vue"; +const { proxy } = getCurrentInstance() import Pagination from "@/components/Pagination/index.vue"; import ETable from "@/components/Table/ETable.vue"; +import FormDia from "@/views/inspectionManagement/components/formDia.vue"; +import QrCodeDia from "@/views/inspectionManagement/components/qrCodeDia.vue"; +import {delInspectionTask, inspectionTaskList} from "@/api/inspectionManagement/index.js"; +const formDia = ref() +const qrCodeDia = ref() // 鏌ヨ鍙傛暟 const queryParams = reactive({ supplierName: "", @@ -79,7 +87,7 @@ }) // 褰撳墠鏍囩 const activeTab = ref("task"); -const tabName = ref("qrCode"); +const tabName = ref("task"); // 鏍囩椤垫暟鎹� const tabs = reactive([ { name: "task", label: "浠诲姟涓嬪彂" }, @@ -93,22 +101,12 @@ const pageNum = ref(1); const pageSize = ref(10); const columns = ref([ - { prop: "saleDate", label: "閿�鍞棩鏈�", minWidth: 160 }, - { prop: "customer", label: "瀹㈡埛", minWidth: 120 }, - { prop: "coal", label: "鐓ょ", minWidth: 150 }, - { prop: "unit", label: "鍗曚綅", minWidth: 150 }, - { prop: "priceIncludingTax", label: "鍗曚环(鍚◣)", minWidth: 150 }, - { prop: "inventoryQuantity", label: "搴撳瓨鏁伴噺", minWidth: 120 }, - { prop: "saleQuantity", label: "閿�鍞暟閲�", minWidth: 120 }, - { prop: "salePrice", label: "閿�鍞崟浠�(鍚◣)", minWidth: 150 }, - { prop: "totalAmount", label: "閿�鍞�讳环(鍚◣)", minWidth: 120 }, - { prop: "freight", label: "杩愯垂", minWidth: 90 }, - { prop: "taxCoal", label: "璐攢鐓ょ◣鐜�(%)", minWidth: 120 }, - { prop: "taxTrans", label: "杩愯緭绋庣巼(%)", minWidth: 120 }, - { prop: "grossProfit", label: "姣涘埄娑�", minWidth: 90 }, - { prop: "netProfit", label: "鍑�鍒╂鼎", minWidth: 90 }, + { prop: "taskName", label: "宸℃浠诲姟鍚嶇О", minWidth: 160 }, + { prop: "port", label: "鍦扮偣", minWidth: 120 }, + { prop: "remarks", label: "澶囨敞", minWidth: 150 }, + { prop: "inspector", label: "鎵ц宸℃浜�", minWidth: 150 }, { prop: "registrant", label: "鐧昏浜�", minWidth: 100 }, - { prop: "registrationDate", label: "鐧昏鏃ユ湡", minWidth: 100 }, + { prop: "createTime", label: "鐧昏鏃ユ湡", minWidth: 100 }, ]); onMounted(() => { @@ -127,8 +125,13 @@ getList() } const getList = () => { - // tableLoading.value = true; - + tableLoading.value = true; + inspectionTaskList({...queryParams, size: pageSize.value, current: pageNum.value}).then(res => { + console.log(res) + tableLoading.value = false; + tableData.value = res.data.records; + total.value = res.data.total; + }) }; // 閲嶇疆鏌ヨ const resetQuery = () => { @@ -142,7 +145,14 @@ // 鏂板銆佺紪杈� const handleAdd = (row) => { - + const type = row === undefined ? 'add' : 'edit' + nextTick(() => { + if (tabName.value === "task") { + formDia.value?.openDialog(type, row) + } else { + qrCodeDia.value?.openDialog(type, row) + } + }) }; // 鍒犻櫎浠诲姟 const handleDelete = () => { @@ -152,7 +162,7 @@ } const deleteIds = selectedRows.value.map(item => item.id); proxy.$modal.confirm('鏄惁纭鍒犻櫎鎵�閫夋暟鎹」锛�').then(function() { - return delSalesRecord(deleteIds) + return delInspectionTask(deleteIds) }).then(() => { handleQuery() proxy.$modal.msgSuccess("鍒犻櫎鎴愬姛") diff --git a/src/views/inspectionUpload/components/formDia.vue b/src/views/inspectionUpload/components/formDia.vue new file mode 100644 index 0000000..8889657 --- /dev/null +++ b/src/views/inspectionUpload/components/formDia.vue @@ -0,0 +1,158 @@ +<template> + <div> + <el-dialog title="涓婁紶" + v-model="dialogVisitable" width="400px" @close="cancel"> + <el-form :model="form" ref="formRef" label-width="120px"> + <el-form-item label="鐢熶骇鍓�" prop="fileList0"> + <el-upload + v-model:file-list="fileList0" + ref="fileUpload0" + :action="uploadFileUrl" + multiple + name="files" + :data="{type: 0}" + style="width: 100%" + :headers="headers" + :before-upload="handleBeforeUpload" + :on-success="handleUploadSuccess" + > + <el-button type="primary">涓婁紶</el-button> + </el-upload> + </el-form-item> + <el-form-item label="鐢熶骇鍚�" prop="fileList1"> + <el-upload + v-model:file-list="fileList1" + ref="fileUpload1" + :action="uploadFileUrl" + multiple + name="files" + :data="{type: 1}" + style="width: 100%" + :headers="headers" + :before-upload="handleBeforeUpload" + :on-success="handleUploadSuccess1" + > + <el-button type="primary">涓婁紶</el-button> + </el-upload> + </el-form-item> + <el-form-item label="鐢熶骇闂" prop="fileList2"> + <el-upload + v-model:file-list="fileList2" + ref="fileUpload2" + :action="uploadFileUrl" + multiple + name="files" + :data="{type: 2}" + style="width: 100%" + :headers="headers" + :before-upload="handleBeforeUpload" + :on-success="handleUploadSuccess2" + > + <el-button type="primary">涓婁紶</el-button> + </el-upload> + </el-form-item> + </el-form> + <template #footer> + <div class="dialog-footer"> + <el-button @click="cancel">鍙栨秷</el-button> + <el-button type="primary" @click="submitForm">淇濆瓨</el-button> + </div> + </template> + </el-dialog> + </div> +</template> + +<script setup> +import {reactive, ref} from "vue"; +import {addOrEditInspectionTask} from "@/api/inspectionManagement/index.js"; +import {getToken} from "@/utils/auth.js"; + +const { proxy } = getCurrentInstance() +const emit = defineEmits() +const dialogVisitable = ref(false); +const data = reactive({ + form: { + id: '', + storageBlobDTO: {} + }, +}) + +const { form } = toRefs(data) +const fileList0 = ref([]) +const fileList1 = ref([]) +const fileList2 = ref([]) +const uploadFileUrl = ref(import.meta.env.VITE_APP_BASE_API + '/common/minioUploads'); // 涓婁紶鏂囦欢鏈嶅姟鍣ㄥ湴鍧� +const headers = ref({ Authorization: "Bearer " + getToken() }); + +// 鎵撳紑寮规 +const openDialog = async (row) => { + dialogVisitable.value = true + form.value.id = row.id +} +// 涓婁紶鍓嶆牎妫�鏍煎紡鍜屽ぇ灏� +function handleBeforeUpload(file) { + + return true +} +// 涓婁紶鎴愬姛鍥炶皟 +function handleUploadSuccess(res, file) { + if (res.code === 200) { + console.log("涓婁紶鎴愬姛", res); + proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛"); + console.log('fileList0---', fileList0) + } else { + proxy.$modal.msgError(res.msg) + proxy.$refs.fileUpload0.handleRemove(file) + } +} +function handleUploadSuccess1(res, file) { + if (res.code === 200) { + proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛"); + } else { + proxy.$modal.msgError(res.msg) + proxy.$refs.fileUpload1.handleRemove(file) + } +} +function handleUploadSuccess2(res, file) { + if (res.code === 200) { + proxy.$modal.msgSuccess("鏂囦欢涓婁紶鎴愬姛"); + } else { + proxy.$modal.msgError(res.msg) + proxy.$refs.fileUpload2.handleRemove(file) + } +} + +// 鎻愪氦鍚堝苟琛ㄥ崟 +const submitForm = () => { + proxy.$refs["formRef"].validate(valid => { + if (valid) { + // 鍒濆鍖� storageBlobDTO 涓轰竴涓┖鏁扮粍 + form.value.storageBlobDTO = [] + // 鍚堝苟鎵�鏈� fileList 鍒� storageBlobDTO + const allFiles = [ + ...fileList0.value, + ...fileList1.value, + ...fileList2.value + ] + // 灏嗘枃浠跺垪琛ㄨ祴鍊肩粰 form + form.value.storageBlobDTO = allFiles + // 鎻愪氦鏁版嵁 + addOrEditInspectionTask(form.value).then(() => { + cancel() + proxy.$modal.msgSuccess('鎻愪氦鎴愬姛') + }) + } + }) +} +// 鍏抽棴鍚堝苟琛ㄥ崟 +const cancel = () => { + proxy.resetForm("formRef") + dialogVisitable.value = false + emit('closeDia') +} +defineExpose({ openDialog }) +</script> + +<style scoped> + +</style> \ No newline at end of file diff --git a/src/views/inspectionUpload/index.vue b/src/views/inspectionUpload/index.vue new file mode 100644 index 0000000..762d39a --- /dev/null +++ b/src/views/inspectionUpload/index.vue @@ -0,0 +1,100 @@ +<template> + <div class="app-container"> + <el-card> + <!-- 鏍囩椤� --> + <el-tabs + v-model="activeTab" + class="info-tabs" + @tab-click="handleTabClick" + > + <el-tab-pane + v-for="tab in tabs" + :key="tab.name" + :label="tab.label" + :name="tab.name" + /> + </el-tabs> + <div> + <div> + <el-table ref="table" :data="tableData" height="480" v-loading="tableLoading"> + <el-table-column label="搴忓彿" type="index" width="60" align="center" /> + <el-table-column prop="taskName" label="宸℃浠诲姟鍚嶇О" :show-overflow-tooltip="true"></el-table-column> + <el-table-column prop="port" label="鍦扮偣" :show-overflow-tooltip="true"></el-table-column> + <el-table-column prop="remarks" label="澶囨敞"></el-table-column> + <el-table-column prop="inspector" label="鎵ц宸℃浜�"></el-table-column> + <el-table-column fixed="right" label="鎿嶄綔"> + <template #default="scope"> + <el-button link type="primary" @click="handleAdd(scope.row)">涓婁紶</el-button> + </template> + </el-table-column> + </el-table> + </div> + <pagination + v-if="total>0" + :page-num="pageNum" + :page-size="pageSize" + :total="total" + @pagination="handleQuery" + :layout="'total, prev, pager, next, jumper'" + /> + </div> + </el-card> + <form-dia ref="formDia" @closeDia="handleQuery"></form-dia> + </div> +</template> + +<script setup> +import Pagination from "@/components/Pagination/index.vue"; +import {inspectionTaskList} from "@/api/inspectionManagement/index.js"; +import {onMounted, ref} from "vue"; +import FormDia from "@/views/inspectionUpload/components/formDia.vue"; +const formDia = ref() +// 褰撳墠鏍囩 +const activeTab = ref("task"); +const tabName = ref("task"); +// 鏍囩椤垫暟鎹� +const tabs = reactive([ + { name: "task", label: "浠诲姟涓嬪彂" }, + { name: "qrCode", label: "浜岀淮鐮佺鐞�" }, +]); +// 琛ㄦ牸 +const tableData = ref([]); +const tableLoading = ref(false); +const total = ref(0); +const pageNum = ref(1); +const pageSize = ref(10); + +onMounted(() => { + handleTabClick({ props: { name: "task" } }); +}); +// 鏍囩椤电偣鍑� +const handleTabClick = (tab) => { + tabName.value = tab.props.name; + tableData.value = []; + getList(); +}; +// 鐐瑰嚮鏌ヨ +const handleQuery = () => { + pageNum.value = 1 + pageSize.value = 10 + getList() +} +const getList = () => { + tableLoading.value = true; + inspectionTaskList({size: pageSize.value, current: pageNum.value}).then(res => { + tableLoading.value = false; + tableData.value = res.data.records; + total.value = res.data.total; + }) +}; +// 涓婁紶 +const handleAdd = (row) => { + nextTick(() => { + formDia.value?.openDialog(row) + }) +} +</script> + +<style scoped> + +</style> \ No newline at end of file diff --git a/src/views/salesOutbound/index.vue b/src/views/salesOutbound/index.vue index 1c28393..39c3d28 100644 --- a/src/views/salesOutbound/index.vue +++ b/src/views/salesOutbound/index.vue @@ -79,7 +79,7 @@ import ETable from "@/components/Table/ETable.vue"; import Pagination from "@/components/Pagination/index.vue"; import FormDia from "@/views/salesOutbound/components/formDia.vue"; -import {delSalesRecord, salesRecordList} from "../../api/salesOutbound/index.js"; +import {delSalesRecord, salesRecordList} from "@/api/salesOutbound/index.js"; const formDia = ref() const activeTab = ref("out"); -- Gitblit v1.9.3