| | |
| | | }) |
| | | |
| | | // 详æ
模å¼ä¸å±ç¤ºâ确认âæé®ï¼å
¶å®ç±»åæ£å¸¸æ¾ç¤º |
| | | const showConfirm = computed(() => props.operationType !== 'detail') |
| | | const showConfirm = computed(() => props.operationType !== 'detail' && props.operationType !== 'view') |
| | | |
| | | const computedTitle = computed(() => { |
| | | if (typeof props.title === 'function') { |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form" style="margin-bottom: 20px;"> |
| | | <div class="search_form" |
| | | style="margin-bottom: 20px;"> |
| | | <div> |
| | | <span class="search_title">客æ·åç§°ï¼</span> |
| | | <el-input v-model="searchForm.customerName" |
| | |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitReminderForm">确认</el-button> |
| | | <el-button type="primary" |
| | | @click="submitReminderForm">确认</el-button> |
| | | <el-button @click="closeReminderDialog">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitNegotiationForm">确认</el-button> |
| | | <el-button type="primary" |
| | | @click="submitNegotiationForm">确认</el-button> |
| | | <el-button @click="closeNegotiationDialog">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | |
| | | addReturnVisit, |
| | | getReturnVisit, |
| | | } from "@/api/basicData/customerFile.js"; |
| | | import {listCustomer, getCustomer, addCustomer, updateCustomer, delCustomer, backCustomer} from "@/api/basicData/customer.js"; |
| | | import { |
| | | listCustomer, |
| | | getCustomer, |
| | | addCustomer, |
| | | updateCustomer, |
| | | delCustomer, |
| | | backCustomer, |
| | | } from "@/api/basicData/customer.js"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | |
| | | const negotiationFormRef = ref(); |
| | | const negotiationForm = reactive({ |
| | | customerName: "", |
| | | customerId: "", |
| | | customerId: "", |
| | | followUpMethod: "", |
| | | followUpLevel: "", |
| | | followUpTime: "", |
| | |
| | | openForm("edit", row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "æ·»å æ´½è°è¿åº¦", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openNegotiationDialog(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "æ·»å æ´½è°è¿åº¦", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openNegotiationDialog(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "å访æé", |
| | | type: "text", |
| | |
| | | openReminderDialog(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "详æ
", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openDetailDialog(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "详æ
", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openDetailDialog(row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | |
| | | searchForm: { |
| | | customerName: "", |
| | | customerType: "", |
| | | type: 0 |
| | | type: 0, |
| | | }, |
| | | form: { |
| | | customerName: "", |
| | |
| | | bankAccount: "", |
| | | bankCode: "", |
| | | customerType: "", |
| | | type: 0 |
| | | type: 0, |
| | | }, |
| | | rules: { |
| | | customerName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/basic/customer/importData", |
| | | data: { |
| | | type: 0 |
| | | type: 0, |
| | | }, |
| | | // æä»¶ä¸ä¼ åçåè° |
| | | beforeUpload: file => { |
| | |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/basic/customer/export", {type: 0}, "å®¢æ·æ¡£æ¡.xlsx"); |
| | | proxy.download("/basic/customer/export", { type: 0 }, "å®¢æ·æ¡£æ¡.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | |
| | | if (reminderForm.id) { |
| | | submitvalue.value = { |
| | | id: reminderForm.id, |
| | | customerId: currentCustomerId.value, |
| | | customerId: currentCustomerId.value, |
| | | isEnabled: reminderForm.reminderSwitch ? 1 : 0, |
| | | content: reminderForm.reminderContent, |
| | | reminderTime: reminderForm.reminderTime, |
| | |
| | | // å°å½åè®°å½æ°æ®å¡«å
å°è¡¨å |
| | | Object.assign(negotiationForm, { |
| | | customerName: row.customerName, |
| | | customerId: row.customerId, |
| | | customerId: row.customerId, |
| | | followUpMethod: row.followUpMethod, |
| | | followUpLevel: row.followUpLevel, |
| | | followUpTime: row.followUpTime, |
| | |
| | | const downloadAttachment = row => { |
| | | if (row.url) { |
| | | // proxy.download(row.url, {}, row.name); |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | } else { |
| | | proxy.$modal.msgError("ä¸è½½é¾æ¥ä¸åå¨"); |
| | | } |
| | |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title">ä¾åºåæ¡£æ¡ï¼</span> |
| | | <el-input |
| | | v-model="searchForm.supplierName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥ä¾åºååç§°æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | /> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px" |
| | | >æç´¢</el-button |
| | | > |
| | | <el-input v-model="searchForm.supplierName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥ä¾åºååç§°æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" /> |
| | | <el-button type="primary" |
| | | @click="handleQuery" |
| | | style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | ></PIMTable> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination"></PIMTable> |
| | | </div> |
| | | <el-dialog |
| | | v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢ä¾åºåä¿¡æ¯' : 'ç¼è¾ä¾åºåä¿¡æ¯'" |
| | | width="70%" |
| | | @close="closeDia" |
| | | > |
| | | <el-form |
| | | :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | > |
| | | <el-dialog v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢ä¾åºåä¿¡æ¯' : 'ç¼è¾ä¾åºåä¿¡æ¯'" |
| | | width="70%" |
| | | @close="closeDia"> |
| | | <el-form :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¾åºååç§°ï¼" prop="supplierName"> |
| | | <el-input |
| | | v-model="form.supplierName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | <el-form-item label="ä¾åºååç§°ï¼" |
| | | prop="supplierName"> |
| | | <el-input v-model="form.supplierName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item |
| | | label="纳ç¨äººè¯å«å·ï¼" |
| | | prop="taxpayerIdentificationNum" |
| | | > |
| | | <el-input |
| | | v-model="form.taxpayerIdentificationNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | <el-form-item label="纳ç¨äººè¯å«å·ï¼" |
| | | prop="taxpayerIdentificationNum"> |
| | | <el-input v-model="form.taxpayerIdentificationNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="å
¬å¸å°åï¼" |
| | | prop="companyAddress"> |
| | | <el-input v-model="form.companyAddress" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸å°åï¼" prop="companyAddress"> |
| | | <el-input |
| | | v-model="form.companyAddress" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸çµè¯ï¼" prop="companyPhone"> |
| | | <el-input |
| | | v-model="form.companyPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="弿·è¡ï¼" prop="bankAccountName"> |
| | | <el-input |
| | | v-model="form.bankAccountName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è´¦å·ï¼" prop="bankAccountNum"> |
| | | <el-input |
| | | v-model="form.bankAccountNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è系人ï¼" prop="contactUserName"> |
| | | <el-input |
| | | v-model="form.contactUserName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="èç³»çµè¯ï¼" prop="contactUserPhone"> |
| | | <el-input |
| | | v-model="form.contactUserPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤äººï¼" prop="maintainUserId"> |
| | | <el-select |
| | | v-model="form.maintainUserId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | disabled |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.nickName" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | /> |
| | | <el-form-item label="ç»´æ¤äººï¼" |
| | | prop="maintainUserId"> |
| | | <el-select v-model="form.maintainUserId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | disabled> |
| | | <el-option v-for="item in userList" |
| | | :key="item.nickName" |
| | | :label="item.nickName" |
| | | :value="item.userId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤æ¶é´ï¼" prop="maintainTime"> |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="form.maintainTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | /> |
| | | <el-form-item label="ç»´æ¤æ¶é´ï¼" |
| | | prop="maintainTime"> |
| | | <el-date-picker style="width: 100%" |
| | | v-model="form.maintainTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¾åºåç±»åï¼" prop="supplierType"> |
| | | <el-select v-model="form.supplierType" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="ç²" value="ç²" /> |
| | | <el-option label="ä¹" value="ä¹" /> |
| | | <el-option label="ä¸" value="ä¸" /> |
| | | <el-option label="ä¸" value="ä¸" /> |
| | | <el-form-item label="ä¾åºåç±»åï¼" |
| | | prop="supplierType"> |
| | | <el-select v-model="form.supplierType" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option label="ç²" |
| | | value="ç²" /> |
| | | <el-option label="ä¹" |
| | | value="ä¹" /> |
| | | <el-option label="ä¸" |
| | | value="ä¸" /> |
| | | <el-option label="ä¸" |
| | | value="ä¸" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦ç½ååï¼" prop="isWhite"> |
| | | <el-select v-model="form.isWhite" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="æ¯" :value="0" /> |
| | | <el-option label="å¦" :value="1" /> |
| | | <el-form-item label="æ¯å¦ç½ååï¼" |
| | | prop="isWhite"> |
| | | <el-select v-model="form.isWhite" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option label="æ¯" |
| | | :value="0" /> |
| | | <el-option label="å¦" |
| | | :value="1" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">确认</el-button> |
| | | <el-button type="primary" |
| | | @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- ä¾åºå导å
¥å¯¹è¯æ¡ --> |
| | | <el-dialog |
| | | :title="upload.title" |
| | | v-model="upload.open" |
| | | width="400px" |
| | | append-to-body |
| | | > |
| | | <el-upload |
| | | ref="uploadRef" |
| | | :limit="1" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url + '?updateSupport=' + upload.updateSupport" |
| | | :disabled="upload.isUploading" |
| | | :on-progress="handleFileUploadProgress" |
| | | :on-success="handleFileSuccess" |
| | | :on-error="handleFileError" |
| | | :auto-upload="false" |
| | | drag |
| | | > |
| | | <el-dialog :title="upload.title" |
| | | v-model="upload.open" |
| | | width="400px" |
| | | append-to-body> |
| | | <el-upload ref="uploadRef" |
| | | :limit="1" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url + '?updateSupport=' + upload.updateSupport" |
| | | :disabled="upload.isUploading" |
| | | :on-progress="handleFileUploadProgress" |
| | | :on-success="handleFileSuccess" |
| | | :on-error="handleFileError" |
| | | :auto-upload="false" |
| | | drag> |
| | | <el-icon class="el-icon--upload"><upload-filled /></el-icon> |
| | | <div class="el-upload__text">å°æä»¶æå°æ¤å¤ï¼æ<em>ç¹å»ä¸ä¼ </em></div> |
| | | <template #tip> |
| | | <div class="el-upload__tip text-center"> |
| | | <span>ä»
å
许导å
¥xlsãxlsxæ ¼å¼æä»¶ã</span> |
| | | <el-link |
| | | type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline" |
| | | @click="importTemplate" |
| | | >ä¸è½½æ¨¡æ¿</el-link |
| | | > |
| | | <el-link type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline" |
| | | @click="importTemplate">ä¸è½½æ¨¡æ¿</el-link> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button type="primary" |
| | | @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="upload.open = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { delSupplier } from "@/api/basicData/supplierManageFile.js"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addSupplier, |
| | | getSupplier, |
| | | listSupplier, |
| | | updateSupplier, |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import { onMounted, ref } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { delSupplier } from "@/api/basicData/supplierManageFile.js"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addSupplier, |
| | | getSupplier, |
| | | listSupplier, |
| | | updateSupplier, |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "ä¾åºååç§°", |
| | | prop: "supplierName", |
| | | width: 250, |
| | | }, |
| | | { |
| | | label: "ä¾åºåç±»å", |
| | | prop: "supplierType", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "纳ç¨äººè¯å«å·", |
| | | prop: "taxpayerIdentificationNum", |
| | | width: 230, |
| | | }, |
| | | { |
| | | label: "å
¬å¸å°å", |
| | | prop: "companyAddress", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "èç³»æ¹å¼", |
| | | prop: "companyPhone", |
| | | width:150 |
| | | }, |
| | | { |
| | | label: "弿·è¡", |
| | | prop: "bankAccountName", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è´¦å·", |
| | | prop: "bankAccountNum", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è系人", |
| | | prop: "contactUserName", |
| | | }, |
| | | { |
| | | label: "èç³»çµè¯", |
| | | prop: "contactUserPhone", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "ç»´æ¤äºº", |
| | | prop: "maintainUserName", |
| | | }, |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "ä¾åºååç§°", |
| | | prop: "supplierName", |
| | | width: 250, |
| | | }, |
| | | { |
| | | label: "ä¾åºåç±»å", |
| | | prop: "supplierType", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "纳ç¨äººè¯å«å·", |
| | | prop: "taxpayerIdentificationNum", |
| | | width: 230, |
| | | }, |
| | | { |
| | | label: "å
¬å¸å°å", |
| | | prop: "companyAddress", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "ç»´æ¤äºº", |
| | | prop: "maintainUserName", |
| | | }, |
| | | |
| | | { |
| | | label: "ç»´æ¤æ¶é´", |
| | | prop: "maintainTime", |
| | | width:100 |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: 'right', |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openForm("edit", row); |
| | | { |
| | | label: "ç»´æ¤æ¶é´", |
| | | prop: "maintainTime", |
| | | width: 100, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openForm("edit", row); |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | //èµè´¨éä»¶ |
| | | name: "èµè´¨æä»¶", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openFileDialog(row) |
| | | { |
| | | //èµè´¨éä»¶ |
| | | name: "èµè´¨æä»¶", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openFileDialog(row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const fileListDialogVisible = ref(false); |
| | | const recordId = ref(); |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | }, |
| | | form: { |
| | | supplierName: "", |
| | | taxpayerIdentificationNum: "", |
| | | companyAddress: "", |
| | | maintainUserId: "", |
| | | maintainTime: "", |
| | | supplierType: "", |
| | | isWhite: "", |
| | | }, |
| | | rules: { |
| | | supplierName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxpayerIdentificationNum: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | companyAddress: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | maintainUserId: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | maintainTime: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | supplierType: [ |
| | | { required: true, message: "è¯·éæ©ä¾åºåç±»å", trigger: "change" }, |
| | | ], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | /** æäº¤ä¸ä¼ æä»¶ */ |
| | | function submitFileForm() { |
| | | upload.isUploading = true; |
| | | proxy.$refs["uploadRef"].submit(); |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listSupplier({ ...searchForm.value, ...page, isWhite: 1 }).then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }); |
| | | }; |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå±ï¼ä¾åºå导å
¥ï¼ |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ï¼ä¾åºå导å
¥ï¼ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // æ¯å¦æ´æ°å·²ç»åå¨çç¨æ·æ°æ® |
| | | updateSupport: 1, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import", |
| | | }); |
| | | /** 导å
¥æé®æä½ */ |
| | | function handleImport() { |
| | | upload.title = "ä¾åºå导å
¥"; |
| | | upload.open = true; |
| | | } |
| | | /** ä¸è½½æ¨¡æ¿ */ |
| | | function importTemplate() { |
| | | proxy.download( |
| | | "/system/supplier/downloadTemplate", |
| | | {}, |
| | | "ä¾åºå导å
¥æ¨¡æ¿.xlsx" |
| | | ); |
| | | } |
| | | |
| | | /**æä»¶ä¸ä¼ ä¸å¤ç */ |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ æåå¤ç */ |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.isUploading = false; |
| | | if (response.code === 200) { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | upload.open = false; |
| | | proxy.$refs["uploadRef"].clearFiles(); |
| | | getList(); |
| | | } else if (response.code === 500) { |
| | | proxy.$modal.msgError(response.msg); |
| | | } else { |
| | | proxy.$modal.msgWarning(response.msg); |
| | | } |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ 失败å¤ç */ |
| | | const handleFileError = (error, file, fileList) => { |
| | | upload.isUploading = false; |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | form.value.maintainUserId = userStore.id; |
| | | form.value.maintainTime = getCurrentDate(); |
| | | userListNoPage().then(res => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | getSupplier(row.id).then(res => { |
| | | form.value = { ...res.data }; |
| | | }); |
| | | } |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| | | submitEdit(); |
| | | } else { |
| | | submitAdd(); |
| | | } |
| | | } |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const fileListDialogVisible = ref(false); |
| | | const recordId = ref(); |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | }, |
| | | form: { |
| | | supplierName: "", |
| | | taxpayerIdentificationNum: "", |
| | | companyAddress: "", |
| | | companyPhone: "", |
| | | bankAccountName: "", |
| | | bankAccountNum: "", |
| | | contactUserName: "", |
| | | contactUserPhone: "", |
| | | maintainUserId: "", |
| | | maintainTime: "", |
| | | supplierType: "", |
| | | isWhite: "", |
| | | }, |
| | | rules: { |
| | | supplierName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxpayerIdentificationNum: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | companyAddress: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | companyPhone: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountNum: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserName: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserPhone: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | maintainUserId: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | maintainTime: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | supplierType: [{ required: true, message: "è¯·éæ©ä¾åºåç±»å", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | /** æäº¤ä¸ä¼ æä»¶ */ |
| | | function submitFileForm() { |
| | | upload.isUploading = true; |
| | | proxy.$refs["uploadRef"].submit(); |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listSupplier({ ...searchForm.value, ...page, isWhite: 1 }).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }); |
| | | }; |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå±ï¼ä¾åºå导å
¥ï¼ |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ï¼ä¾åºå导å
¥ï¼ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // æ¯å¦æ´æ°å·²ç»åå¨çç¨æ·æ°æ® |
| | | updateSupport: 1, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import", |
| | | }); |
| | | /** 导å
¥æé®æä½ */ |
| | | function handleImport() { |
| | | upload.title = "ä¾åºå导å
¥"; |
| | | upload.open = true; |
| | | } |
| | | /** ä¸è½½æ¨¡æ¿ */ |
| | | function importTemplate() { |
| | | proxy.download("/system/supplier/downloadTemplate", {}, "ä¾åºå导å
¥æ¨¡æ¿.xlsx"); |
| | | } |
| | | |
| | | /**æä»¶ä¸ä¼ ä¸å¤ç */ |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ æåå¤ç */ |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.isUploading = false; |
| | | if(response.code === 200){ |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | upload.open = false; |
| | | proxy.$refs["uploadRef"].clearFiles(); |
| | | getList(); |
| | | }else if(response.code === 500){ |
| | | proxy.$modal.msgError(response.msg); |
| | | }else{ |
| | | proxy.$modal.msgWarning(response.msg); |
| | | } |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ 失败å¤ç */ |
| | | const handleFileError = (error, file, fileList) => { |
| | | upload.isUploading = false; |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | form.value.maintainUserId = userStore.id; |
| | | form.value.maintainTime = getCurrentDate(); |
| | | userListNoPage().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | getSupplier(row.id).then((res) => { |
| | | form.value = { ...res.data }; |
| | | }); |
| | | } |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate((valid) => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| | | submitEdit(); |
| | | } else { |
| | | submitAdd(); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | // æäº¤æ°å¢ |
| | | const submitAdd = () => { |
| | | addSupplier(form.value).then((res) => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // æäº¤ä¿®æ¹ |
| | | const submitEdit = () => { |
| | | updateSupplier(form.value).then((res) => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | }; |
| | | // æäº¤æ°å¢ |
| | | const submitAdd = () => { |
| | | addSupplier(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // æäº¤ä¿®æ¹ |
| | | const submitEdit = () => { |
| | | updateSupplier(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/system/supplier/export", { isWhite: 1 }, "ä¾åºåæ¡£æ¡.xlsx"); |
| | | proxy.download( |
| | | "/system/supplier/export", |
| | | { isWhite: 1 }, |
| | | "ä¾åºåæ¡£æ¡.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | // æ£æ¥æ¯å¦æä»äººç»´æ¤çæ°æ® |
| | | const unauthorizedData = selectedRows.value.filter(item => item.maintainUserName !== userStore.nickName); |
| | | if (unauthorizedData.length > 0) { |
| | | proxy.$modal.msgWarning("ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®"); |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | // æ£æ¥æ¯å¦æä»äººç»´æ¤çæ°æ® |
| | | const unauthorizedData = selectedRows.value.filter( |
| | | item => item.maintainUserName !== userStore.nickName |
| | | ); |
| | | if (unauthorizedData.length > 0) { |
| | | proxy.$modal.msgWarning("ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®"); |
| | | return; |
| | | } |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ids = selectedRows.value.map((item) => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | delSupplier(ids) |
| | | .then((res) => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | .then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | |
| | | defineExpose({ |
| | | getList, |
| | | }); |
| | | defineExpose({ |
| | | getList, |
| | | }); |
| | | </script> |
| | | |
| | | |
| | |
| | | <div class="search_form"> |
| | | <div style="margin-bottom: 10px;"> |
| | | <span class="search_title">ä¾åºåæ¡£æ¡ï¼</span> |
| | | <el-input |
| | | v-model="searchForm.supplierName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥ä¾åºååç§°æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | /> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px" |
| | | >æç´¢</el-button |
| | | > |
| | | <el-input v-model="searchForm.supplierName" |
| | | style="width: 240px" |
| | | placeholder="è¾å
¥ä¾åºååç§°æç´¢" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" /> |
| | | <el-button type="primary" |
| | | @click="handleQuery" |
| | | style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <div style="margin-bottom: 10px;"> |
| | | <el-button type="primary" @click="openForm('add')" |
| | | >æ°å¢ä¾åºå</el-button |
| | | > |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢ä¾åºå</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="info" plain icon="Upload" @click="handleImport" |
| | | >导å
¥</el-button |
| | | > |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | <el-button type="info" |
| | | plain |
| | | icon="Upload" |
| | | @click="handleImport">导å
¥</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | ></PIMTable> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination"></PIMTable> |
| | | </div> |
| | | <el-dialog |
| | | v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢ä¾åºåä¿¡æ¯' : 'ç¼è¾ä¾åºåä¿¡æ¯'" |
| | | width="70%" |
| | | @close="closeDia" |
| | | > |
| | | <el-form |
| | | :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | > |
| | | <el-dialog v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢ä¾åºåä¿¡æ¯' : 'ç¼è¾ä¾åºåä¿¡æ¯'" |
| | | width="70%" |
| | | @close="closeDia"> |
| | | <el-form :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¾åºååç§°ï¼" prop="supplierName"> |
| | | <el-input |
| | | v-model="form.supplierName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | <el-form-item label="ä¾åºååç§°ï¼" |
| | | prop="supplierName"> |
| | | <el-input v-model="form.supplierName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item |
| | | label="纳ç¨äººè¯å«å·ï¼" |
| | | prop="taxpayerIdentificationNum" |
| | | > |
| | | <el-input |
| | | v-model="form.taxpayerIdentificationNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | <el-form-item label="纳ç¨äººè¯å«å·ï¼" |
| | | prop="taxpayerIdentificationNum"> |
| | | <el-input v-model="form.taxpayerIdentificationNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="å
¬å¸å°åï¼" |
| | | prop="companyAddress"> |
| | | <el-input v-model="form.companyAddress" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸å°åï¼" prop="companyAddress"> |
| | | <el-input |
| | | v-model="form.companyAddress" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å
¬å¸çµè¯ï¼" prop="companyPhone"> |
| | | <el-input |
| | | v-model="form.companyPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="弿·è¡ï¼" prop="bankAccountName"> |
| | | <el-input |
| | | v-model="form.bankAccountName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è´¦å·ï¼" prop="bankAccountNum"> |
| | | <el-input |
| | | v-model="form.bankAccountNum" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è系人ï¼" prop="contactUserName"> |
| | | <el-input |
| | | v-model="form.contactUserName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="èç³»çµè¯ï¼" prop="contactUserPhone"> |
| | | <el-input |
| | | v-model="form.contactUserPhone" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤äººï¼" prop="maintainUserId"> |
| | | <el-select |
| | | v-model="form.maintainUserId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | disabled |
| | | > |
| | | <el-option |
| | | v-for="item in userList" |
| | | :key="item.nickName" |
| | | :label="item.nickName" |
| | | :value="item.userId" |
| | | /> |
| | | <el-form-item label="ç»´æ¤äººï¼" |
| | | prop="maintainUserId"> |
| | | <el-select v-model="form.maintainUserId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | disabled> |
| | | <el-option v-for="item in userList" |
| | | :key="item.nickName" |
| | | :label="item.nickName" |
| | | :value="item.userId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´æ¤æ¶é´ï¼" prop="maintainTime"> |
| | | <el-date-picker |
| | | style="width: 100%" |
| | | v-model="form.maintainTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | /> |
| | | <el-form-item label="ç»´æ¤æ¶é´ï¼" |
| | | prop="maintainTime"> |
| | | <el-date-picker style="width: 100%" |
| | | v-model="form.maintainTime" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¾åºåç±»åï¼" prop="supplierType"> |
| | | <el-select v-model="form.supplierType" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="ç²" value="ç²" /> |
| | | <el-option label="ä¹" value="ä¹" /> |
| | | <el-option label="ä¸" value="ä¸" /> |
| | | <el-option label="ä¸" value="ä¸" /> |
| | | <el-form-item label="ä¾åºåç±»åï¼" |
| | | prop="supplierType"> |
| | | <el-select v-model="form.supplierType" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option label="ç²" |
| | | value="ç²" /> |
| | | <el-option label="ä¹" |
| | | value="ä¹" /> |
| | | <el-option label="ä¸" |
| | | value="ä¸" /> |
| | | <el-option label="ä¸" |
| | | value="ä¸" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦ç½ååï¼" prop="isWhite"> |
| | | <el-select v-model="form.isWhite" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="æ¯" :value="0" /> |
| | | <el-option label="å¦" :value="1" /> |
| | | <el-form-item label="æ¯å¦ç½ååï¼" |
| | | prop="isWhite"> |
| | | <el-select v-model="form.isWhite" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option label="æ¯" |
| | | :value="0" /> |
| | | <el-option label="å¦" |
| | | :value="1" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">确认</el-button> |
| | | <el-button type="primary" |
| | | @click="submitForm">确认</el-button> |
| | | <el-button @click="closeDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | |
| | | <!-- ä¾åºå导å
¥å¯¹è¯æ¡ --> |
| | | <el-dialog |
| | | :title="upload.title" |
| | | v-model="upload.open" |
| | | width="400px" |
| | | append-to-body |
| | | > |
| | | <el-upload |
| | | ref="uploadRef" |
| | | :limit="1" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url + '?updateSupport=' + upload.updateSupport" |
| | | :disabled="upload.isUploading" |
| | | :on-progress="handleFileUploadProgress" |
| | | :on-success="handleFileSuccess" |
| | | :on-error="handleFileError" |
| | | :auto-upload="false" |
| | | drag |
| | | > |
| | | <el-dialog :title="upload.title" |
| | | v-model="upload.open" |
| | | width="400px" |
| | | append-to-body> |
| | | <el-upload ref="uploadRef" |
| | | :limit="1" |
| | | accept=".xlsx, .xls" |
| | | :headers="upload.headers" |
| | | :action="upload.url + '?updateSupport=' + upload.updateSupport" |
| | | :disabled="upload.isUploading" |
| | | :on-progress="handleFileUploadProgress" |
| | | :on-success="handleFileSuccess" |
| | | :on-error="handleFileError" |
| | | :auto-upload="false" |
| | | drag> |
| | | <el-icon class="el-icon--upload"><upload-filled /></el-icon> |
| | | <div class="el-upload__text">å°æä»¶æå°æ¤å¤ï¼æ<em>ç¹å»ä¸ä¼ </em></div> |
| | | <template #tip> |
| | | <div class="el-upload__tip text-center"> |
| | | <span>ä»
å
许导å
¥xlsãxlsxæ ¼å¼æä»¶ã</span> |
| | | <el-link |
| | | type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline" |
| | | @click="importTemplate" |
| | | >ä¸è½½æ¨¡æ¿</el-link |
| | | > |
| | | <el-link type="primary" |
| | | :underline="false" |
| | | style="font-size: 12px; vertical-align: baseline" |
| | | @click="importTemplate">ä¸è½½æ¨¡æ¿</el-link> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button type="primary" |
| | | @click="submitFileForm">ç¡® å®</el-button> |
| | | <el-button @click="upload.open = false">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { delSupplier } from "@/api/basicData/supplierManageFile.js"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addSupplier, |
| | | getSupplier, |
| | | listSupplier, |
| | | updateSupplier, |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import { onMounted, ref } from "vue"; |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import { delSupplier } from "@/api/basicData/supplierManageFile.js"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addSupplier, |
| | | getSupplier, |
| | | listSupplier, |
| | | updateSupplier, |
| | | } from "@/api/basicData/supplierManageFile.js"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | ); |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "ä¾åºååç§°", |
| | | prop: "supplierName", |
| | | width: 250, |
| | | }, |
| | | { |
| | | label: "ä¾åºåç±»å", |
| | | prop: "supplierType", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "纳ç¨äººè¯å«å·", |
| | | prop: "taxpayerIdentificationNum", |
| | | width: 230, |
| | | }, |
| | | { |
| | | label: "å
¬å¸å°å", |
| | | prop: "companyAddress", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "èç³»æ¹å¼", |
| | | prop: "companyPhone", |
| | | width:150 |
| | | }, |
| | | { |
| | | label: "弿·è¡", |
| | | prop: "bankAccountName", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è´¦å·", |
| | | prop: "bankAccountNum", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "è系人", |
| | | prop: "contactUserName", |
| | | }, |
| | | { |
| | | label: "èç³»çµè¯", |
| | | prop: "contactUserPhone", |
| | | width: 150, |
| | | }, |
| | | { |
| | | label: "ç»´æ¤äºº", |
| | | prop: "maintainUserName", |
| | | }, |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "ä¾åºååç§°", |
| | | prop: "supplierName", |
| | | width: 250, |
| | | }, |
| | | { |
| | | label: "ä¾åºåç±»å", |
| | | prop: "supplierType", |
| | | width: 120, |
| | | }, |
| | | { |
| | | label: "纳ç¨äººè¯å«å·", |
| | | prop: "taxpayerIdentificationNum", |
| | | width: 230, |
| | | }, |
| | | { |
| | | label: "å
¬å¸å°å", |
| | | prop: "companyAddress", |
| | | width: 220, |
| | | }, |
| | | { |
| | | label: "ç»´æ¤äºº", |
| | | prop: "maintainUserName", |
| | | }, |
| | | |
| | | { |
| | | label: "ç»´æ¤æ¶é´", |
| | | prop: "maintainTime", |
| | | width:100 |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: 'right', |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openForm("edit", row); |
| | | { |
| | | label: "ç»´æ¤æ¶é´", |
| | | prop: "maintainTime", |
| | | width: 100, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 150, |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openForm("edit", row); |
| | | }, |
| | | }, |
| | | }, |
| | | { |
| | | //èµè´¨éä»¶ |
| | | name: "èµè´¨æä»¶", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openFileDialog(row) |
| | | { |
| | | //èµè´¨éä»¶ |
| | | name: "èµè´¨æä»¶", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openFileDialog(row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const fileListDialogVisible = ref(false); |
| | | const recordId = ref(); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | }, |
| | | form: { |
| | | supplierName: "", |
| | | taxpayerIdentificationNum: "", |
| | | companyAddress: "", |
| | | maintainUserId: "", |
| | | maintainTime: "", |
| | | supplierType: "", |
| | | isWhite: "", |
| | | }, |
| | | rules: { |
| | | supplierName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxpayerIdentificationNum: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | companyAddress: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | maintainUserId: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | maintainTime: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | supplierType: [ |
| | | { required: true, message: "è¯·éæ©ä¾åºåç±»å", trigger: "change" }, |
| | | ], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | /** æäº¤ä¸ä¼ æä»¶ */ |
| | | function submitFileForm() { |
| | | upload.isUploading = true; |
| | | proxy.$refs["uploadRef"].submit(); |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listSupplier({ ...searchForm.value, ...page, isWhite: 0 }).then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }); |
| | | }; |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå±ï¼ä¾åºå导å
¥ï¼ |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ï¼ä¾åºå导å
¥ï¼ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // æ¯å¦æ´æ°å·²ç»åå¨çç¨æ·æ°æ® |
| | | updateSupport: 1, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import", |
| | | }); |
| | | /** 导å
¥æé®æä½ */ |
| | | function handleImport() { |
| | | upload.title = "ä¾åºå导å
¥"; |
| | | upload.open = true; |
| | | } |
| | | /** ä¸è½½æ¨¡æ¿ */ |
| | | function importTemplate() { |
| | | proxy.download( |
| | | "/system/supplier/downloadTemplate", |
| | | {}, |
| | | "ä¾åºå导å
¥æ¨¡æ¿.xlsx" |
| | | ); |
| | | } |
| | | |
| | | /**æä»¶ä¸ä¼ ä¸å¤ç */ |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ æåå¤ç */ |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.isUploading = false; |
| | | if (response.code === 200) { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | upload.open = false; |
| | | proxy.$refs["uploadRef"].clearFiles(); |
| | | getList(); |
| | | } else if (response.code === 500) { |
| | | proxy.$modal.msgError(response.msg); |
| | | } else { |
| | | proxy.$modal.msgWarning(response.msg); |
| | | } |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ 失败å¤ç */ |
| | | const handleFileError = (error, file, fileList) => { |
| | | upload.isUploading = false; |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | form.value.maintainUserId = userStore.id; |
| | | form.value.maintainTime = getCurrentDate(); |
| | | userListNoPage().then(res => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | getSupplier(row.id).then(res => { |
| | | form.value = { ...res.data }; |
| | | }); |
| | | } |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| | | submitEdit(); |
| | | } else { |
| | | submitAdd(); |
| | | } |
| | | } |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const fileListDialogVisible = ref(false); |
| | | const recordId = ref(); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", |
| | | }, |
| | | form: { |
| | | supplierName: "", |
| | | taxpayerIdentificationNum: "", |
| | | companyAddress: "", |
| | | companyPhone: "", |
| | | bankAccountName: "", |
| | | bankAccountNum: "", |
| | | contactUserName: "", |
| | | contactUserPhone: "", |
| | | maintainUserId: "", |
| | | maintainTime: "", |
| | | supplierType: "", |
| | | isWhite: "", |
| | | }, |
| | | rules: { |
| | | supplierName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxpayerIdentificationNum: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | companyAddress: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | companyPhone: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountName: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | bankAccountNum: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserName: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | contactUserPhone: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | maintainUserId: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | maintainTime: [{ required: false, message: "è¯·éæ©", trigger: "change" }], |
| | | supplierType: [{ required: true, message: "è¯·éæ©ä¾åºåç±»å", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { searchForm, form, rules } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | /** æäº¤ä¸ä¼ æä»¶ */ |
| | | function submitFileForm() { |
| | | upload.isUploading = true; |
| | | proxy.$refs["uploadRef"].submit(); |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | listSupplier({ ...searchForm.value, ...page, isWhite: 0 }).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }); |
| | | }; |
| | | const upload = reactive({ |
| | | // æ¯å¦æ¾ç¤ºå¼¹åºå±ï¼ä¾åºå导å
¥ï¼ |
| | | open: false, |
| | | // å¼¹åºå±æ é¢ï¼ä¾åºå导å
¥ï¼ |
| | | title: "", |
| | | // æ¯å¦ç¦ç¨ä¸ä¼ |
| | | isUploading: false, |
| | | // æ¯å¦æ´æ°å·²ç»åå¨çç¨æ·æ°æ® |
| | | updateSupport: 1, |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/system/supplier/import", |
| | | }); |
| | | /** 导å
¥æé®æä½ */ |
| | | function handleImport() { |
| | | upload.title = "ä¾åºå导å
¥"; |
| | | upload.open = true; |
| | | } |
| | | /** ä¸è½½æ¨¡æ¿ */ |
| | | function importTemplate() { |
| | | proxy.download("/system/supplier/downloadTemplate", {}, "ä¾åºå导å
¥æ¨¡æ¿.xlsx"); |
| | | } |
| | | |
| | | /**æä»¶ä¸ä¼ ä¸å¤ç */ |
| | | const handleFileUploadProgress = (event, file, fileList) => { |
| | | upload.isUploading = true; |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ æåå¤ç */ |
| | | const handleFileSuccess = (response, file, fileList) => { |
| | | upload.isUploading = false; |
| | | if(response.code === 200){ |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | upload.open = false; |
| | | proxy.$refs["uploadRef"].clearFiles(); |
| | | getList(); |
| | | }else if(response.code === 500){ |
| | | proxy.$modal.msgError(response.msg); |
| | | }else{ |
| | | proxy.$modal.msgWarning(response.msg); |
| | | } |
| | | }; |
| | | |
| | | /** æä»¶ä¸ä¼ 失败å¤ç */ |
| | | const handleFileError = (error, file, fileList) => { |
| | | upload.isUploading = false; |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | form.value.maintainUserId = userStore.id; |
| | | form.value.maintainTime = getCurrentDate(); |
| | | userListNoPage().then((res) => { |
| | | userList.value = res.data; |
| | | }); |
| | | if (type === "edit") { |
| | | getSupplier(row.id).then((res) => { |
| | | form.value = { ...res.data }; |
| | | }); |
| | | } |
| | | dialogFormVisible.value = true; |
| | | }; |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate((valid) => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| | | submitEdit(); |
| | | } else { |
| | | submitAdd(); |
| | | } |
| | | } |
| | | }); |
| | | }; |
| | | // æäº¤æ°å¢ |
| | | const submitAdd = () => { |
| | | addSupplier(form.value).then((res) => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // æäº¤ä¿®æ¹ |
| | | const submitEdit = () => { |
| | | updateSupplier(form.value).then((res) => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | }; |
| | | // æäº¤æ°å¢ |
| | | const submitAdd = () => { |
| | | addSupplier(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // æäº¤ä¿®æ¹ |
| | | const submitEdit = () => { |
| | | updateSupplier(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/system/supplier/export", { isWhite: 0 }, "ä¾åºåæ¡£æ¡.xlsx"); |
| | | proxy.download( |
| | | "/system/supplier/export", |
| | | { isWhite: 0 }, |
| | | "ä¾åºåæ¡£æ¡.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | // æ£æ¥æ¯å¦æä»äººç»´æ¤çæ°æ® |
| | | const unauthorizedData = selectedRows.value.filter(item => item.maintainUserName !== userStore.nickName); |
| | | if (unauthorizedData.length > 0) { |
| | | proxy.$modal.msgWarning("ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®"); |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | // æ£æ¥æ¯å¦æä»äººç»´æ¤çæ°æ® |
| | | const unauthorizedData = selectedRows.value.filter( |
| | | item => item.maintainUserName !== userStore.nickName |
| | | ); |
| | | if (unauthorizedData.length > 0) { |
| | | proxy.$modal.msgWarning("ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®"); |
| | | return; |
| | | } |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ids = selectedRows.value.map((item) => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | delSupplier(ids) |
| | | .then((res) => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | .then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | |
| | | defineExpose({ |
| | | getList, |
| | | }); |
| | | defineExpose({ |
| | | getList, |
| | | }); |
| | | </script> |
| | | |
| | |
| | | <el-descriptions-item label="æ¥ä»·æ»é¢" |
| | | :span="2"> |
| | | <span style="font-size: 18px; color: #e6a23c; font-weight: bold;"> |
| | | ¥{{ Number(currentQuotation.totalAmount ?? 0).toFixed(2) }} |
| | | ¥{{ Number(currentQuotation.totalAmount ?? 0).toFixed(6) }} |
| | | </span> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | |
| | | label="åä½" /> |
| | | <el-table-column prop="unitPrice" |
| | | label="åä»·"> |
| | | <template #default="scope">Â¥{{ Number(scope.row.unitPrice ?? 0).toFixed(2) }}</template> |
| | | <template #default="scope">Â¥{{ Number(scope.row.unitPrice ?? 0).toFixed(6) }}</template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- åºå·®æ¶é´ï¼ä»
å½ approveType 为 3 æ¶æ¾ç¤ºï¼ --> |
| | | <el-row :gutter="30" v-if="props.approveType == 3"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åºå·®å¼å§æ¶é´ï¼" prop="startDateTime"> |
| | | <el-date-picker |
| | | v-model="form.startDateTime" |
| | | type="datetime" |
| | | placeholder="è¯·éæ©å¼å§æ¶é´" |
| | | value-format="YYYY-MM-DD HH:mm" |
| | | format="YYYY-MM-DD HH:mm" |
| | | clearable |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åºå·®ç»ææ¶é´ï¼" prop="endDateTime"> |
| | | <el-date-picker |
| | | v-model="form.endDateTime" |
| | | type="datetime" |
| | | placeholder="è¯·éæ©ç»ææ¶é´" |
| | | value-format="YYYY-MM-DD HH:mm" |
| | | format="YYYY-MM-DD HH:mm" |
| | | clearable |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- åºå·®å°ç¹ï¼ä»
å½ approveType 为 3 æ¶æ¾ç¤ºï¼ --> |
| | | <el-row v-if="props.approveType == 3"> |
| | | <el-col :span="24"> |
| | |
| | | startDate: "", // 请åå¼å§æ¶é´ |
| | | endDate: "", // 请åç»ææ¶é´ |
| | | price: null, // æ¥ééé¢ |
| | | startDateTime: "", // åºå·®å¼å§æ¶é´ |
| | | endDateTime: "", // åºå·®ç»ææ¶é´ |
| | | location: "", // åºå·®å°ç¹ |
| | | storageBlobDTOS: [] |
| | | }, |
| | |
| | | startDate: [{ required: true, message: "è¯·éæ©è¯·åå¼å§æ¶é´", trigger: "change" }], |
| | | endDate: [{ required: true, message: "è¯·éæ©è¯·åç»ææ¶é´", trigger: "change" }], |
| | | price: [{ required: true, message: "请è¾å
¥æ¥ééé¢", trigger: "blur" }], |
| | | startDateTime: [{ required: true, message: "è¯·éæ©åºå·®å¼å§æ¶é´", trigger: "change" }], |
| | | endDateTime: [{ required: true, message: "è¯·éæ©åºå·®ç»ææ¶é´", trigger: "change" }], |
| | | location: [{ required: true, message: "请è¾å
¥åºå·®å°ç¹", trigger: "blur" }], |
| | | }, |
| | | }); |
| | |
| | | return |
| | | } |
| | | } |
| | | // å½ approveType 为 3 æ¶ï¼æ ¡éªåºå·®å°ç¹ |
| | | // å½ approveType 为 3 æ¶ï¼æ ¡éªåºå·®æ¶é´åå°ç¹ |
| | | if (props.approveType == 3) { |
| | | if (!form.value.startDateTime) { |
| | | proxy.$modal.msgError("è¯·éæ©åºå·®å¼å§æ¶é´ï¼") |
| | | return |
| | | } |
| | | if (!form.value.endDateTime) { |
| | | proxy.$modal.msgError("è¯·éæ©åºå·®ç»ææ¶é´ï¼") |
| | | return |
| | | } |
| | | if (new Date(form.value.endDateTime) < new Date(form.value.startDateTime)) { |
| | | proxy.$modal.msgError("åºå·®ç»ææ¶é´ä¸è½æ©äºå¼å§æ¶é´ï¼") |
| | | return |
| | | } |
| | | if (!form.value.location || form.value.location.trim() === '') { |
| | | proxy.$modal.msgError("请è¾å
¥åºå·®å°ç¹ï¼") |
| | | return |
| | |
| | | // å¨æè¡¨æ ¼åé
ç½®ï¼æ ¹æ®å®¡æ¹ç±»åçæå |
| | | const tableColumnCopy = computed(() => { |
| | | const isLeaveType = currentApproveType.value === 2; // 请å管ç |
| | | const isBusinessTripType = currentApproveType.value === 3; // åºå·®ç®¡ç |
| | | const isReimburseType = currentApproveType.value === 4; // æ¥é管ç |
| | | const isQuotationType = currentApproveType.value === 6; // æ¥ä»·å®¡æ¹ |
| | | const isPurchaseType = currentApproveType.value === 5; // éè´å®¡æ¹ |
| | |
| | | width: 120 |
| | | }); |
| | | } |
| | | |
| | | // 请å管çï¼å¼å§æ¥æ / ç»ææ¥æ |
| | | if (isLeaveType) { |
| | | baseColumns.push( |
| | | { label: "å¼å§æ¥æ", prop: "startDate", width: 120 }, |
| | | { label: "ç»ææ¥æ", prop: "endDate", width: 120 } |
| | | ); |
| | | } |
| | | |
| | | // æ¥æåï¼æ ¹æ®ç±»å卿é
ç½®ï¼ |
| | | baseColumns.push( |
| | | { |
| | | label: isLeaveType ? "å¼å§æ¥æ" : "ç³è¯·æ¥æ", |
| | | prop: isLeaveType ? "startDate" : "approveTime", |
| | | width: 200 |
| | | }, |
| | | { |
| | | label: "ç»ææ¥æ", |
| | | prop: isLeaveType ? "endDate" : "approveOverTime", |
| | | width: 120 |
| | | } |
| | | ); |
| | | // åºå·®ç®¡çï¼å¼å§æ¶é´ / ç»ææ¶é´ï¼ä¸å«ç§ï¼ |
| | | if (isBusinessTripType) { |
| | | baseColumns.push( |
| | | { |
| | | label: "å¼å§æ¶é´", |
| | | prop: "startDateTime", |
| | | width: 180, |
| | | formatData: (val) => val ? val.substring(0, 16) : '' |
| | | }, |
| | | { |
| | | label: "ç»ææ¶é´", |
| | | prop: "endDateTime", |
| | | width: 180, |
| | | formatData: (val) => val ? val.substring(0, 16) : '' |
| | | } |
| | | ); |
| | | } |
| | | |
| | | // å½å审æ¹äººå |
| | | baseColumns.push({ |
| | |
| | | prop: "approveUserCurrentName", |
| | | width: 120 |
| | | }); |
| | | |
| | | // ç³è¯·æ¶é´ - ææç±»å齿¾ç¤º |
| | | baseColumns.push({ |
| | | label: "ç³è¯·æ¶é´", |
| | | prop: "approveTime", |
| | | width: 180, |
| | | }); |
| | | |
| | | // å®¡æ¹æ¶é´ - ææç±»å齿¾ç¤º |
| | | baseColumns.push({ |
| | | label: "å®¡æ¹æ¶é´", |
| | | prop: "approveOverTime", |
| | | width: 180, |
| | | }); |
| | | |
| | | // æä½å |
| | | const actionOperations = [ |
| | |
| | | return; |
| | | } |
| | | if (operationType.value === "add") { |
| | | productSelectedRows.value.forEach(selectedRow => { |
| | | const index = productData.value.findIndex( |
| | | product => product.id === selectedRow.id |
| | | ); |
| | | if (index !== -1) { |
| | | productData.value.splice(index, 1); |
| | | } |
| | | }); |
| | | productData.value = productData.value.filter( |
| | | item => !productSelectedRows.value.includes(item) |
| | | ); |
| | | productSelectedRows.value = []; |
| | | } else { |
| | | let ids = []; |
| | | if (productSelectedRows.value.length > 0) { |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è¯åï¼" prop="rating"> |
| | | <el-rate |
| | | v-model="form.rating" |
| | | :disabled="operationType === 'view'" |
| | | :max="5" |
| | | show-text |
| | | :texts="['é叏䏿»¡æ', '䏿»¡æ', 'ä¸è¬', '满æ', 'é常满æ']" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="è¯ä»·å
容æè¿°ï¼" prop="evaluation"> |
| | | <el-input |
| | | v-model="form.evaluation" |
| | | placeholder="请è¾å
¥è¯ä»·å
容æè¿°" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | type="textarea" |
| | | :rows="3" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | |
| | | disposeUserId: "", |
| | | disDate: "", |
| | | disRes: "", |
| | | rating: null, |
| | | evaluation: "", |
| | | }, |
| | | rules: { |
| | | feedbackDate: [{required: true, message: "è¯·éæ©", trigger: "change"}], |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item label="é®é¢æè¿°ï¼" |
| | | <el-form-item label="客æ·è¯æ±ï¼" |
| | | prop="proDesc"> |
| | | <el-input v-model="form.proDesc" |
| | | placeholder="请è¾å
¥é®é¢æè¿°" /> |
| | | placeholder="请è¾å
¥å®¢æ·è¯æ±" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | form.value.customerId = null; |
| | | } |
| | | getSalesLedger({ |
| | | customerName: form.value.customerName, |
| | | customerId: form.value.customerId, |
| | | }).then(res => { |
| | | if (res.code === 200) { |
| | | associatedSalesOrderNumberOptions.value = res.data.records.map(item => ({ |
| | |
| | | form.value = { ...row }; |
| | | if (form.value.customerName) { |
| | | const res = await getSalesLedger({ |
| | | customerName: form.value.customerName, |
| | | customerId: form.value.customerId, |
| | | }); |
| | | if (res?.code === 200) { |
| | | console.log(res); |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="workorder-stats"> |
| | | <div |
| | | v-for="(item, index) in statsList" |
| | | :key="index" |
| | | class="stat-card" |
| | | > |
| | | <div class="stat-icon" :style="{ backgroundColor: item.bgColor }"> |
| | | <el-icon :color="item.color" :size="20"> |
| | | <div v-for="(item, index) in statsList" |
| | | :key="index" |
| | | class="stat-card"> |
| | | <div class="stat-icon" |
| | | :style="{ backgroundColor: item.bgColor }"> |
| | | <el-icon :color="item.color" |
| | | :size="20"> |
| | | <component :is="item.icon" /> |
| | | </el-icon> |
| | | </div> |
| | |
| | | </div> |
| | | </div> |
| | | <div class="search-wrapper"> |
| | | <el-form |
| | | :model="searchForm" |
| | | class="demo-form-inline" |
| | | > |
| | | <el-form :model="searchForm" |
| | | class="demo-form-inline"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-input |
| | | v-model="searchForm.afterSalesServiceNo" |
| | | placeholder="请è¾å
¥å·¥åç¼å·" |
| | | clearable |
| | | /> |
| | | <el-input v-model="searchForm.afterSalesServiceNo" |
| | | placeholder="请è¾å
¥å·¥åç¼å·" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-select |
| | | v-model="searchForm.status" |
| | | placeholder="è¯·éæ©å·¥åç¶æ" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="dict in workOrderStatusOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | /> |
| | | <el-select v-model="searchForm.status" |
| | | placeholder="è¯·éæ©å·¥åç¶æ" |
| | | clearable> |
| | | <el-option v-for="dict in workOrderStatusOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-select |
| | | v-model="searchForm.urgency" |
| | | placeholder="è¯·éæ©ç´§æ¥ç¨åº¦" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="dict in degreeOfUrgencyOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | /> |
| | | <el-select v-model="searchForm.urgency" |
| | | placeholder="è¯·éæ©ç´§æ¥ç¨åº¦" |
| | | clearable> |
| | | <el-option v-for="dict in degreeOfUrgencyOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-select |
| | | v-model="searchForm.serviceType" |
| | | placeholder="è¯·éæ©å®åç±»å" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="dict in classificationOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" |
| | | /> |
| | | <el-select v-model="searchForm.serviceType" |
| | | placeholder="è¯·éæ©å®åç±»å" |
| | | clearable> |
| | | <el-option v-for="dict in classificationOptions" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-input |
| | | v-model="searchForm.orderNo" |
| | | placeholder="请è¾å
¥éå®åå·" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | |
| | | |
| | | |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-input v-model="searchForm.orderNo" |
| | | placeholder="请è¾å
¥éå®åå·" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <!-- æé® --> |
| | | <el-col :span="4"> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery"> |
| | | <el-button type="primary" |
| | | @click="handleQuery"> |
| | | æç´¢ |
| | | </el-button> |
| | | <el-button @click="handleReset"> |
| | |
| | | </el-form> |
| | | </div> |
| | | <div class="table_list"> |
| | | <div class="table_header" style="display: flex; justify-content: space-between; align-items: center;"> |
| | | <div class="table_header" |
| | | style="display: flex; justify-content: space-between; align-items: center;"> |
| | | <div> |
| | | <el-button type="primary" @click="openForm('add')">æ°å¢å®åå</el-button> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢å®åå</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :height="tableHeight" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | ></PIMTable> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :height="tableHeight" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination"></PIMTable> |
| | | </div> |
| | | <form-dia ref="formDia" @close="handleQuery"></form-dia> |
| | | <form-dia ref="formDia" |
| | | @close="handleQuery"></form-dia> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {onMounted, reactive, ref, toRefs, computed, getCurrentInstance, nextTick} from "vue"; |
| | | import FormDia from "@/views/customerService/feedbackRegistration/components/formDia.vue"; |
| | | import {ElMessageBox} from "element-plus"; |
| | | import {afterSalesServiceDelete, afterSalesServiceListPage, getSalesLedgerDetail} from "@/api/customerService/index.js"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore() |
| | | import { Document, FolderOpened, UserFilled } from "@element-plus/icons-vue" |
| | | import { markRaw } from 'vue' |
| | | import { |
| | | onMounted, |
| | | reactive, |
| | | ref, |
| | | toRefs, |
| | | computed, |
| | | getCurrentInstance, |
| | | nextTick, |
| | | } from "vue"; |
| | | import FormDia from "@/views/customerService/feedbackRegistration/components/formDia.vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { |
| | | afterSalesServiceDelete, |
| | | afterSalesServiceListPage, |
| | | getSalesLedgerDetail, |
| | | } from "@/api/customerService/index.js"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | import { Document, FolderOpened, UserFilled } from "@element-plus/icons-vue"; |
| | | import { markRaw } from "vue"; |
| | | |
| | | const statsList = ref([ |
| | | { |
| | | icon: markRaw(Document), |
| | | count: 0, |
| | | label: 'å
¨é¨å·¥å', |
| | | color: '#4080ff', |
| | | bgColor: '#eaf2ff' |
| | | }, |
| | | { |
| | | icon: markRaw(FolderOpened), |
| | | count: 0, |
| | | label: 'å·²å¤ç', |
| | | color: '#ff9a2e', |
| | | bgColor: '#fff5e6' |
| | | }, |
| | | { |
| | | icon: markRaw(UserFilled), |
| | | count: 0, |
| | | label: '已宿', |
| | | color: '#00b42a', |
| | | bgColor: '#e6f7ed' |
| | | }, |
| | | ]) |
| | | |
| | | const data = reactive({ |
| | | searchForm : { |
| | | customerName: "", |
| | | status: "", |
| | | urgency: "", |
| | | serviceType: "", |
| | | reviewStatus: "", |
| | | orderNo: "", |
| | | } |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "å·¥åç¼å·", |
| | | prop:"afterSalesServiceNo", |
| | | width: 150, |
| | | align: "center" |
| | | }, |
| | | { |
| | | label: "éå®åå·", |
| | | prop:"salesContractNo", |
| | | width: 150, |
| | | align: "center" |
| | | }, |
| | | { |
| | | label: "å¤çç¶æ", |
| | | prop: "status", |
| | | dataType: "tag", |
| | | |
| | | formatData: (params) => { |
| | | if (params) { |
| | | let part = String(params) |
| | | const item = workOrderStatusOptions.value.find(item => item.value === part); |
| | | return item?.label || params; |
| | | } |
| | | return null; |
| | | const statsList = ref([ |
| | | { |
| | | icon: markRaw(Document), |
| | | count: 0, |
| | | label: "å
¨é¨å·¥å", |
| | | color: "#4080ff", |
| | | bgColor: "#eaf2ff", |
| | | }, |
| | | formatType: (params) => { |
| | | if (params === 1) { |
| | | return "danger"; |
| | | } else if (params === 2) { |
| | | return "success"; |
| | | } else { |
| | | { |
| | | icon: markRaw(FolderOpened), |
| | | count: 0, |
| | | label: "å¾
å¤ç", |
| | | color: "#ff9a2e", |
| | | bgColor: "#fff5e6", |
| | | }, |
| | | { |
| | | icon: markRaw(UserFilled), |
| | | count: 0, |
| | | label: "å·²å¤ç", |
| | | color: "#00b42a", |
| | | bgColor: "#e6f7ed", |
| | | }, |
| | | ]); |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | customerName: "", |
| | | status: "", |
| | | urgency: "", |
| | | serviceType: "", |
| | | reviewStatus: "", |
| | | orderNo: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "å·¥åç¼å·", |
| | | prop: "afterSalesServiceNo", |
| | | width: 150, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "éå®åå·", |
| | | prop: "salesContractNo", |
| | | width: 150, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "å¤çç¶æ", |
| | | prop: "status", |
| | | dataType: "tag", |
| | | |
| | | formatData: params => { |
| | | if (params) { |
| | | let part = String(params); |
| | | const item = workOrderStatusOptions.value.find( |
| | | item => item.value === part |
| | | ); |
| | | return item?.label || params; |
| | | } |
| | | return null; |
| | | } |
| | | }, |
| | | align: "center" |
| | | }, |
| | | { |
| | | label: "å馿¥æ", |
| | | prop: "feedbackDate", |
| | | width: 150, |
| | | align: "center" |
| | | }, |
| | | { |
| | | label: "ç»è®°äºº", |
| | | prop: "checkNickName", |
| | | align: "center" |
| | | }, |
| | | { |
| | | label: "ç´§æ¥ç¨åº¦", |
| | | prop: "urgency", |
| | | // æ ¹æ®degreeOfUrgencyOptionsåå
¸å»èªå¨å¹é
|
| | | formatData: (params) => { |
| | | if (params) { |
| | | const item = degreeOfUrgencyOptions.value.find(item => item.value === params); |
| | | return item?.label || params; |
| | | } |
| | | return null; |
| | | }, |
| | | align: "center" |
| | | }, |
| | | { |
| | | label: "å®åç±»å", |
| | | prop: "serviceType", |
| | | // æ ¹æ®classificationOptionsåå
¸å»èªå¨å¹é
|
| | | formatData: (params) => { |
| | | if (params) { |
| | | const item = classificationOptions.value.find(item => item.value === params); |
| | | return item?.label || params; |
| | | } |
| | | return null; |
| | | }, |
| | | align: "center" |
| | | }, |
| | | { |
| | | label: "é®é¢æè¿°", |
| | | prop: "proDesc", |
| | | width:300, |
| | | }, |
| | | { |
| | | label: "å
³èé¨é¨", |
| | | prop: "deptName", |
| | | width: 200, |
| | | align: "center" |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | fixed: 'right', |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | console.log(row) |
| | | openForm("edit", row); |
| | | }, |
| | | disabled: (row) => { |
| | | return row.status !== 1 |
| | | }, |
| | | formatType: params => { |
| | | if (params === 1) { |
| | | return "danger"; |
| | | } else if (params === 2) { |
| | | return "success"; |
| | | } else { |
| | | return null; |
| | | } |
| | | }, |
| | | ], |
| | | align: "center" |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const selectedRows = ref([]); |
| | | const tableHeight = computed(() => "calc(100% -80px)"); |
| | | |
| | | const handleReset = () => { |
| | | Object.keys(searchForm.value).forEach(key => { |
| | | searchForm.value[key] = "" |
| | | }) |
| | | page.current = 1; |
| | | getList(); |
| | | } |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | const formDia = ref() |
| | | |
| | | // åå
¸è·å |
| | | /* |
| | | post_sale_waiting_list æ°å¢çå®ååç±» |
| | | degree_of_urgency æ°å¢çç´§æ¥ç¨åº¦ |
| | | work_order_status 主页çå·¥åç¶æ |
| | | review_status é¦é¡µçå®¡æ ¸ç¶æ |
| | | */ |
| | | const { post_sale_waiting_list, degree_of_urgency, work_order_status, review_status } = proxy.useDict( |
| | | "post_sale_waiting_list", |
| | | "degree_of_urgency", |
| | | "work_order_status", |
| | | "review_status" |
| | | ); |
| | | |
| | | const classificationOptions = computed(() => post_sale_waiting_list?.value || []); |
| | | const degreeOfUrgencyOptions = computed(() => degree_of_urgency?.value || []); |
| | | const workOrderStatusOptions = computed(() => work_order_status?.value || []); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getSalesLedgerDetails() |
| | | afterSalesServiceListPage({ ...searchForm.value, ...page }).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "å馿¥æ", |
| | | prop: "feedbackDate", |
| | | width: 150, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "ç»è®°äºº", |
| | | prop: "checkNickName", |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "ç´§æ¥ç¨åº¦", |
| | | prop: "urgency", |
| | | // æ ¹æ®degreeOfUrgencyOptionsåå
¸å»èªå¨å¹é
|
| | | formatData: params => { |
| | | if (params) { |
| | | const item = degreeOfUrgencyOptions.value.find( |
| | | item => item.value === params |
| | | ); |
| | | return item?.label || params; |
| | | } |
| | | return null; |
| | | }, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "å®åç±»å", |
| | | prop: "serviceType", |
| | | // æ ¹æ®classificationOptionsåå
¸å»èªå¨å¹é
|
| | | formatData: params => { |
| | | if (params) { |
| | | const item = classificationOptions.value.find( |
| | | item => item.value === params |
| | | ); |
| | | return item?.label || params; |
| | | } |
| | | return null; |
| | | }, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "客æ·è¯æ±", |
| | | prop: "proDesc", |
| | | width: 300, |
| | | }, |
| | | { |
| | | label: "å
³èé¨é¨", |
| | | prop: "deptName", |
| | | width: 200, |
| | | align: "center", |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | fixed: "right", |
| | | operation: [ |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: row => { |
| | | console.log(row); |
| | | openForm("edit", row); |
| | | }, |
| | | disabled: row => { |
| | | return row.status !== 1; |
| | | }, |
| | | }, |
| | | ], |
| | | align: "center", |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | }; |
| | | const selectedRows = ref([]); |
| | | const tableHeight = computed(() => "calc(100% -80px)"); |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | nextTick(() => { |
| | | formDia.value?.openDialog(type, row) |
| | | }) |
| | | }; |
| | | const handleReset = () => { |
| | | Object.keys(searchForm.value).forEach(key => { |
| | | searchForm.value[key] = ""; |
| | | }); |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | const formDia = ref(); |
| | | |
| | | function handleDelete() { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | // æ£æ¥æ¯å¦æä»äººç»´æ¤çæ°æ® |
| | | const unauthorizedData = selectedRows.value.filter(item => item.checkUserId !== userStore.id); |
| | | if (unauthorizedData.length > 0) { |
| | | proxy.$modal.msgWarning("ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®"); |
| | | // åå
¸è·å |
| | | /* |
| | | post_sale_waiting_list æ°å¢çå®ååç±» |
| | | degree_of_urgency æ°å¢çç´§æ¥ç¨åº¦ |
| | | work_order_status 主页çå·¥åç¶æ |
| | | review_status é¦é¡µçå®¡æ ¸ç¶æ |
| | | */ |
| | | const { |
| | | post_sale_waiting_list, |
| | | degree_of_urgency, |
| | | work_order_status, |
| | | review_status, |
| | | } = proxy.useDict( |
| | | "post_sale_waiting_list", |
| | | "degree_of_urgency", |
| | | "work_order_status", |
| | | "review_status" |
| | | ); |
| | | |
| | | const classificationOptions = computed( |
| | | () => post_sale_waiting_list?.value || [] |
| | | ); |
| | | const degreeOfUrgencyOptions = computed(() => degree_of_urgency?.value || []); |
| | | const workOrderStatusOptions = computed(() => work_order_status?.value || []); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | getSalesLedgerDetails(); |
| | | afterSalesServiceListPage({ ...searchForm.value, ...page }).then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }); |
| | | }; |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | nextTick(() => { |
| | | formDia.value?.openDialog(type, row); |
| | | }); |
| | | }; |
| | | |
| | | function handleDelete() { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | // æ£æ¥æ¯å¦æä»äººç»´æ¤çæ°æ® |
| | | const unauthorizedData = selectedRows.value.filter( |
| | | item => item.checkUserId !== userStore.id |
| | | ); |
| | | if (unauthorizedData.length > 0) { |
| | | proxy.$modal.msgWarning("ä¸å¯å é¤ä»äººç»´æ¤çæ°æ®"); |
| | | return; |
| | | } |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ids = selectedRows.value.map((item) => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | afterSalesServiceDelete(ids) |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | .then(() => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | } |
| | | |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/afterSalesService/export", {}, "åé¦ç»è®°.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | const getStatsCountByStatus = (list, status) => { |
| | | if (!Array.isArray(list)) return 0; |
| | | return list.find((item) => item?.status === status)?.count || 0; |
| | | }; |
| | | const getStatsCountByStatus = (list, status) => { |
| | | if (!Array.isArray(list)) return 0; |
| | | return list.find(item => item?.status === status)?.count || 0; |
| | | }; |
| | | |
| | | // è·åç»è®¡æ°æ®å¹¶å·æ°é¡¶é¨å¡ç |
| | | const getSalesLedgerDetails = () => { |
| | | getSalesLedgerDetail({}).then((res) => { |
| | | getSalesLedgerDetail({}).then(res => { |
| | | if (res.code === 200) { |
| | | const statsData = Array.isArray(res.data) ? res.data : []; |
| | | statsList.value[0].count = getStatsCountByStatus(statsData, 3); |
| | | statsList.value[1].count = getStatsCountByStatus(statsData, 2); |
| | | statsList.value[2].count = getStatsCountByStatus(statsData, 1); |
| | | statsList.value[1].count = getStatsCountByStatus(statsData, 1); |
| | | statsList.value[2].count = getStatsCountByStatus(statsData, 2); |
| | | } |
| | | }); |
| | | } |
| | | }; |
| | | |
| | | |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | |
| | | }); |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .search-wrapper { |
| | | background: white; |
| | | padding: 1rem 1rem 0 1rem; |
| | | border: 8px; |
| | | border-radius: 16px; |
| | | } |
| | | .search-wrapper { |
| | | background: white; |
| | | padding: 1rem 1rem 0 1rem; |
| | | border: 8px; |
| | | border-radius: 16px; |
| | | } |
| | | |
| | | .expand-btn { |
| | | width: 100%; |
| | | padding: 20px; /* ä¸ä¸å·¦å³å20pxï¼ç¹å»è¿ä¸ªèå´é½è½è§¦åäºä»¶ */ |
| | | cursor: pointer; /* é¼ æ æ¬æµ®æ¾ç¤ºæåï¼æåä½éª */ |
| | | text-align: center; |
| | | } |
| | | .expand-btn { |
| | | width: 100%; |
| | | padding: 20px; /* ä¸ä¸å·¦å³å20pxï¼ç¹å»è¿ä¸ªèå´é½è½è§¦åäºä»¶ */ |
| | | cursor: pointer; /* é¼ æ æ¬æµ®æ¾ç¤ºæåï¼æåä½éª */ |
| | | text-align: center; |
| | | } |
| | | |
| | | .workorder-stats { |
| | | display: flex; |
| | | gap: 16px; |
| | | padding-bottom:1rem; |
| | | border-radius: 8px; |
| | | } |
| | | .workorder-stats { |
| | | display: flex; |
| | | gap: 16px; |
| | | padding-bottom: 1rem; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .stat-card { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | padding: 20px; |
| | | background-color: #fff; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06); |
| | | } |
| | | .stat-card { |
| | | flex: 1; |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 12px; |
| | | padding: 20px; |
| | | background-color: #fff; |
| | | border-radius: 8px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.06); |
| | | } |
| | | |
| | | .stat-icon { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 48px; |
| | | height: 48px; |
| | | border-radius: 8px; |
| | | } |
| | | .stat-icon { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 48px; |
| | | height: 48px; |
| | | border-radius: 8px; |
| | | } |
| | | |
| | | .stat-info { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | } |
| | | .stat-info { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 4px; |
| | | } |
| | | |
| | | .stat-number { |
| | | font-size: 24px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | line-height: 1; |
| | | } |
| | | .stat-number { |
| | | font-size: 24px; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | line-height: 1; |
| | | } |
| | | |
| | | .stat-label { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | line-height: 1; |
| | | } |
| | | .table_header{ |
| | | padding-bottom: 10px; |
| | | } |
| | | .stat-label { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | line-height: 1; |
| | | } |
| | | .table_header { |
| | | padding-bottom: 10px; |
| | | } |
| | | |
| | | .table_list { |
| | | height: calc(100vh - 380px); |
| | | background: #fff; |
| | | margin-top: 20px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | .table_list { |
| | | height: calc(100vh - 380px); |
| | | background: #fff; |
| | | margin-top: 20px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | :deep(.table_list .pagination-container) { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | align-items: center; |
| | | margin-top: auto; |
| | | padding: 12px 0 0; |
| | | } |
| | | :deep(.table_list .pagination-container) { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | align-items: center; |
| | | margin-top: auto; |
| | | padding: 12px 0 0; |
| | | } |
| | | |
| | | :deep(.table_list .el-pagination) { |
| | | flex-wrap: nowrap; |
| | | justify-content: flex-end; |
| | | width: 100%; |
| | | } |
| | | :deep(.table_list .el-pagination) { |
| | | flex-wrap: nowrap; |
| | | justify-content: flex-end; |
| | | width: 100%; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <FormDialog |
| | | v-model="dialogVisible" |
| | | title="ä¸ä¼ å·¡æ£è®°å½" |
| | | width="980px" |
| | | @close="handleClose" |
| | | @cancel="handleClose" |
| | | > |
| | | <FormDialog v-model="dialogVisible" |
| | | :title="operationType === 'view' ? 'å·¡æ£è®°å½è¯¦æ
' : 'ä¸ä¼ å·¡æ£è®°å½'" |
| | | width="980px" |
| | | :operation-type="operationType" |
| | | @close="handleClose" |
| | | @cancel="handleClose"> |
| | | <main class="upload-content"> |
| | | <el-card v-if="taskInfo" class="section-card"> |
| | | <el-descriptions :column="1" border> |
| | | <el-card v-if="taskInfo" |
| | | class="section-card"> |
| | | <el-descriptions :column="2" |
| | | border> |
| | | <el-descriptions-item label="å·¡æ£ä»»å¡åç§°"> |
| | | {{ taskInfo.taskName || "-" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="å·¡æ£é¡¹ç®"> |
| | | {{ taskInfo.inspectionProject || "-" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="æ§è¡å·¡æ£äºº"> |
| | | <template v-if="formattedInspector && formattedInspector.length"> |
| | | <el-tag v-for="tag in formattedInspector" |
| | | :key="tag" |
| | | size="small" |
| | | style="margin-right: 4px"> |
| | | {{ tag }} |
| | | </el-tag> |
| | | </template> |
| | | <span v-else>--</span> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="颿¬¡"> |
| | | {{ formatFrequencyType(taskInfo.frequencyType) || "-" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="å¼å§æ¥æä¸æ¶é´"> |
| | | {{ formatFrequencyDetail(taskInfo.frequencyDetail) || "-" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="ç»è®°äºº"> |
| | | {{ taskInfo.registrant || "-" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="ç»è®°æ¥æ"> |
| | | {{ formatDateTime(taskInfo.createTime) || "-" }} |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="夿³¨"> |
| | | {{ taskInfo.remarks || "-" }} |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </el-card> |
| | | |
| | | <el-card class="section-card"> |
| | | <h3>å·¡æ£ç¶æ</h3> |
| | | <el-radio-group v-model="hasException"> |
| | | <el-radio-group v-model="hasException" |
| | | :disabled="operationType === 'view'"> |
| | | <el-radio-button :value="false">æ£å¸¸</el-radio-button> |
| | | <el-radio-button :value="true">åå¨å¼å¸¸</el-radio-button> |
| | | </el-radio-group> |
| | | </el-card> |
| | | |
| | | <el-card v-if="hasException === true" class="section-card"> |
| | | <el-card v-if="hasException === true" |
| | | class="section-card"> |
| | | <h3>å¼å¸¸æè¿°</h3> |
| | | <el-input |
| | | v-model="abnormalDescription" |
| | | type="textarea" |
| | | maxlength="500" |
| | | show-word-limit |
| | | :rows="4" |
| | | placeholder="请æè¿°å¼å¸¸æ
åµ..." |
| | | /> |
| | | <el-input v-model="abnormalDescription" |
| | | type="textarea" |
| | | maxlength="500" |
| | | show-word-limit |
| | | :rows="4" |
| | | :disabled="operationType === 'view'" |
| | | placeholder="请æè¿°å¼å¸¸æ
åµ..." /> |
| | | </el-card> |
| | | |
| | | <el-card v-if="hasException === true" class="section-card"> |
| | | <el-tabs v-model="currentUploadType"> |
| | | <el-tab-pane label="ç产å" name="before" /> |
| | | <el-tab-pane label="ç产ä¸" name="after" /> |
| | | <el-tab-pane label="ç产å" name="issue" /> |
| | | </el-tabs> |
| | | |
| | | <div class="upload-buttons"> |
| | | <el-upload |
| | | :show-file-list="false" |
| | | :http-request="uploadFile" |
| | | :disabled="getCurrentFiles().length >= uploadConfig.limit || uploading" |
| | | accept="image/*" |
| | | > |
| | | <el-button type="primary" :loading="uploading"> |
| | | <el-icon><Camera /></el-icon> |
| | | <el-card v-if="hasException === true" |
| | | class="section-card"> |
| | | <div class="upload-buttons" |
| | | v-if="operationType !== 'view'"> |
| | | <el-upload :show-file-list="false" |
| | | :http-request="uploadFile" |
| | | :disabled="beforeModelValue.length >= uploadConfig.limit || uploading" |
| | | accept="image/*"> |
| | | <el-button type="primary" |
| | | :loading="uploading"> |
| | | <el-icon> |
| | | <Camera /> |
| | | </el-icon> |
| | | éæ©å¾ç |
| | | </el-button> |
| | | </el-upload> |
| | | |
| | | <el-upload |
| | | :show-file-list="false" |
| | | :http-request="uploadFile" |
| | | :disabled="getCurrentFiles().length >= uploadConfig.limit || uploading" |
| | | accept="video/*" |
| | | > |
| | | <el-button type="success" :loading="uploading"> |
| | | <el-icon><VideoCamera /></el-icon> |
| | | <el-upload :show-file-list="false" |
| | | :http-request="uploadFile" |
| | | :disabled="beforeModelValue.length >= uploadConfig.limit || uploading" |
| | | accept="video/*"> |
| | | <el-button type="success" |
| | | :loading="uploading"> |
| | | <el-icon> |
| | | <VideoCamera /> |
| | | </el-icon> |
| | | éæ©è§é¢ |
| | | </el-button> |
| | | </el-upload> |
| | | </div> |
| | | |
| | | <el-progress |
| | | v-if="uploading" |
| | | :percentage="uploadProgress" |
| | | class="upload-progress" |
| | | /> |
| | | |
| | | <div v-if="getCurrentFiles().length" class="file-list"> |
| | | <div |
| | | v-for="(file, index) in getCurrentFiles()" |
| | | :key="file.uid || file.id || index" |
| | | class="file-item" |
| | | > |
| | | <el-progress v-if="uploading" |
| | | :percentage="uploadProgress" |
| | | class="upload-progress" /> |
| | | <div v-if="beforeModelValue.length" |
| | | class="file-list"> |
| | | <div v-for="(file, index) in beforeModelValue" |
| | | :key="file.uid || file.id || index" |
| | | class="file-item"> |
| | | <div class="file-preview-container"> |
| | | <el-image |
| | | v-if="file.type === 'image' || !file.type" |
| | | :src="file.url || file.tempFilePath || file.path || file.downloadUrl" |
| | | fit="cover" |
| | | class="file-preview" |
| | | :preview-src-list="[file.url || file.tempFilePath || file.path || file.downloadUrl]" |
| | | preview-teleported |
| | | /> |
| | | |
| | | <div v-else class="video-preview" @click="previewVideo(file)"> |
| | | <el-icon><VideoCamera /></el-icon> |
| | | <el-image v-if="file.type === 'image' || !file.type" |
| | | :src="file.url || file.tempFilePath || file.path || file.downloadUrl" |
| | | fit="cover" |
| | | class="file-preview" |
| | | :preview-src-list="[file.url || file.tempFilePath || file.path || file.downloadUrl]" |
| | | preview-teleported /> |
| | | <div v-else |
| | | class="video-preview" |
| | | @click="previewVideo(file)"> |
| | | <el-icon> |
| | | <VideoCamera /> |
| | | </el-icon> |
| | | <span>è§é¢</span> |
| | | </div> |
| | | |
| | | <el-button |
| | | class="delete-btn" |
| | | type="danger" |
| | | circle |
| | | size="small" |
| | | @click="removeFile(index)" |
| | | > |
| | | <el-icon><Close /></el-icon> |
| | | <el-button class="delete-btn" |
| | | type="danger" |
| | | circle |
| | | size="small" |
| | | v-if="operationType !== 'view'" |
| | | @click="removeFile(index)"> |
| | | <el-icon> |
| | | <Close /> |
| | | </el-icon> |
| | | </el-button> |
| | | </div> |
| | | |
| | | <div class="file-info"> |
| | | <div class="file-name"> |
| | | {{ file.bucketFilename || file.name || (file.type === "image" ? "å¾ç" : "è§é¢") }} |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <el-empty |
| | | v-else |
| | | :description="`è¯·éæ©è¦ä¸ä¼ ç${getUploadTypeText()}å¾çæè§é¢`" |
| | | /> |
| | | |
| | | <el-alert |
| | | class="upload-summary" |
| | | type="info" |
| | | :closable="false" |
| | | :title="`ç产åï¼${beforeModelValue.length}个æä»¶ | ç产ä¸ï¼${afterModelValue.length}个æä»¶ | ç产åï¼${issueModelValue.length}个æä»¶`" |
| | | /> |
| | | <el-empty v-else |
| | | :description="operationType === 'view' ? 'ææ å¼å¸¸ç
§çæè§é¢' : 'è¯·éæ©è¦ä¸ä¼ çå·¡æ£å¾çæè§é¢'" /> |
| | | </el-card> |
| | | |
| | | <el-result |
| | | v-if="hasException === false" |
| | | icon="success" |
| | | title="设å¤è¿è¡æ£å¸¸" |
| | | sub-title="æ éä¸ä¼ ç
§ç" |
| | | /> |
| | | <el-result v-if="hasException === false" |
| | | icon="success" |
| | | title="设å¤è¿è¡æ£å¸¸" |
| | | :sub-title="operationType === 'view' ? '' : 'æ éä¸ä¼ ç
§ç'" /> |
| | | </main> |
| | | |
| | | <template #footer> |
| | | <footer class="footer-buttons"> |
| | | <el-button type="primary" @click="submitUpload">æäº¤</el-button> |
| | | <el-button v-if="hasException === true" type="warning" @click="goToRepair"> |
| | | <el-button type="primary" |
| | | v-if="operationType !== 'view'" |
| | | @click="submitUpload">æäº¤</el-button> |
| | | <el-button v-if="hasException === true && operationType !== 'view'" |
| | | type="warning" |
| | | @click="goToRepair"> |
| | | æ°å¢æ¥ä¿® |
| | | </el-button> |
| | | <el-button @click="handleClose">åæ¶</el-button> |
| | | <el-button @click="handleClose">{{ operationType === 'view' ? 'å
³é' : 'åæ¶' }}</el-button> |
| | | </footer> |
| | | </template> |
| | | </FormDialog> |
| | | |
| | | <el-dialog |
| | | v-model="showVideoDialog" |
| | | :title="currentVideoFile?.originalFilename || currentVideoFile?.name || 'è§é¢é¢è§'" |
| | | width="720px" |
| | | > |
| | | <video |
| | | v-if="currentVideoFile" |
| | | :src="currentVideoFile.url || currentVideoFile.downloadUrl" |
| | | class="video-player" |
| | | controls |
| | | autoplay |
| | | /> |
| | | <el-dialog v-model="showVideoDialog" |
| | | :title="currentVideoFile?.originalFilename || currentVideoFile?.name || 'è§é¢é¢è§'" |
| | | width="720px"> |
| | | <video v-if="currentVideoFile" |
| | | :src="currentVideoFile.url || currentVideoFile.downloadUrl" |
| | | class="video-player" |
| | | controls |
| | | autoplay /> |
| | | </el-dialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { computed, ref } from "vue"; |
| | | import { useRouter } from "vue-router"; |
| | | import { ElLoading, ElMessage, ElMessageBox } from "element-plus"; |
| | | import { Camera, Close, VideoCamera } from "@element-plus/icons-vue"; |
| | | import axios from "axios"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { uploadInspectionTask } from "@/api/inspectionManagement/index.js"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import { computed, ref } from "vue"; |
| | | import { useRouter } from "vue-router"; |
| | | import { ElLoading, ElMessage, ElMessageBox } from "element-plus"; |
| | | import { Camera, Close, VideoCamera } from "@element-plus/icons-vue"; |
| | | import axios from "axios"; |
| | | import dayjs from "dayjs"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { uploadInspectionTask } from "@/api/inspectionManagement/index.js"; |
| | | import { getToken } from "@/utils/auth"; |
| | | |
| | | const emit = defineEmits(["closeDia", "success"]); |
| | | const router = useRouter(); |
| | | const emit = defineEmits(["closeDia", "success"]); |
| | | const router = useRouter(); |
| | | |
| | | const dialogVisible = ref(false); |
| | | const taskInfo = ref(null); |
| | | const uploading = ref(false); |
| | | const uploadProgress = ref(0); |
| | | const dialogVisible = ref(false); |
| | | const taskInfo = ref(null); |
| | | const uploading = ref(false); |
| | | const uploadProgress = ref(0); |
| | | const operationType = ref("add"); // add, view |
| | | |
| | | const beforeModelValue = ref([]); |
| | | const afterModelValue = ref([]); |
| | | const issueModelValue = ref([]); |
| | | const beforeModelValue = ref([]); |
| | | |
| | | const currentUploadType = ref("before"); |
| | | const hasException = ref(null); |
| | | const abnormalDescription = ref(""); |
| | | |
| | | const showVideoDialog = ref(false); |
| | | const currentVideoFile = ref(null); |
| | | |
| | | const uploadConfig = { |
| | | action: "/common/upload", |
| | | limit: 10, |
| | | fileSize: 50, |
| | | fileType: ["jpg", "jpeg", "png", "mp4", "mov"], |
| | | }; |
| | | |
| | | const uploadFileUrl = computed( |
| | | () => `${import.meta.env.VITE_APP_BASE_API}${uploadConfig.action}` |
| | | ); |
| | | |
| | | const processFileUrl = fileUrl => { |
| | | if (!fileUrl) return ""; |
| | | |
| | | let currentUrl = String(fileUrl); |
| | | if (currentUrl.includes("\\")) { |
| | | const uploadsIndex = currentUrl.toLowerCase().indexOf("uploads"); |
| | | if (uploadsIndex > -1) { |
| | | currentUrl = `/${currentUrl.substring(uploadsIndex).replace(/\\/g, "/")}`; |
| | | } else { |
| | | const fileName = currentUrl.split("\\").pop(); |
| | | currentUrl = `/uploads/${fileName}`; |
| | | const formattedInspector = computed(() => { |
| | | if (!taskInfo.value?.inspector) return []; |
| | | if (Array.isArray(taskInfo.value.inspector)) return taskInfo.value.inspector; |
| | | if (typeof taskInfo.value.inspector === "string") { |
| | | return taskInfo.value.inspector |
| | | .split(",") |
| | | .map(s => s.trim()) |
| | | .filter(s => s); |
| | | } |
| | | } |
| | | |
| | | if (currentUrl && !currentUrl.startsWith("http")) { |
| | | if (!currentUrl.startsWith("/")) { |
| | | currentUrl = `/${currentUrl}`; |
| | | } |
| | | currentUrl = __BASE_API__ + currentUrl; |
| | | } |
| | | |
| | | return currentUrl; |
| | | }; |
| | | |
| | | const normalizeList = (list, fileType) => { |
| | | if (!Array.isArray(list)) return []; |
| | | |
| | | return list.filter(Boolean).map(item => { |
| | | let currentType = item.type; |
| | | if (!currentType && item.contentType) { |
| | | currentType = item.contentType.startsWith("video") ? "video" : "image"; |
| | | } else if (!currentType) { |
| | | currentType = fileType || "image"; |
| | | } |
| | | |
| | | return { |
| | | ...item, |
| | | url: processFileUrl(item.url || item.previewURL || item.downloadUrl || item.path || ""), |
| | | downloadUrl: processFileUrl( |
| | | item.downloadUrl || item.url || item.previewURL || item.path || "" |
| | | ), |
| | | name: item.name || item.originalFilename || item.bucketFilename, |
| | | tempId: item.tempId || item.id || item.tempFileId, |
| | | tempFileId: item.tempFileId || item.tempId || item.id, |
| | | size: item.size || item.byteSize || 0, |
| | | type: currentType, |
| | | status: "success", |
| | | uid: item.uid || `${Date.now()}-${Math.random()}`, |
| | | }; |
| | | }); |
| | | }; |
| | | |
| | | const resetState = () => { |
| | | taskInfo.value = null; |
| | | beforeModelValue.value = []; |
| | | afterModelValue.value = []; |
| | | issueModelValue.value = []; |
| | | currentUploadType.value = "before"; |
| | | hasException.value = null; |
| | | abnormalDescription.value = ""; |
| | | uploading.value = false; |
| | | uploadProgress.value = 0; |
| | | showVideoDialog.value = false; |
| | | currentVideoFile.value = null; |
| | | }; |
| | | |
| | | const openDialog = row => { |
| | | const raw = JSON.parse(JSON.stringify(row?.__raw || row || {})); |
| | | taskInfo.value = raw; |
| | | |
| | | beforeModelValue.value = normalizeList( |
| | | raw.commonFileListBeforeVO || raw.commonFileListBefore || [], |
| | | "image" |
| | | ); |
| | | afterModelValue.value = normalizeList( |
| | | raw.commonFileListVO || raw.commonFileList || [], |
| | | "image" |
| | | ); |
| | | issueModelValue.value = normalizeList( |
| | | raw.commonFileListAfterVO || raw.commonFileListAfter || [], |
| | | "image" |
| | | ); |
| | | |
| | | abnormalDescription.value = raw.abnormalDescription || ""; |
| | | |
| | | if (raw.hasException !== undefined && raw.hasException !== null) { |
| | | hasException.value = raw.hasException; |
| | | } else if (raw.inspectionResult !== undefined && raw.inspectionResult !== null) { |
| | | hasException.value = String(raw.inspectionResult) === "0"; |
| | | } else { |
| | | hasException.value = null; |
| | | } |
| | | |
| | | if ( |
| | | hasException.value !== true && |
| | | (beforeModelValue.value.length || afterModelValue.value.length || issueModelValue.value.length) |
| | | ) { |
| | | hasException.value = true; |
| | | } |
| | | |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleClose = () => { |
| | | dialogVisible.value = false; |
| | | resetState(); |
| | | emit("closeDia"); |
| | | }; |
| | | |
| | | const getCurrentFiles = () => { |
| | | if (currentUploadType.value === "before") return beforeModelValue.value; |
| | | if (currentUploadType.value === "after") return afterModelValue.value; |
| | | if (currentUploadType.value === "issue") return issueModelValue.value; |
| | | return []; |
| | | }; |
| | | |
| | | const getUploadTypeText = () => { |
| | | if (currentUploadType.value === "before") return "ç产å"; |
| | | if (currentUploadType.value === "after") return "ç产ä¸"; |
| | | if (currentUploadType.value === "issue") return "ç产å"; |
| | | return ""; |
| | | }; |
| | | |
| | | const getTabType = () => { |
| | | if (currentUploadType.value === "before") return 10; |
| | | if (currentUploadType.value === "after") return 11; |
| | | if (currentUploadType.value === "issue") return 12; |
| | | return 10; |
| | | }; |
| | | |
| | | const previewVideo = file => { |
| | | currentVideoFile.value = file; |
| | | showVideoDialog.value = true; |
| | | }; |
| | | |
| | | const uploadFile = async uploadRequest => { |
| | | const rawFile = uploadRequest.file; |
| | | |
| | | if (getCurrentFiles().length >= uploadConfig.limit) { |
| | | ElMessage.warning(`æå¤åªè½éæ©${uploadConfig.limit}个æä»¶`); |
| | | return; |
| | | } |
| | | |
| | | const ext = rawFile.name.split(".").pop()?.toLowerCase(); |
| | | if (!uploadConfig.fileType.includes(ext)) { |
| | | ElMessage.warning(`æä»¶æ ¼å¼ä¸æ¯æï¼è¯·ä¸ä¼ ${uploadConfig.fileType.join("/")} æ ¼å¼`); |
| | | return; |
| | | } |
| | | |
| | | if (rawFile.size > uploadConfig.fileSize * 1024 * 1024) { |
| | | ElMessage.warning(`æä»¶å¤§å°ä¸è½è¶
è¿ ${uploadConfig.fileSize}MB`); |
| | | return; |
| | | } |
| | | |
| | | const token = getToken(); |
| | | if (!token) { |
| | | ElMessage.warning("ç¨æ·æªç»å½"); |
| | | return; |
| | | } |
| | | |
| | | const formData = new FormData(); |
| | | formData.append("files", rawFile); |
| | | formData.append("type", getTabType()); |
| | | |
| | | uploading.value = true; |
| | | uploadProgress.value = 0; |
| | | |
| | | try { |
| | | const { data } = await axios.post(uploadFileUrl.value, formData, { |
| | | headers: { |
| | | Authorization: `Bearer ${token}`, |
| | | "Content-Type": "multipart/form-data", |
| | | }, |
| | | onUploadProgress: event => { |
| | | if (event.total) { |
| | | uploadProgress.value = Math.round((event.loaded / event.total) * 100); |
| | | } |
| | | }, |
| | | }); |
| | | |
| | | if (data.code !== 200) { |
| | | ElMessage.error(data.msg || "ä¸ä¼ 失败"); |
| | | return; |
| | | } |
| | | |
| | | const resultData = Array.isArray(data.data) ? data.data[0] : data.data; |
| | | const finalUrl = processFileUrl( |
| | | resultData.url || resultData.previewURL || resultData.downloadUrl || "" |
| | | ); |
| | | const finalName = resultData.name || resultData.originalFilename || resultData.bucketFilename; |
| | | const finalId = resultData.tempId || resultData.id || resultData.tempFileId; |
| | | |
| | | const uploadedFile = { |
| | | ...resultData, |
| | | url: finalUrl, |
| | | downloadUrl: finalUrl, |
| | | name: finalName, |
| | | tempId: finalId, |
| | | tempFileId: resultData.tempFileId || finalId, |
| | | size: rawFile.size || resultData.size || resultData.byteSize || 0, |
| | | type: rawFile.type?.startsWith("video") ? "video" : "image", |
| | | status: "success", |
| | | uid: `${Date.now()}-${Math.random()}`, |
| | | }; |
| | | |
| | | getCurrentFiles().push(uploadedFile); |
| | | ElMessage.success("ä¸ä¼ æå"); |
| | | } catch (error) { |
| | | ElMessage.error(error?.message || "ä¸ä¼ 失败"); |
| | | } finally { |
| | | uploading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const buildFileItem = item => ({ |
| | | id: item?.id, |
| | | tempId: item?.tempId, |
| | | tempFileId: item?.tempFileId, |
| | | url: item?.downloadUrl || item?.url || "", |
| | | downloadUrl: item?.downloadUrl || item?.url || "", |
| | | name: item?.name, |
| | | bucketFilename: item?.bucketFilename || item?.name, |
| | | originalFilename: item?.originalFilename || item?.name, |
| | | size: item?.size || 0, |
| | | byteSize: item?.byteSize || item?.size || 0, |
| | | contentType: item?.contentType || "", |
| | | type: item?.type, |
| | | }); |
| | | |
| | | const submitUpload = async () => { |
| | | if (hasException.value === null) { |
| | | ElMessage.warning("è¯·éæ©å·¡æ£ç¶æ"); |
| | | return; |
| | | } |
| | | |
| | | if (hasException.value === true) { |
| | | const totalFiles = |
| | | beforeModelValue.value.length + |
| | | afterModelValue.value.length + |
| | | issueModelValue.value.length; |
| | | |
| | | if (!totalFiles) { |
| | | ElMessage.warning("请ä¸ä¼ å¼å¸¸ç
§çæè§é¢"); |
| | | return; |
| | | } |
| | | |
| | | if (!abnormalDescription.value.trim()) { |
| | | ElMessage.warning("请填åå¼å¸¸æè¿°"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | const loading = ElLoading.service({ |
| | | text: "æäº¤ä¸...", |
| | | background: "rgba(0, 0, 0, 0.3)", |
| | | return [taskInfo.value.inspector]; |
| | | }); |
| | | |
| | | try { |
| | | const allFiles = [ |
| | | ...beforeModelValue.value, |
| | | ...afterModelValue.value, |
| | | ...issueModelValue.value, |
| | | ]; |
| | | |
| | | const tempFileIds = allFiles |
| | | .map(item => item?.tempId ?? item?.tempFileId ?? item?.id) |
| | | .filter(Boolean); |
| | | |
| | | const { |
| | | createTime, |
| | | updateTime, |
| | | storageBlobDTO, |
| | | commonFileListAfterVO, |
| | | commonFileListVO, |
| | | commonFileListBeforeVO, |
| | | commonFileListAfter, |
| | | commonFileList, |
| | | commonFileListBefore, |
| | | __raw, |
| | | ...baseTaskInfo |
| | | } = taskInfo.value || {}; |
| | | |
| | | const submitData = { |
| | | ...baseTaskInfo, |
| | | commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem), |
| | | commonFileListDTO: afterModelValue.value.map(buildFileItem), |
| | | commonFileListAfterDTO: issueModelValue.value.map(buildFileItem), |
| | | hasException: hasException.value, |
| | | inspectionResult: hasException.value ? 0 : 1, |
| | | abnormalDescription: abnormalDescription.value, |
| | | tempFileIds, |
| | | const formatFrequencyType = type => { |
| | | const mapping = { |
| | | DAILY: "æ¯æ¥", |
| | | WEEKLY: "æ¯å¨", |
| | | MONTHLY: "æ¯æ", |
| | | QUARTERLY: "å£åº¦", |
| | | }; |
| | | |
| | | const result = await uploadInspectionTask(submitData); |
| | | |
| | | if (result && (result.code === 200 || result.success)) { |
| | | ElMessage.success("æäº¤æå"); |
| | | dialogVisible.value = false; |
| | | resetState(); |
| | | emit("success"); |
| | | emit("closeDia"); |
| | | } else { |
| | | ElMessage.error(result?.msg || result?.message || "æäº¤å¤±è´¥"); |
| | | } |
| | | } catch (error) { |
| | | ElMessage.error(error?.message || "æäº¤å¤±è´¥"); |
| | | } finally { |
| | | loading.close(); |
| | | } |
| | | }; |
| | | |
| | | const removeFile = async index => { |
| | | try { |
| | | await ElMessageBox.confirm("ç¡®å®è¦å é¤è¿ä¸ªæä»¶åï¼", "确认å é¤", { |
| | | type: "warning", |
| | | }); |
| | | getCurrentFiles().splice(index, 1); |
| | | } catch {} |
| | | }; |
| | | |
| | | const goToRepair = () => { |
| | | const taskData = { |
| | | taskId: taskInfo.value?.taskId || taskInfo.value?.id, |
| | | taskName: taskInfo.value?.taskName, |
| | | inspectionLocation: taskInfo.value?.inspectionLocation, |
| | | inspector: taskInfo.value?.inspector, |
| | | hasException: hasException.value, |
| | | inspectionResult: hasException.value ? 0 : 1, |
| | | commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem), |
| | | commonFileListDTO: afterModelValue.value.map(buildFileItem), |
| | | commonFileListAfterDTO: issueModelValue.value.map(buildFileItem), |
| | | uploadedFiles: { |
| | | before: beforeModelValue.value, |
| | | after: afterModelValue.value, |
| | | issue: issueModelValue.value, |
| | | }, |
| | | return mapping[type] || type; |
| | | }; |
| | | |
| | | sessionStorage.setItem("repairTaskInfo", JSON.stringify(taskData)); |
| | | router.push("/equipmentManagement/repair/add"); |
| | | }; |
| | | const formatFrequencyDetail = detail => { |
| | | if (typeof detail !== "string") return detail; |
| | | const replacements = { |
| | | MON: "å¨ä¸", |
| | | TUE: "å¨äº", |
| | | WED: "å¨ä¸", |
| | | THU: "å¨å", |
| | | FRI: "å¨äº", |
| | | SAT: "å¨å
", |
| | | SUN: "卿¥", |
| | | }; |
| | | return detail.replace( |
| | | /MON|TUE|WED|THU|FRI|SAT|SUN/g, |
| | | match => replacements[match] |
| | | ); |
| | | }; |
| | | |
| | | const formatFileSize = size => { |
| | | if (!size) return "0 B"; |
| | | const formatDateTime = date => { |
| | | if (!date) return "-"; |
| | | return dayjs(date).format("YYYY-MM-DD HH:mm:ss"); |
| | | }; |
| | | |
| | | const units = ["B", "KB", "MB", "GB"]; |
| | | let index = 0; |
| | | let fileSize = size; |
| | | const hasException = ref(null); |
| | | const abnormalDescription = ref(""); |
| | | |
| | | while (fileSize >= 1024 && index < units.length - 1) { |
| | | fileSize /= 1024; |
| | | index += 1; |
| | | } |
| | | const showVideoDialog = ref(false); |
| | | const currentVideoFile = ref(null); |
| | | |
| | | return `${fileSize.toFixed(2)} ${units[index]}`; |
| | | }; |
| | | const uploadConfig = { |
| | | action: "/common/upload", |
| | | limit: 10, |
| | | fileSize: 50, |
| | | fileType: ["jpg", "jpeg", "png", "mp4", "mov"], |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openDialog, |
| | | }); |
| | | const uploadFileUrl = computed( |
| | | () => `${import.meta.env.VITE_APP_BASE_API}${uploadConfig.action}` |
| | | ); |
| | | |
| | | const processFileUrl = fileUrl => { |
| | | if (!fileUrl) return ""; |
| | | |
| | | let currentUrl = String(fileUrl); |
| | | if (currentUrl.includes("\\")) { |
| | | const uploadsIndex = currentUrl.toLowerCase().indexOf("uploads"); |
| | | if (uploadsIndex > -1) { |
| | | currentUrl = `/${currentUrl.substring(uploadsIndex).replace(/\\/g, "/")}`; |
| | | } else { |
| | | const fileName = currentUrl.split("\\").pop(); |
| | | currentUrl = `/uploads/${fileName}`; |
| | | } |
| | | } |
| | | |
| | | if (currentUrl && !currentUrl.startsWith("http")) { |
| | | if (!currentUrl.startsWith("/")) { |
| | | currentUrl = `/${currentUrl}`; |
| | | } |
| | | currentUrl = __BASE_API__ + currentUrl; |
| | | } |
| | | |
| | | return currentUrl; |
| | | }; |
| | | |
| | | const normalizeList = (list, fileType) => { |
| | | if (!Array.isArray(list)) return []; |
| | | |
| | | return list.filter(Boolean).map(item => { |
| | | let currentType = item.type; |
| | | if (!currentType && item.contentType) { |
| | | currentType = item.contentType.startsWith("video") ? "video" : "image"; |
| | | } else if (!currentType) { |
| | | currentType = fileType || "image"; |
| | | } |
| | | |
| | | return { |
| | | ...item, |
| | | url: processFileUrl( |
| | | item.url || item.previewURL || item.downloadUrl || item.path || "" |
| | | ), |
| | | downloadUrl: processFileUrl( |
| | | item.downloadUrl || item.url || item.previewURL || item.path || "" |
| | | ), |
| | | name: item.name || item.originalFilename || item.bucketFilename, |
| | | tempId: item.tempId || item.id || item.tempFileId, |
| | | tempFileId: item.tempFileId || item.tempId || item.id, |
| | | size: item.size || item.byteSize || 0, |
| | | type: currentType, |
| | | status: "success", |
| | | uid: item.uid || `${Date.now()}-${Math.random()}`, |
| | | }; |
| | | }); |
| | | }; |
| | | |
| | | const resetState = () => { |
| | | taskInfo.value = null; |
| | | beforeModelValue.value = []; |
| | | hasException.value = null; |
| | | abnormalDescription.value = ""; |
| | | uploading.value = false; |
| | | uploadProgress.value = 0; |
| | | showVideoDialog.value = false; |
| | | currentVideoFile.value = null; |
| | | operationType.value = "add"; |
| | | }; |
| | | |
| | | const openDialog = (type, row) => { |
| | | operationType.value = type || "add"; |
| | | const raw = JSON.parse(JSON.stringify(row?.__raw || row || {})); |
| | | taskInfo.value = raw; |
| | | |
| | | beforeModelValue.value = normalizeList( |
| | | raw.commonFileListBeforeVO || raw.commonFileListBefore || [], |
| | | "image" |
| | | ); |
| | | |
| | | abnormalDescription.value = raw.abnormalDescription || ""; |
| | | |
| | | if (raw.hasException !== undefined && raw.hasException !== null) { |
| | | hasException.value = raw.hasException; |
| | | } else if ( |
| | | raw.inspectionResult !== undefined && |
| | | raw.inspectionResult !== null |
| | | ) { |
| | | hasException.value = String(raw.inspectionResult) === "0"; |
| | | } else { |
| | | hasException.value = null; |
| | | } |
| | | |
| | | if (hasException.value !== true && beforeModelValue.value.length) { |
| | | hasException.value = true; |
| | | } |
| | | |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleClose = () => { |
| | | dialogVisible.value = false; |
| | | resetState(); |
| | | emit("closeDia"); |
| | | }; |
| | | |
| | | const previewVideo = file => { |
| | | currentVideoFile.value = file; |
| | | showVideoDialog.value = true; |
| | | }; |
| | | |
| | | const uploadFile = async uploadRequest => { |
| | | const rawFile = uploadRequest.file; |
| | | |
| | | if (beforeModelValue.value.length >= uploadConfig.limit) { |
| | | ElMessage.warning(`æå¤åªè½éæ©${uploadConfig.limit}个æä»¶`); |
| | | return; |
| | | } |
| | | |
| | | const ext = rawFile.name.split(".").pop()?.toLowerCase(); |
| | | if (!uploadConfig.fileType.includes(ext)) { |
| | | ElMessage.warning( |
| | | `æä»¶æ ¼å¼ä¸æ¯æï¼è¯·ä¸ä¼ ${uploadConfig.fileType.join("/")} æ ¼å¼` |
| | | ); |
| | | return; |
| | | } |
| | | |
| | | if (rawFile.size > uploadConfig.fileSize * 1024 * 1024) { |
| | | ElMessage.warning(`æä»¶å¤§å°ä¸è½è¶
è¿ ${uploadConfig.fileSize}MB`); |
| | | return; |
| | | } |
| | | |
| | | const token = getToken(); |
| | | if (!token) { |
| | | ElMessage.warning("ç¨æ·æªç»å½"); |
| | | return; |
| | | } |
| | | |
| | | const formData = new FormData(); |
| | | formData.append("files", rawFile); |
| | | formData.append("type", 10); // ç产ååºå®ä¸º10 |
| | | |
| | | uploading.value = true; |
| | | uploadProgress.value = 0; |
| | | |
| | | try { |
| | | const { data } = await axios.post(uploadFileUrl.value, formData, { |
| | | headers: { |
| | | Authorization: `Bearer ${token}`, |
| | | "Content-Type": "multipart/form-data", |
| | | }, |
| | | onUploadProgress: event => { |
| | | if (event.total) { |
| | | uploadProgress.value = Math.round((event.loaded / event.total) * 100); |
| | | } |
| | | }, |
| | | }); |
| | | |
| | | if (data.code !== 200) { |
| | | ElMessage.error(data.msg || "ä¸ä¼ 失败"); |
| | | return; |
| | | } |
| | | |
| | | const resultData = Array.isArray(data.data) ? data.data[0] : data.data; |
| | | const finalUrl = processFileUrl( |
| | | resultData.url || resultData.previewURL || resultData.downloadUrl || "" |
| | | ); |
| | | const finalName = |
| | | resultData.name || |
| | | resultData.originalFilename || |
| | | resultData.bucketFilename; |
| | | const finalId = resultData.tempId || resultData.id || resultData.tempFileId; |
| | | |
| | | const uploadedFile = { |
| | | ...resultData, |
| | | url: finalUrl, |
| | | downloadUrl: finalUrl, |
| | | name: finalName, |
| | | tempId: finalId, |
| | | tempFileId: resultData.tempFileId || finalId, |
| | | size: rawFile.size || resultData.size || resultData.byteSize || 0, |
| | | type: rawFile.type?.startsWith("video") ? "video" : "image", |
| | | status: "success", |
| | | uid: `${Date.now()}-${Math.random()}`, |
| | | }; |
| | | |
| | | beforeModelValue.value.push(uploadedFile); |
| | | ElMessage.success("ä¸ä¼ æå"); |
| | | } catch (error) { |
| | | ElMessage.error(error?.message || "ä¸ä¼ 失败"); |
| | | } finally { |
| | | uploading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const buildFileItem = item => ({ |
| | | id: item?.id, |
| | | tempId: item?.tempId, |
| | | tempFileId: item?.tempFileId, |
| | | url: item?.downloadUrl || item?.url || "", |
| | | downloadUrl: item?.downloadUrl || item?.url || "", |
| | | name: item?.name, |
| | | bucketFilename: item?.bucketFilename || item?.name, |
| | | originalFilename: item?.originalFilename || item?.name, |
| | | size: item?.size || 0, |
| | | byteSize: item?.byteSize || item?.size || 0, |
| | | contentType: item?.contentType || "", |
| | | type: item?.type, |
| | | }); |
| | | |
| | | const submitUpload = async () => { |
| | | if (hasException.value === null) { |
| | | ElMessage.warning("è¯·éæ©å·¡æ£ç¶æ"); |
| | | return; |
| | | } |
| | | |
| | | if (hasException.value === true) { |
| | | const totalFiles = beforeModelValue.value.length; |
| | | |
| | | if (!totalFiles) { |
| | | ElMessage.warning("请ä¸ä¼ å¼å¸¸ç
§çæè§é¢"); |
| | | return; |
| | | } |
| | | |
| | | if (!abnormalDescription.value.trim()) { |
| | | ElMessage.warning("请填åå¼å¸¸æè¿°"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | const loading = ElLoading.service({ |
| | | text: "æäº¤ä¸...", |
| | | background: "rgba(0, 0, 0, 0.3)", |
| | | }); |
| | | |
| | | try { |
| | | const allFiles = [...beforeModelValue.value]; |
| | | |
| | | const tempFileIds = allFiles |
| | | .map(item => item?.tempId ?? item?.tempFileId ?? item?.id) |
| | | .filter(Boolean); |
| | | |
| | | const { |
| | | createTime, |
| | | updateTime, |
| | | storageBlobDTO, |
| | | commonFileListAfterVO, |
| | | commonFileListVO, |
| | | commonFileListBeforeVO, |
| | | commonFileListAfter, |
| | | commonFileList, |
| | | commonFileListBefore, |
| | | __raw, |
| | | ...baseTaskInfo |
| | | } = taskInfo.value || {}; |
| | | |
| | | const submitData = { |
| | | ...baseTaskInfo, |
| | | commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem), |
| | | commonFileListDTO: [], |
| | | commonFileListAfterDTO: [], |
| | | hasException: hasException.value, |
| | | inspectionResult: hasException.value ? 0 : 1, |
| | | abnormalDescription: abnormalDescription.value, |
| | | tempFileIds, |
| | | }; |
| | | |
| | | const result = await uploadInspectionTask(submitData); |
| | | |
| | | if (result && (result.code === 200 || result.success)) { |
| | | ElMessage.success("æäº¤æå"); |
| | | dialogVisible.value = false; |
| | | resetState(); |
| | | emit("success"); |
| | | emit("closeDia"); |
| | | } else { |
| | | ElMessage.error(result?.msg || result?.message || "æäº¤å¤±è´¥"); |
| | | } |
| | | } catch (error) { |
| | | ElMessage.error(error?.message || "æäº¤å¤±è´¥"); |
| | | } finally { |
| | | loading.close(); |
| | | } |
| | | }; |
| | | |
| | | const removeFile = async index => { |
| | | try { |
| | | await ElMessageBox.confirm("ç¡®å®è¦å é¤è¿ä¸ªæä»¶åï¼", "确认å é¤", { |
| | | type: "warning", |
| | | }); |
| | | beforeModelValue.value.splice(index, 1); |
| | | } catch {} |
| | | }; |
| | | |
| | | const goToRepair = () => { |
| | | const taskData = { |
| | | taskId: taskInfo.value?.taskId || taskInfo.value?.id, |
| | | taskName: taskInfo.value?.taskName, |
| | | inspectionLocation: taskInfo.value?.inspectionLocation, |
| | | inspector: taskInfo.value?.inspector, |
| | | hasException: hasException.value, |
| | | inspectionResult: hasException.value ? 0 : 1, |
| | | commonFileListBeforeDTO: beforeModelValue.value.map(buildFileItem), |
| | | commonFileListDTO: [], |
| | | commonFileListAfterDTO: [], |
| | | uploadedFiles: { |
| | | before: beforeModelValue.value, |
| | | after: [], |
| | | issue: [], |
| | | }, |
| | | }; |
| | | |
| | | sessionStorage.setItem("repairTaskInfo", JSON.stringify(taskData)); |
| | | router.push("/equipmentManagement/repair/add"); |
| | | }; |
| | | |
| | | const formatFileSize = size => { |
| | | if (!size) return "0 B"; |
| | | |
| | | const units = ["B", "KB", "MB", "GB"]; |
| | | let index = 0; |
| | | let fileSize = size; |
| | | |
| | | while (fileSize >= 1024 && index < units.length - 1) { |
| | | fileSize /= 1024; |
| | | index += 1; |
| | | } |
| | | |
| | | return `${fileSize.toFixed(2)} ${units[index]}`; |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openDialog, |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .inspection-upload-page { |
| | | min-height: 70vh; |
| | | background: #f5f7fa; |
| | | padding: 20px 20px 90px; |
| | | box-sizing: border-box; |
| | | } |
| | | .inspection-upload-page { |
| | | min-height: 70vh; |
| | | background: #f5f7fa; |
| | | padding: 20px 20px 90px; |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | .upload-content { |
| | | max-width: 960px; |
| | | margin: 20px auto 0; |
| | | } |
| | | .upload-content { |
| | | max-width: 960px; |
| | | margin: 20px auto 0; |
| | | } |
| | | |
| | | .section-card { |
| | | margin-bottom: 16px; |
| | | } |
| | | .section-card { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .section-card h3 { |
| | | margin: 0 0 16px; |
| | | font-size: 16px; |
| | | } |
| | | .section-card h3 { |
| | | margin: 0 0 16px; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .upload-buttons { |
| | | display: flex; |
| | | gap: 12px; |
| | | margin: 16px 0; |
| | | } |
| | | .upload-buttons { |
| | | display: flex; |
| | | gap: 12px; |
| | | margin: 16px 0; |
| | | } |
| | | |
| | | .upload-progress { |
| | | margin-bottom: 16px; |
| | | } |
| | | .upload-progress { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | .file-list { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); |
| | | gap: 12px; |
| | | } |
| | | .file-list { |
| | | display: grid; |
| | | grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); |
| | | gap: 12px; |
| | | } |
| | | |
| | | .file-preview-container { |
| | | position: relative; |
| | | aspect-ratio: 1; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | background: #f2f3f5; |
| | | } |
| | | .file-preview-container { |
| | | position: relative; |
| | | aspect-ratio: 1; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | background: #f2f3f5; |
| | | } |
| | | |
| | | .file-preview { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | .file-preview { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .video-preview { |
| | | width: 100%; |
| | | height: 100%; |
| | | background: #303133; |
| | | color: #fff; |
| | | display: flex; |
| | | gap: 6px; |
| | | align-items: center; |
| | | justify-content: center; |
| | | cursor: pointer; |
| | | } |
| | | .video-preview { |
| | | width: 100%; |
| | | height: 100%; |
| | | background: #303133; |
| | | color: #fff; |
| | | display: flex; |
| | | gap: 6px; |
| | | align-items: center; |
| | | justify-content: center; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .delete-btn { |
| | | position: absolute; |
| | | top: 6px; |
| | | right: 6px; |
| | | } |
| | | .delete-btn { |
| | | position: absolute; |
| | | top: 6px; |
| | | right: 6px; |
| | | } |
| | | |
| | | .file-info { |
| | | margin-top: 6px; |
| | | font-size: 12px; |
| | | } |
| | | .file-info { |
| | | margin-top: 6px; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .file-name { |
| | | color: #606266; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | .file-name { |
| | | color: #606266; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .file-size { |
| | | color: #909399; |
| | | margin-top: 2px; |
| | | } |
| | | .file-size { |
| | | color: #909399; |
| | | margin-top: 2px; |
| | | } |
| | | |
| | | .upload-summary { |
| | | margin-top: 16px; |
| | | } |
| | | .upload-summary { |
| | | margin-top: 16px; |
| | | } |
| | | |
| | | .footer-buttons { |
| | | position: sticky; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | padding: 14px 20px 0; |
| | | background: #f5f7fa; |
| | | display: flex; |
| | | justify-content: center; |
| | | gap: 12px; |
| | | } |
| | | .footer-buttons { |
| | | position: sticky; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | padding: 14px 20px 0; |
| | | background: #f5f7fa; |
| | | display: flex; |
| | | justify-content: center; |
| | | gap: 12px; |
| | | } |
| | | |
| | | .video-player { |
| | | width: 100%; |
| | | max-height: 70vh; |
| | | background: #000; |
| | | } |
| | | .video-player { |
| | | width: 100%; |
| | | max-height: 70vh; |
| | | background: #000; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog title="æ¥çéä»¶" v-model="dialogVisitable" width="800px" @close="cancel"> |
| | | <el-dialog title="æ¥çéä»¶" |
| | | v-model="dialogVisitable" |
| | | width="800px" |
| | | @close="cancel"> |
| | | <div class="upload-container"> |
| | | <div class="form-container"> |
| | | <div class="title">ç产å</div> |
| | | |
| | | <div class="title">å¾çå表</div> |
| | | <div class="media-list"> |
| | | <img |
| | | v-for="(item, index) in beforeProductionImgs" |
| | | :key="`before-img-${index}`" |
| | | :src="item" |
| | | alt="" |
| | | class="media-image" |
| | | @click="showMedia(beforeProductionImgs, index, 'image')" |
| | | /> |
| | | <img v-for="(item, index) in beforeProductionImgs" |
| | | :key="`before-img-${index}`" |
| | | :src="item" |
| | | alt="" |
| | | class="media-image" |
| | | @click="showMedia(beforeProductionImgs, index, 'image')" /> |
| | | </div> |
| | | |
| | | <div class="media-list"> |
| | | <div |
| | | v-for="(videoUrl, index) in beforeProductionVideos" |
| | | :key="`before-video-${index}`" |
| | | class="video-item" |
| | | @click="showMedia(beforeProductionVideos, index, 'video')" |
| | | > |
| | | <div v-for="(videoUrl, index) in beforeProductionVideos" |
| | | :key="`before-video-${index}`" |
| | | class="video-item" |
| | | @click="showMedia(beforeProductionVideos, index, 'video')"> |
| | | <div class="video-thumb"> |
| | | <img src="@/assets/images/video.png" alt="ææ¾" class="video-icon" /> |
| | | <img src="@/assets/images/video.png" |
| | | alt="ææ¾" |
| | | class="video-icon" /> |
| | | </div> |
| | | <div class="video-text">ç¹å»ææ¾</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="form-container"> |
| | | <!-- <div class="form-container"> |
| | | <div class="title">ç产ä¸</div> |
| | | |
| | | <div class="media-list"> |
| | |
| | | <div class="video-text">ç¹å»ææ¾</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> --> |
| | | </div> |
| | | </el-dialog> |
| | | |
| | | <div v-if="isMediaViewerVisible" class="media-viewer-overlay" @click.self="closeMediaViewer"> |
| | | <div class="media-viewer-content" @click.stop> |
| | | <vue-easy-lightbox |
| | | v-if="mediaType === 'image'" |
| | | :visible="isMediaViewerVisible" |
| | | :imgs="mediaList" |
| | | :index="currentMediaIndex" |
| | | @hide="closeMediaViewer" |
| | | /> |
| | | |
| | | <div v-else-if="mediaType === 'video'" class="video-player-wrap"> |
| | | <video :src="mediaList[currentMediaIndex]" autoplay controls class="video-player" /> |
| | | <div v-if="isMediaViewerVisible" |
| | | class="media-viewer-overlay" |
| | | @click.self="closeMediaViewer"> |
| | | <div class="media-viewer-content" |
| | | @click.stop> |
| | | <vue-easy-lightbox v-if="mediaType === 'image'" |
| | | :visible="isMediaViewerVisible" |
| | | :imgs="mediaList" |
| | | :index="currentMediaIndex" |
| | | @hide="closeMediaViewer" /> |
| | | <div v-else-if="mediaType === 'video'" |
| | | class="video-player-wrap"> |
| | | <video :src="mediaList[currentMediaIndex]" |
| | | autoplay |
| | | controls |
| | | class="video-player" /> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from "vue"; |
| | | import VueEasyLightbox from "vue-easy-lightbox"; |
| | | import { ref } from "vue"; |
| | | import VueEasyLightbox from "vue-easy-lightbox"; |
| | | |
| | | const dialogVisitable = ref(false); |
| | | const dialogVisitable = ref(false); |
| | | |
| | | const beforeProductionImgs = ref([]); |
| | | const afterProductionImgs = ref([]); |
| | | const productionIssuesImgs = ref([]); |
| | | const beforeProductionImgs = ref([]); |
| | | const afterProductionImgs = ref([]); |
| | | const productionIssuesImgs = ref([]); |
| | | |
| | | const beforeProductionVideos = ref([]); |
| | | const afterProductionVideos = ref([]); |
| | | const productionIssuesVideos = ref([]); |
| | | const beforeProductionVideos = ref([]); |
| | | const afterProductionVideos = ref([]); |
| | | const productionIssuesVideos = ref([]); |
| | | |
| | | const isMediaViewerVisible = ref(false); |
| | | const currentMediaIndex = ref(0); |
| | | const mediaList = ref([]); |
| | | const mediaType = ref("image"); |
| | | const isMediaViewerVisible = ref(false); |
| | | const currentMediaIndex = ref(0); |
| | | const mediaList = ref([]); |
| | | const mediaType = ref("image"); |
| | | |
| | | const processFileUrl = fileUrl => { |
| | | if (!fileUrl) return ""; |
| | | const processFileUrl = fileUrl => { |
| | | if (!fileUrl) return ""; |
| | | |
| | | let currentUrl = String(fileUrl); |
| | | if (currentUrl.includes("\\")) { |
| | | const uploadsIndex = currentUrl.toLowerCase().indexOf("uploads"); |
| | | if (uploadsIndex > -1) { |
| | | currentUrl = `/${currentUrl.substring(uploadsIndex).replace(/\\/g, "/")}`; |
| | | } else { |
| | | const fileName = currentUrl.split("\\").pop(); |
| | | currentUrl = `/uploads/${fileName}`; |
| | | let currentUrl = String(fileUrl); |
| | | if (currentUrl.includes("\\")) { |
| | | const uploadsIndex = currentUrl.toLowerCase().indexOf("uploads"); |
| | | if (uploadsIndex > -1) { |
| | | currentUrl = `/${currentUrl.substring(uploadsIndex).replace(/\\/g, "/")}`; |
| | | } else { |
| | | const fileName = currentUrl.split("\\").pop(); |
| | | currentUrl = `/uploads/${fileName}`; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (currentUrl && !currentUrl.startsWith("http")) { |
| | | if (!currentUrl.startsWith("/")) { |
| | | currentUrl = `/${currentUrl}`; |
| | | if (currentUrl && !currentUrl.startsWith("http")) { |
| | | if (!currentUrl.startsWith("/")) { |
| | | currentUrl = `/${currentUrl}`; |
| | | } |
| | | currentUrl = __BASE_API__ + currentUrl; |
| | | } |
| | | currentUrl = __BASE_API__ + currentUrl; |
| | | } |
| | | |
| | | return currentUrl; |
| | | }; |
| | | return currentUrl; |
| | | }; |
| | | |
| | | const processItems = items => { |
| | | const images = []; |
| | | const videos = []; |
| | | const processItems = items => { |
| | | const images = []; |
| | | const videos = []; |
| | | |
| | | if (!Array.isArray(items)) { |
| | | if (!Array.isArray(items)) { |
| | | return { images, videos }; |
| | | } |
| | | |
| | | items.forEach(item => { |
| | | if (!item) return; |
| | | |
| | | const fileUrl = processFileUrl( |
| | | item.previewURL || item.url || item.downloadUrl || item.path || "" |
| | | ); |
| | | const contentType = String(item.contentType || "").toLowerCase(); |
| | | |
| | | if (!fileUrl) return; |
| | | |
| | | if (contentType.startsWith("video/")) { |
| | | videos.push(fileUrl); |
| | | return; |
| | | } |
| | | |
| | | images.push(fileUrl); |
| | | }); |
| | | |
| | | return { images, videos }; |
| | | } |
| | | }; |
| | | |
| | | items.forEach(item => { |
| | | if (!item) return; |
| | | |
| | | const fileUrl = processFileUrl( |
| | | item.previewURL || item.url || item.downloadUrl || item.path || "" |
| | | const openDialog = row => { |
| | | const { images: beforeImgs, videos: beforeVids } = processItems( |
| | | row.commonFileListBeforeVO || [] |
| | | ); |
| | | const contentType = String(item.contentType || "").toLowerCase(); |
| | | const { images: afterImgs, videos: afterVids } = processItems( |
| | | row.commonFileListVO || [] |
| | | ); |
| | | const { images: issueImgs, videos: issueVids } = processItems( |
| | | row.commonFileListAfterVO || [] |
| | | ); |
| | | |
| | | if (!fileUrl) return; |
| | | beforeProductionImgs.value = beforeImgs; |
| | | beforeProductionVideos.value = beforeVids; |
| | | afterProductionImgs.value = afterImgs; |
| | | afterProductionVideos.value = afterVids; |
| | | productionIssuesImgs.value = issueImgs; |
| | | productionIssuesVideos.value = issueVids; |
| | | dialogVisitable.value = true; |
| | | }; |
| | | |
| | | if (contentType.startsWith("video/")) { |
| | | videos.push(fileUrl); |
| | | return; |
| | | } |
| | | const showMedia = (items, index, type) => { |
| | | mediaList.value = items; |
| | | currentMediaIndex.value = index; |
| | | mediaType.value = type; |
| | | isMediaViewerVisible.value = true; |
| | | }; |
| | | |
| | | images.push(fileUrl); |
| | | }); |
| | | const closeMediaViewer = () => { |
| | | isMediaViewerVisible.value = false; |
| | | mediaList.value = []; |
| | | mediaType.value = "image"; |
| | | }; |
| | | |
| | | return { images, videos }; |
| | | }; |
| | | const cancel = () => { |
| | | dialogVisitable.value = false; |
| | | }; |
| | | |
| | | const openDialog = row => { |
| | | const { images: beforeImgs, videos: beforeVids } = processItems( |
| | | row.commonFileListBeforeVO || [] |
| | | ); |
| | | const { images: afterImgs, videos: afterVids } = processItems( |
| | | row.commonFileListVO || [] |
| | | ); |
| | | const { images: issueImgs, videos: issueVids } = processItems( |
| | | row.commonFileListAfterVO || [] |
| | | ); |
| | | |
| | | beforeProductionImgs.value = beforeImgs; |
| | | beforeProductionVideos.value = beforeVids; |
| | | afterProductionImgs.value = afterImgs; |
| | | afterProductionVideos.value = afterVids; |
| | | productionIssuesImgs.value = issueImgs; |
| | | productionIssuesVideos.value = issueVids; |
| | | dialogVisitable.value = true; |
| | | }; |
| | | |
| | | const showMedia = (items, index, type) => { |
| | | mediaList.value = items; |
| | | currentMediaIndex.value = index; |
| | | mediaType.value = type; |
| | | isMediaViewerVisible.value = true; |
| | | }; |
| | | |
| | | const closeMediaViewer = () => { |
| | | isMediaViewerVisible.value = false; |
| | | mediaList.value = []; |
| | | mediaType.value = "image"; |
| | | }; |
| | | |
| | | const cancel = () => { |
| | | dialogVisitable.value = false; |
| | | }; |
| | | |
| | | defineExpose({ openDialog }); |
| | | defineExpose({ openDialog }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .upload-container { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | padding: 20px; |
| | | border: 1px solid #dcdfe6; |
| | | box-sizing: border-box; |
| | | .upload-container { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | padding: 20px; |
| | | border: 1px solid #dcdfe6; |
| | | box-sizing: border-box; |
| | | |
| | | .form-container { |
| | | flex: 1; |
| | | width: 100%; |
| | | margin-bottom: 20px; |
| | | .form-container { |
| | | flex: 1; |
| | | width: 100%; |
| | | margin-bottom: 20px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .title { |
| | | font-size: 14px; |
| | | color: #165dff; |
| | | line-height: 20px; |
| | | font-weight: 600; |
| | | padding-left: 10px; |
| | | position: relative; |
| | | margin: 6px 0; |
| | | .title { |
| | | font-size: 14px; |
| | | color: #165dff; |
| | | line-height: 20px; |
| | | font-weight: 600; |
| | | padding-left: 10px; |
| | | position: relative; |
| | | margin: 6px 0; |
| | | |
| | | &::before { |
| | | content: ""; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 3px; |
| | | width: 4px; |
| | | height: 14px; |
| | | background-color: #165dff; |
| | | &::before { |
| | | content: ""; |
| | | position: absolute; |
| | | left: 0; |
| | | top: 3px; |
| | | width: 4px; |
| | | height: 14px; |
| | | background-color: #165dff; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .media-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | } |
| | | .media-list { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | .media-image { |
| | | max-width: 100px; |
| | | height: 100px; |
| | | margin: 5px; |
| | | cursor: pointer; |
| | | } |
| | | .media-image { |
| | | max-width: 100px; |
| | | height: 100px; |
| | | margin: 5px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .video-item { |
| | | position: relative; |
| | | margin: 10px; |
| | | cursor: pointer; |
| | | } |
| | | .video-item { |
| | | position: relative; |
| | | margin: 10px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .video-thumb { |
| | | width: 160px; |
| | | height: 90px; |
| | | background-color: #333; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .video-thumb { |
| | | width: 160px; |
| | | height: 90px; |
| | | background-color: #333; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .video-icon { |
| | | width: 30px; |
| | | height: 30px; |
| | | opacity: 0.8; |
| | | } |
| | | .video-icon { |
| | | width: 30px; |
| | | height: 30px; |
| | | opacity: 0.8; |
| | | } |
| | | |
| | | .video-text { |
| | | text-align: center; |
| | | font-size: 12px; |
| | | color: #666; |
| | | } |
| | | .video-text { |
| | | text-align: center; |
| | | font-size: 12px; |
| | | color: #666; |
| | | } |
| | | |
| | | .media-viewer-overlay { |
| | | position: fixed; |
| | | inset: 0; |
| | | background-color: rgba(0, 0, 0, 0.8); |
| | | z-index: 9999; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | .media-viewer-overlay { |
| | | position: fixed; |
| | | inset: 0; |
| | | background-color: rgba(0, 0, 0, 0.8); |
| | | z-index: 9999; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .media-viewer-content { |
| | | position: relative; |
| | | max-width: 90vw; |
| | | max-height: 90vh; |
| | | overflow: hidden; |
| | | } |
| | | .media-viewer-content { |
| | | position: relative; |
| | | max-width: 90vw; |
| | | max-height: 90vh; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .video-player-wrap { |
| | | position: relative; |
| | | } |
| | | .video-player-wrap { |
| | | position: relative; |
| | | } |
| | | |
| | | .video-player { |
| | | max-width: 90vw; |
| | | max-height: 80vh; |
| | | } |
| | | .video-player { |
| | | max-width: 90vw; |
| | | max-height: 80vh; |
| | | } |
| | | </style> |
| | |
| | | total: total, |
| | | layout: 'total, sizes, prev, pager, next, jumper' |
| | | }" |
| | | :table-style="{ width: '100%', height: 'calc(100vh - 23em)' }"> |
| | | height="calc(100vh - 23em)" |
| | | :table-style="{ width: '100%' }"> |
| | | <template #inspector="{ row }"> |
| | | <div class="person-tags"> |
| | | <!-- è°è¯ä¿¡æ¯ï¼ä¸çº¿æ¶å é¤ --> |
| | |
| | | // åéæ¡é
ç½® |
| | | const activeRadio = ref("taskManage"); |
| | | const radios = reactive([ |
| | | { name: "taskManage", label: "宿¶ä»»å¡ç®¡ç" }, |
| | | { name: "task", label: "宿¶ä»»å¡è®°å½" }, |
| | | { name: "taskManage", label: "å·¡æ£ä»»å¡" }, |
| | | { name: "task", label: "å·¡æ£è®°å½" }, |
| | | ]); |
| | | |
| | | // è¡¨æ ¼æ°æ® |
| | |
| | | |
| | | // åé
ç½® |
| | | const columns = ref([ |
| | | { prop: "taskName", label: "å·¡æ£ä»»å¡åç§°", minWidth: 160 }, |
| | | { prop: "inspectionProject", label: "å·¡æ£é¡¹ç®", minWidth: 150 }, |
| | | { prop: "remarks", label: "夿³¨", minWidth: 150 }, |
| | | { prop: "inspector", label: "æ§è¡å·¡æ£äºº", minWidth: 150, slot: "inspector" }, |
| | | { prop: "taskName", label: "å·¡æ£ä»»å¡åç§°", minWidth: 200 }, |
| | | { prop: "inspectionProject", label: "å·¡æ£é¡¹ç®", minWidth: 180 }, |
| | | { prop: "remarks", label: "夿³¨", minWidth: 180 }, |
| | | { prop: "inspector", label: "æ§è¡å·¡æ£äºº", minWidth: 180, slot: "inspector" }, |
| | | { |
| | | prop: "isEnabled", |
| | | label: "æ¯å¦å¯ç¨", |
| | |
| | | { |
| | | prop: "frequencyType", |
| | | label: "颿¬¡", |
| | | minWidth: 150, |
| | | // formatter: (_, __, val) => ({ |
| | | // DAILY: "æ¯æ¥", |
| | | // WEEKLY: "æ¯å¨", |
| | | // MONTHLY: "æ¯æ", |
| | | // QUARTERLY: "å£åº¦" |
| | | // }[val] || "") |
| | | minWidth: 120, |
| | | formatData: params => { |
| | | return params === "DAILY" |
| | | ? "æ¯æ¥" |
| | |
| | | { |
| | | prop: "frequencyDetail", |
| | | label: "å¼å§æ¥æä¸æ¶é´", |
| | | minWidth: 150, |
| | | minWidth: 200, |
| | | formatter: (row, column, cellValue) => { |
| | | // å
夿æ¯å¦æ¯å符串 |
| | | if (typeof cellValue !== "string") return ""; |
| | |
| | | ); |
| | | }, |
| | | }, |
| | | { prop: "registrant", label: "ç»è®°äºº", minWidth: 100 }, |
| | | { prop: "registrant", label: "ç»è®°äºº", minWidth: 120 }, |
| | | { |
| | | prop: "createTime", |
| | | label: "ç»è®°æ¥æ", |
| | | minWidth: 100, |
| | | minWidth: 180, |
| | | formatData: cell => { |
| | | if (!cell) return "-"; |
| | | try { |
| | |
| | | } |
| | | }, |
| | | }, |
| | | { |
| | | prop: "inspectionResult", |
| | | label: "å·¡æ£ç»æ", |
| | | minWidth: 100, |
| | | dataType: "tag", |
| | | formatData: val => { |
| | | return val == 1 ? "æ£å¸¸" : "å¼å¸¸"; |
| | | }, |
| | | formatType: val => { |
| | | return val == 1 ? "success" : "danger"; |
| | | }, |
| | | }, |
| | | { prop: "abnormalDescription", label: "å¼å¸¸æè¿°", minWidth: 100 }, |
| | | // { |
| | | // prop: "inspectionResult", |
| | | // label: "å·¡æ£ç»æ", |
| | | // minWidth: 100, |
| | | // dataType: "tag", |
| | | // formatData: val => { |
| | | // return val == 1 ? "æ£å¸¸" : "å¼å¸¸"; |
| | | // }, |
| | | // formatType: val => { |
| | | // return val == 1 ? "success" : "danger"; |
| | | // }, |
| | | // }, |
| | | { prop: "abnormalDescription", label: "å¼å¸¸æè¿°", minWidth: 150 }, |
| | | ]); |
| | | |
| | | // æä½åé
ç½® |
| | |
| | | label: "æä½", |
| | | width: operations.length > 1 ? 180 : 130, |
| | | fixed: "right", |
| | | align: 'center', |
| | | align: "center", |
| | | dataType: "action", |
| | | operation: operations |
| | | .map(op => { |
| | | switch (op) { |
| | | case "view": |
| | | return { |
| | | name: "详æ
", |
| | | clickFun: openViewDialog, |
| | | color: "#409EFF", |
| | | }; |
| | | case "edit": |
| | | return { |
| | | name: "ç¼è¾", |
| | |
| | | ]; |
| | | operationsArr.value = ["edit"]; |
| | | } else if (value === "task") { |
| | | const operationColumn = getOperationColumn(["upload", "viewFile"]); |
| | | // 宿¶ä»»å¡è®°å½ä¸å±ç¤º"æ¯å¦å¯ç¨"å |
| | | const operationColumn = getOperationColumn(["view", "upload", "viewFile"]); |
| | | // å·¡æ£è®°å½ä¸å±ç¤º"æ¯å¦å¯ç¨"å |
| | | const taskColumns = columns.value.filter(col => col.prop !== "isEnabled"); |
| | | tableColumns.value = [ |
| | | ...taskColumns, |
| | | ...(operationColumn ? [operationColumn] : []), |
| | | ]; |
| | | operationsArr.value = ["upload", "viewFile"]; |
| | | operationsArr.value = ["view", "upload", "viewFile"]; |
| | | } |
| | | pageNum.value = 1; |
| | | pageSize.value = 10; |
| | |
| | | |
| | | const openUploadDialog = row => { |
| | | nextTick(() => { |
| | | uploadFiles.value?.openDialog(row); |
| | | uploadFiles.value?.openDialog("add", row); |
| | | }); |
| | | }; |
| | | |
| | | const openViewDialog = row => { |
| | | nextTick(() => { |
| | | uploadFiles.value?.openDialog("view", row); |
| | | }); |
| | | }; |
| | | |
| | |
| | | .then(() => { |
| | | // æ ¹æ®å½åéä¸çæ ç¾é¡µè°ç¨ä¸åçå¯¼åºæ¥å£ |
| | | if (activeRadio.value === "taskManage") { |
| | | // 宿¶ä»»å¡ç®¡ç |
| | | proxy.download("/timingTask/export", {}, "宿¶ä»»å¡ç®¡ç.xlsx"); |
| | | // å·¡æ£ä»»å¡ |
| | | proxy.download("/timingTask/export", {}, "å·¡æ£ä»»å¡.xlsx"); |
| | | } else if (activeRadio.value === "task") { |
| | | // 宿¶ä»»å¡è®°å½ |
| | | proxy.download("/inspectionTask/export", {}, "宿¶ä»»å¡è®°å½.xlsx"); |
| | | // å·¡æ£è®°å½ |
| | | proxy.download("/inspectionTask/export", {}, "å·¡æ£è®°å½.xlsx"); |
| | | } |
| | | }) |
| | | .catch(() => { |
| | |
| | | <template> |
| | | <div> |
| | | <el-dialog |
| | | v-model="dialogFormVisible" |
| | | title="ä¸ä¼ éä»¶" |
| | | width="50%" |
| | | @close="closeDia" |
| | | > |
| | | <el-dialog v-model="dialogFormVisible" title="ä¸ä¼ éä»¶" width="50%" @close="closeDia"> |
| | | <div style="margin-bottom: 10px;text-align: right"> |
| | | <el-upload |
| | | v-model:file-list="fileList" |
| | | class="upload-demo" |
| | | :action="uploadUrl" |
| | | :on-success="handleUploadSuccess" |
| | | :on-error="handleUploadError" |
| | | name="files" |
| | | :show-file-list="false" |
| | | :headers="headers" |
| | | style="display: inline;margin-right: 10px" |
| | | > |
| | | <el-upload v-model:file-list="fileList" class="upload-demo" :action="uploadUrl" |
| | | :on-success="handleUploadSuccess" :on-error="handleUploadError" name="files" :show-file-list="false" |
| | | :headers="headers" style="display: inline;margin-right: 10px"> |
| | | <el-button type="primary">ä¸ä¼ éä»¶</el-button> |
| | | </el-upload> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :tableLoading="tableLoading" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="paginationSearch" |
| | | height="500" |
| | | > |
| | | <PIMTable rowKey="id" :column="tableColumn" :tableData="tableData" :page="page" :tableLoading="tableLoading" |
| | | :isSelection="true" @selection-change="handleSelectionChange" @pagination="paginationSearch" height="500"> |
| | | </PIMTable> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, reactive, getCurrentInstance} from "vue"; |
| | | import {ElMessageBox} from "element-plus"; |
| | | import {getToken} from "@/utils/auth.js"; |
| | | import { ref, reactive, getCurrentInstance } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import { getToken } from "@/utils/auth.js"; |
| | | import filePreview from '@/components/filePreview/index.vue' |
| | | import PIMTable from "@/components/PIMTable/PIMTable.vue"; |
| | | import { |
| | |
| | | }, |
| | | ]); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const tableData = ref([]); |
| | | const fileList = ref([]); |
| | |
| | | const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/common/upload"); // ä¸ä¼ çæå¡å¨å°å |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openDialog = (row,type) => { |
| | | const openDialog = (row, type) => { |
| | | accountType.value = type; |
| | | dialogFormVisible.value = true; |
| | | currentId.value = row.id; |
| | | getList() |
| | | } |
| | | const paginationSearch = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | // å端å页æä¸å¤çï¼ç´æ¥è°ç¨è·åå
¨éå表 |
| | | getList(); |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | // å端å页æä¸å¤çï¼ç´æ¥è°ç¨è·åå
¨éå表 |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | getStorageAttachmentList({recordId: currentId.value, recordType: accountType.value}).then(res => { |
| | | getStorageAttachmentList({ recordId: currentId.value, recordType: accountType.value }).then(res => { |
| | | tableData.value = res.data; |
| | | page.total = res.data ? res.data.length : 0; |
| | | page.total = res.data ? res.data.length : 0; |
| | | }) |
| | | } |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | |
| | | function handleUploadSuccess(res, file) { |
| | | // 妿ä¸ä¼ æå |
| | | if (res.code == 200 && res.data && res.data.length > 0) { |
| | | const mergedFiles = [...tableData.value, ...res.data]; |
| | | const newFiles = res.data.map(item => ({ |
| | | ...item, |
| | | name: item.originalFilename || item.name |
| | | })); |
| | | const mergedFiles = [...(tableData.value || []), ...newFiles]; |
| | | const storageAttachmentDTO = { |
| | | recordType: accountType.value, |
| | | recordId: currentId.value, |
| | |
| | | } |
| | | // ä¸è½½éä»¶ |
| | | const downLoadFile = (row) => { |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | proxy.$download.byUrl(row.url, row.originalFilename); |
| | | } |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | |
| | | </style> |
| | | <style scoped></style> |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">å½å
¥æ¥æï¼</span> |
| | | <el-date-picker |
| | | v-model="searchForm.recordDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 160px" |
| | | @change="handleQuery" |
| | | /> |
| | | <span class="search_title ml10">计éå¨å
·ç¼å·ï¼</span> |
| | | <el-input v-model="searchForm.code" placeholder="请è¾å
¥ç¼å·" clearable style="width: 240px" @change="handleQuery"/> |
| | | <span class="search_title ml10">ç¶æï¼</span> |
| | | <el-select v-model="searchForm.status" placeholder="è¯·éæ©ç¶æ" @change="handleQuery" style="width: 160px" clearable> |
| | | <el-option label="ææ" :value="1"></el-option> |
| | | <el-option label="龿" :value="2"></el-option> |
| | | </el-select> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px" |
| | | >æç´¢</el-button |
| | | > |
| | | <el-button @click="handleReset" style="margin-left: 10px">éç½®</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="openForm('add')">æ°å¢è®¡éå¨å
·</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :dbRowClick="dbRowClick" |
| | | :rowClassName="rowClassName" |
| | | ></PIMTable> |
| | | </div> |
| | | <form-dia ref="formDia" @close="handleQuery"></form-dia> |
| | | <calibration-dia ref="calibrationDia" @close="handleQuery"></calibration-dia> |
| | | <div class="app-container"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">å½å
¥æ¥æï¼</span> |
| | | <el-date-picker v-model="searchForm.recordDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 160px" |
| | | @change="handleQuery" /> |
| | | <span class="search_title ml10">计éå¨å
·ç¼å·ï¼</span> |
| | | <el-input v-model="searchForm.code" |
| | | placeholder="请è¾å
¥ç¼å·" |
| | | clearable |
| | | style="width: 240px" |
| | | @change="handleQuery" /> |
| | | <span class="search_title ml10">ç¶æï¼</span> |
| | | <el-select v-model="searchForm.status" |
| | | placeholder="è¯·éæ©ç¶æ" |
| | | @change="handleQuery" |
| | | style="width: 160px" |
| | | clearable> |
| | | <el-option label="ææ" |
| | | :value="1"></el-option> |
| | | <el-option label="龿" |
| | | :value="2"></el-option> |
| | | </el-select> |
| | | <el-button type="primary" |
| | | @click="handleQuery" |
| | | style="margin-left: 10px">æç´¢</el-button> |
| | | <el-button @click="handleReset" |
| | | style="margin-left: 10px">éç½®</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢è®¡éå¨å
·</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | :dbRowClick="dbRowClick" |
| | | :rowClassName="rowClassName"></PIMTable> |
| | | </div> |
| | | <form-dia ref="formDia" |
| | | @close="handleQuery"></form-dia> |
| | | <calibration-dia ref="calibrationDia" |
| | | @close="handleQuery"></calibration-dia> |
| | | <files-dia ref="filesDia"></files-dia> |
| | | <rowClickDataForm ref="rowClickData"></rowClickDataForm> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick} from "vue"; |
| | | import FormDia from "@/views/equipmentManagement/measurementEquipment/components/formDia.vue"; |
| | | import {ElMessageBox} from "element-plus"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | import CalibrationDia from "@/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue"; |
| | | import { |
| | | measuringInstrumentDelete, |
| | | measuringInstrumentListPage, |
| | | } from "@/api/equipmentManagement/measurementEquipment.js"; |
| | | import FilesDia from "./filesDia.vue"; |
| | | import rowClickDataForm from "./components/rowClickData.vue" |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore() |
| | | import { |
| | | onMounted, |
| | | ref, |
| | | reactive, |
| | | toRefs, |
| | | getCurrentInstance, |
| | | nextTick, |
| | | } from "vue"; |
| | | import FormDia from "@/views/equipmentManagement/measurementEquipment/components/formDia.vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | import CalibrationDia from "@/views/equipmentManagement/measurementEquipment/components/calibrationDia.vue"; |
| | | import { |
| | | measuringInstrumentDelete, |
| | | measuringInstrumentListPage, |
| | | } from "@/api/equipmentManagement/measurementEquipment.js"; |
| | | import FilesDia from "./filesDia.vue"; |
| | | import rowClickDataForm from "./components/rowClickData.vue"; |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | recordDate: "", |
| | | code: "", |
| | | status: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | recordDate: "", |
| | | code: "", |
| | | status: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "åºåç¼å·", |
| | | prop: "code", |
| | | minWidth:150, |
| | | align:"center" |
| | | }, |
| | | { |
| | | label: "计éå¨å
·åç§°", |
| | | prop: "name", |
| | | width: '160px', |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "æ£å®åä½", |
| | | prop: "unit", |
| | | width: 200, |
| | | align:"center" |
| | | }, |
| | | { |
| | | label: "è¯ä¹¦ç¼å·", |
| | | prop: "model", |
| | | width:200, |
| | | align:"center" |
| | | }, |
| | | { |
| | | label: "ææ°é´å®æ¥æ", |
| | | prop: "mostDate", |
| | | width: 130, |
| | | align:"center" |
| | | }, |
| | | { |
| | | label: "å½å
¥äºº", |
| | | prop: "userName", |
| | | width: 130, |
| | | align:"center" |
| | | }, |
| | | { |
| | | label: "å½å
¥æ¥æ", |
| | | prop: "recordDate", |
| | | align:"center", |
| | | minWidth: 130 |
| | | }, |
| | | { |
| | | label: "æææ¥æ", |
| | | prop: "valid", |
| | | width: 130, |
| | | align:"center" |
| | | }, |
| | | { |
| | | label: "ç¶æ", |
| | | prop: "status", |
| | | width: 130, |
| | | align: "center", |
| | | formatData: (params) => { |
| | | if (params === 1) { |
| | | return "ææ"; |
| | | } else if (params === 2) { |
| | | return "龿"; |
| | | } else { |
| | | return null; |
| | | } |
| | | } |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | width: '130', |
| | | fixed: 'right', |
| | | operation: [ |
| | | { |
| | | name: "éä»¶", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openFilesFormDia(row); |
| | | }, |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "åºåç¼å·", |
| | | prop: "code", |
| | | minWidth: 150, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "计éå¨å
·åç§°", |
| | | prop: "name", |
| | | width: "160px", |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "æ£å®åä½", |
| | | prop: "unit", |
| | | width: 200, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "è¯ä¹¦ç¼å·", |
| | | prop: "model", |
| | | width: 200, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "ææ°é´å®æ¥æ", |
| | | prop: "mostDate", |
| | | width: 130, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "å½å
¥äºº", |
| | | prop: "userName", |
| | | width: 130, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "å½å
¥æ¥æ", |
| | | prop: "recordDate", |
| | | align: "center", |
| | | minWidth: 130, |
| | | }, |
| | | { |
| | | label: "æææ¥æ", |
| | | prop: "valid", |
| | | width: 130, |
| | | align: "center", |
| | | }, |
| | | { |
| | | label: "ç¶æ", |
| | | prop: "status", |
| | | width: 130, |
| | | align: "center", |
| | | formatData: params => { |
| | | if (params === 1) { |
| | | return "ææ"; |
| | | } else if (params === 2) { |
| | | return "龿"; |
| | | } else { |
| | | return null; |
| | | } |
| | | }, |
| | | { |
| | | name: "æ¥ç", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | openCalibrationDia("verifying", row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const rowClickData = ref([]) |
| | | const filesDia = ref() |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const selectedRows = ref([]); |
| | | }, |
| | | { |
| | | dataType: "action", |
| | | label: "æä½", |
| | | align: "center", |
| | | width: "130", |
| | | fixed: "right", |
| | | operation: [ |
| | | { |
| | | name: "éä»¶", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openFilesFormDia(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: row => { |
| | | openCalibrationDia("verifying", row); |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]); |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const rowClickData = ref([]); |
| | | const filesDia = ref(); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | }); |
| | | const selectedRows = ref([]); |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFilesFormDia = (row) => { |
| | | filesDia.value?.openDialog(row,'measuring_instrument_ledger') |
| | | }; |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFilesFormDia = row => { |
| | | filesDia.value?.openDialog(row, "measuring_instrument_ledger"); |
| | | }; |
| | | |
| | | const dbRowClick = (row)=>{ |
| | | rowClickData.value?.openDialog(row) |
| | | } |
| | | const dbRowClick = row => { |
| | | rowClickData.value?.openDialog(row); |
| | | }; |
| | | |
| | | // è¡æ ·å¼ï¼å¿«å°æï¼7天å
ï¼æé¾ææ 红 |
| | | const rowClassName = ({ row }) => { |
| | | console.log('rowClassName called:', row); |
| | | // valid æ¯ææå¤©æ°ï¼mostDate æ¯ææ°æ£å®æ¥æ |
| | | if (row.valid && row.mostDate) { |
| | | const mostDate = new Date(row.mostDate); |
| | | // 计ç®å°ææ¥æ = æ£å®æ¥æ + ææå¤©æ° |
| | | const validDays = parseInt(row.valid) || 0; |
| | | const expireDate = new Date(mostDate); |
| | | expireDate.setDate(expireDate.getDate() + validDays); |
| | | |
| | | const now = new Date(); |
| | | const diffDays = Math.ceil((expireDate - now) / (1000 * 60 * 60 * 24)); |
| | | console.log('row:', row.code, 'validDays:', validDays, 'expireDate:', expireDate, 'diffDays:', diffDays); |
| | | // 7天å
å°ææå·²é¾æé½æ 红 |
| | | if (diffDays <= 7) { |
| | | console.log('return warning-row'); |
| | | return 'warning-row'; |
| | | // è¡æ ·å¼ï¼å¿«å°æï¼7天å
ï¼æé¾ææ 红 |
| | | const rowClassName = ({ row }) => { |
| | | console.log("rowClassName called:", row); |
| | | // valid æ¯ææå¤©æ°ï¼mostDate æ¯ææ°æ£å®æ¥æ |
| | | if (row.valid && row.mostDate) { |
| | | const mostDate = new Date(row.mostDate); |
| | | // 计ç®å°ææ¥æ = æ£å®æ¥æ + ææå¤©æ° |
| | | const validDays = parseInt(row.valid) || 0; |
| | | const expireDate = new Date(mostDate); |
| | | expireDate.setDate(expireDate.getDate() + validDays); |
| | | |
| | | const now = new Date(); |
| | | const diffDays = Math.ceil((expireDate - now) / (1000 * 60 * 60 * 24)); |
| | | console.log( |
| | | "row:", |
| | | row.code, |
| | | "validDays:", |
| | | validDays, |
| | | "expireDate:", |
| | | expireDate, |
| | | "diffDays:", |
| | | diffDays |
| | | ); |
| | | // 7天å
å°ææå·²é¾æé½æ 红 |
| | | if (diffDays <= 7) { |
| | | console.log("return warning-row"); |
| | | return "warning-row"; |
| | | } |
| | | } else { |
| | | console.log("row missing valid or mostDate:", row.valid, row.mostDate); |
| | | } |
| | | } else { |
| | | console.log('row missing valid or mostDate:', row.valid, row.mostDate); |
| | | } |
| | | return ''; |
| | | } |
| | | return ""; |
| | | }; |
| | | |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | const formDia = ref() |
| | | const calibrationDia = ref() |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | const formDia = ref(); |
| | | const calibrationDia = ref(); |
| | | |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | // éç½®æç´¢æ¡ä»¶ |
| | | const handleReset = () => { |
| | | searchForm.value.recordDate = ""; |
| | | searchForm.value.code = ""; |
| | | searchForm.value.status = ""; |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = (obj) => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | measuringInstrumentListPage({ ...searchForm.value, ...page }).then((res) => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }).catch((err) => { |
| | | tableLoading.value = false; |
| | | }) |
| | | }; |
| | | // éç½®æç´¢æ¡ä»¶ |
| | | const handleReset = () => { |
| | | searchForm.value.recordDate = ""; |
| | | searchForm.value.code = ""; |
| | | searchForm.value.status = ""; |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | const pagination = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | measuringInstrumentListPage({ ...searchForm.value, ...page }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | page.total = res.data.total; |
| | | }) |
| | | .catch(err => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | nextTick(() => { |
| | | formDia.value?.openDialog(type, row) |
| | | }) |
| | | }; |
| | | // æå¼æ£å®æ ¡åå¼¹æ¡ |
| | | const openCalibrationDia = (type, row) => { |
| | | nextTick(() => { |
| | | calibrationDia.value?.openDialog(type, row) |
| | | }) |
| | | } |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = (type, row) => { |
| | | nextTick(() => { |
| | | formDia.value?.openDialog(type, row); |
| | | }); |
| | | }; |
| | | // æå¼æ£å®æ ¡åå¼¹æ¡ |
| | | const openCalibrationDia = (type, row) => { |
| | | nextTick(() => { |
| | | calibrationDia.value?.openDialog(type, row); |
| | | }); |
| | | }; |
| | | |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map((item) => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | measuringInstrumentDelete(ids) |
| | | .then((res) => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/measuringInstrumentLedger/export", {}, "计éå¨å
·å°è´¦.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤æç¤º", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | measuringInstrumentDelete(ids) |
| | | .then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .finally(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download( |
| | | "/measuringInstrumentLedger/export", |
| | | {}, |
| | | "计éå¨å
·å°è´¦.xlsx" |
| | | ); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | :deep(.el-table .warning-row) { |
| | | background-color: #fef0f0 !important; |
| | | } |
| | | :deep(.el-table .warning-row:hover > td) { |
| | | background-color: #f9d5d5 !important; |
| | | } |
| | | :deep(.el-table .el-table__body tr.warning-row td) { |
| | | background-color: #fef0f0 !important; |
| | | } |
| | | :deep(.el-table .warning-row) { |
| | | background-color: #fef0f0 !important; |
| | | } |
| | | :deep(.el-table .warning-row:hover > td) { |
| | | background-color: #f9d5d5 !important; |
| | | } |
| | | :deep(.el-table .el-table__body tr.warning-row td) { |
| | | background-color: #fef0f0 !important; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <FormDialog |
| | | v-model="visible" |
| | | :title="id ? 'ç¼è¾è®¾å¤æ¥ä¿®' : 'æ°å¢è®¾å¤æ¥ä¿®'" |
| | | width="800px" |
| | | @confirm="sendForm" |
| | | @cancel="handleCancel" |
| | | @close="handleClose" |
| | | > |
| | | <el-form :model="form" label-width="100px"> |
| | | <FormDialog v-model="visible" |
| | | :title="computedTitle" |
| | | :operation-type="operationType" |
| | | width="800px" |
| | | @confirm="sendForm" |
| | | @cancel="handleCancel" |
| | | @close="handleClose"> |
| | | <el-form :model="form" |
| | | label-width="100px"> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="设å¤åç§°"> |
| | | <el-select v-model="form.deviceLedgerId" @change="setDeviceModel" filterable> |
| | | <el-option |
| | | v-for="(item, index) in deviceOptions" |
| | | :key="index" |
| | | :label="item.deviceName" |
| | | :value="item.id" |
| | | ></el-option> |
| | | <el-select v-model="form.deviceLedgerId" |
| | | @change="setDeviceModel" |
| | | filterable |
| | | :disabled="operationType === 'view'"> |
| | | <el-option v-for="(item, index) in deviceOptions" |
| | | :key="index" |
| | | :label="item.deviceName" |
| | | :value="item.id"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="è§æ ¼åå·"> |
| | | <el-input |
| | | v-model="form.deviceModel" |
| | | placeholder="请è¾å
¥è§æ ¼åå·" |
| | | disabled |
| | | /> |
| | | <el-input v-model="form.deviceModel" |
| | | placeholder="请è¾å
¥è§æ ¼åå·" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¥ä¿®æ¥æ"> |
| | | <el-date-picker |
| | | v-model="form.repairTime" |
| | | placeholder="è¯·éæ©æ¥ä¿®æ¥æ" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | type="date" |
| | | clearable |
| | | style="width: 100%" |
| | | /> |
| | | <el-date-picker v-model="form.repairTime" |
| | | placeholder="è¯·éæ©æ¥ä¿®æ¥æ" |
| | | format="YYYY-MM-DD" |
| | | value-format="YYYY-MM-DD" |
| | | type="date" |
| | | clearable |
| | | style="width: 100%" |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¥ä¿®äºº"> |
| | | <el-input v-model="form.repairName" placeholder="请è¾å
¥æ¥ä¿®äºº" /> |
| | | <el-input v-model="form.repairName" |
| | | placeholder="请è¾å
¥æ¥ä¿®äºº" |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¥ä¿®æ¥ä¿®é¡¹ç®"> |
| | | <el-input v-model="form.machineryCategory" placeholder="请è¾å
¥æ¥ä¿®æ¥ä¿®é¡¹ç®" /> |
| | | <el-input v-model="form.machineryCategory" |
| | | placeholder="请è¾å
¥æ¥ä¿®æ¥ä¿®é¡¹ç®" |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="维修人"> |
| | | <el-input v-model="form.maintenanceName" placeholder="请è¾å
¥ç»´ä¿®äººå§å" /> |
| | | <el-input v-model="form.maintenanceName" |
| | | placeholder="请è¾å
¥ç»´ä¿®äººå§å" |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row v-if="id"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¥ä¿®ç¶æ"> |
| | | <el-select v-model="form.status" disabled> |
| | | <el-option label="å¾
ç»´ä¿®" :value="0"></el-option> |
| | | <el-option label="å·²éªæ¶" :value="1"></el-option> |
| | | <el-option label="失败" :value="2"></el-option> |
| | | <el-select v-model="form.status" |
| | | disabled> |
| | | <el-option label="å¾
ç»´ä¿®" |
| | | :value="0"></el-option> |
| | | <el-option label="å·²éªæ¶" |
| | | :value="1"></el-option> |
| | | <el-option label="失败" |
| | | :value="2"></el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <!-- éªæ¶ä¿¡æ¯å±ç¤º --> |
| | | <el-row v-if="id && form.status === 1"> |
| | | <el-row v-if="id && (form.status === 1 || form.status === 3)"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éªæ¶äºº"> |
| | | <el-input v-model="form.acceptanceName" disabled /> |
| | | <el-input v-model="form.acceptanceName" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éªæ¶æ¶é´"> |
| | | <el-input v-model="form.acceptanceTime" disabled /> |
| | | <el-input v-model="form.acceptanceTime" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24"> |
| | | <el-form-item label="éªæ¶å¤æ³¨"> |
| | | <el-input v-model="form.acceptanceRemark" type="textarea" :rows="2" disabled /> |
| | | <el-input v-model="form.acceptanceRemark" |
| | | type="textarea" |
| | | :rows="2" |
| | | disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="æ
éç°è±¡"> |
| | | <el-input |
| | | v-model="form.remark" |
| | | :rows="2" |
| | | type="textarea" |
| | | placeholder="请è¾å
¥æ
éç°è±¡" |
| | | /> |
| | | <el-input v-model="form.remark" |
| | | :rows="2" |
| | | type="textarea" |
| | | placeholder="请è¾å
¥æ
éç°è±¡" |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-row v-if="operationType !== 'view'" |
| | | :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="éä»¶" prop="attachmentIds"> |
| | | <FileUpload v-model:file-list="form.storageBlobDTOs" /> |
| | | <el-form-item label="éä»¶" |
| | | prop="attachmentIds"> |
| | | <FileUpload v-model:file-list="form.storageBlobDTOs" |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | import { |
| | | addRepair, |
| | | editRepair, |
| | | getRepairById, |
| | | } from "@/api/equipmentManagement/repair"; |
| | | import { ElMessage } from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | import { |
| | | addRepair, |
| | | editRepair, |
| | | getRepairById, |
| | | } from "@/api/equipmentManagement/repair"; |
| | | import { ElMessage } from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | |
| | | defineOptions({ |
| | | name: "è®¾å¤æ¥ä¿®å¼¹çª", |
| | | }); |
| | | defineOptions({ |
| | | name: "è®¾å¤æ¥ä¿®å¼¹çª", |
| | | }); |
| | | |
| | | const emits = defineEmits(["ok"]); |
| | | const emits = defineEmits(["ok"]); |
| | | |
| | | const id = ref(); |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | const id = ref(); |
| | | const visible = ref(false); |
| | | const loading = ref(false); |
| | | const operationType = ref(""); // add, edit, view |
| | | |
| | | const userStore = useUserStore(); |
| | | const deviceOptions = ref([]); |
| | | const fileList = ref([]); |
| | | const computedTitle = computed(() => { |
| | | if (operationType.value === "add") return "æ°å¢è®¾å¤æ¥ä¿®"; |
| | | if (operationType.value === "edit") return "ç¼è¾è®¾å¤æ¥ä¿®"; |
| | | if (operationType.value === "view") return "è®¾å¤æ¥ä¿®è¯¦æ
"; |
| | | return ""; |
| | | }); |
| | | |
| | | const loadDeviceName = async () => { |
| | | const { data } = await getDeviceLedger(); |
| | | deviceOptions.value = data; |
| | | }; |
| | | const userStore = useUserStore(); |
| | | const deviceOptions = ref([]); |
| | | const fileList = ref([]); |
| | | |
| | | const { form, resetForm } = useFormData({ |
| | | deviceLedgerId: undefined, // 设å¤Id |
| | | deviceName: undefined, // 设å¤åç§° |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | repairTime: dayjs().format("YYYY-MM-DD"), // æ¥ä¿®æ¥æï¼é»è®¤å½å¤© |
| | | repairName: userStore.nickName, // æ¥ä¿®äºº |
| | | remark: undefined, // æ
éç°è±¡ |
| | | status: 0, // æ¥ä¿®ç¶æ |
| | | machineryCategory: undefined, |
| | | storageBlobDTOs: [], |
| | | maintenanceName: undefined, // 维修人 |
| | | }); |
| | | const loadDeviceName = async () => { |
| | | const { data } = await getDeviceLedger(); |
| | | deviceOptions.value = data; |
| | | }; |
| | | |
| | | const setDeviceModel = (deviceId) => { |
| | | const option = deviceOptions.value.find((item) => item.id === deviceId); |
| | | form.deviceModel = option.deviceModel; |
| | | }; |
| | | const { form, resetForm } = useFormData({ |
| | | deviceLedgerId: undefined, // 设å¤Id |
| | | deviceName: undefined, // 设å¤åç§° |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | repairTime: dayjs().format("YYYY-MM-DD"), // æ¥ä¿®æ¥æï¼é»è®¤å½å¤© |
| | | repairName: userStore.nickName, // æ¥ä¿®äºº |
| | | remark: undefined, // æ
éç°è±¡ |
| | | status: 0, // æ¥ä¿®ç¶æ |
| | | machineryCategory: undefined, |
| | | storageBlobDTOs: [], |
| | | maintenanceName: undefined, // 维修人 |
| | | }); |
| | | |
| | | const setForm = (data) => { |
| | | form.deviceLedgerId = data.deviceLedgerId; |
| | | form.deviceName = data.deviceName; |
| | | form.deviceModel = data.deviceModel; |
| | | form.repairTime = data.repairTime; |
| | | form.repairName = data.repairName; |
| | | form.remark = data.remark; |
| | | form.status = data.status; |
| | | form.machineryCategory = data.machineryCategory; |
| | | form.storageBlobDTOs = data.storageBlobVOs || []; |
| | | form.maintenanceName = data.maintenanceName; |
| | | form.acceptanceName = data.acceptanceName; |
| | | form.acceptanceTime = data.acceptanceTime; |
| | | form.acceptanceRemark = data.acceptanceRemark; |
| | | }; |
| | | const setDeviceModel = deviceId => { |
| | | const option = deviceOptions.value.find(item => item.id === deviceId); |
| | | form.deviceModel = option.deviceModel; |
| | | }; |
| | | |
| | | const sendForm = async () => { |
| | | loading.value = true; |
| | | try { |
| | | const { code } = id.value |
| | | ? await editRepair({ id: unref(id), ...form }) |
| | | : await addRepair(form); |
| | | if (code == 200) { |
| | | ElMessage.success(`${id.value ? "ç¼è¾" : "æ°å¢"}æ¥ä¿®æå`); |
| | | visible.value = false; |
| | | emits("ok"); |
| | | const setForm = data => { |
| | | form.deviceLedgerId = data.deviceLedgerId; |
| | | form.deviceName = data.deviceName; |
| | | form.deviceModel = data.deviceModel; |
| | | form.repairTime = data.repairTime; |
| | | form.repairName = data.repairName; |
| | | form.remark = data.remark; |
| | | form.status = data.status; |
| | | form.machineryCategory = data.machineryCategory; |
| | | form.storageBlobDTOs = data.storageBlobVOs || []; |
| | | form.maintenanceName = data.maintenanceName; |
| | | form.acceptanceName = data.acceptanceName; |
| | | form.acceptanceTime = data.acceptanceTime; |
| | | form.acceptanceRemark = data.acceptanceRemark; |
| | | }; |
| | | |
| | | const sendForm = async () => { |
| | | loading.value = true; |
| | | try { |
| | | const { code } = id.value |
| | | ? await editRepair({ id: unref(id), ...form }) |
| | | : await addRepair(form); |
| | | if (code == 200) { |
| | | ElMessage.success(`${id.value ? "ç¼è¾" : "æ°å¢"}æ¥ä¿®æå`); |
| | | visible.value = false; |
| | | emits("ok"); |
| | | } |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | } finally { |
| | | loading.value = false; |
| | | } |
| | | }; |
| | | }; |
| | | |
| | | const handleCancel = () => { |
| | | resetForm(); |
| | | visible.value = false; |
| | | }; |
| | | const handleCancel = () => { |
| | | resetForm(); |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const handleClose = () => { |
| | | resetForm(); |
| | | visible.value = false; |
| | | }; |
| | | const handleClose = () => { |
| | | resetForm(); |
| | | visible.value = false; |
| | | }; |
| | | |
| | | const openAdd = async () => { |
| | | id.value = undefined; |
| | | visible.value = true; |
| | | fileList.value = []; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | | }; |
| | | const openAdd = async () => { |
| | | id.value = undefined; |
| | | operationType.value = "add"; |
| | | visible.value = true; |
| | | fileList.value = []; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | | }; |
| | | |
| | | const openEdit = async (editId) => { |
| | | const { data } = await getRepairById(editId); |
| | | id.value = editId; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | | setForm(data); |
| | | }; |
| | | const openEdit = async editId => { |
| | | const { data } = await getRepairById(editId); |
| | | id.value = editId; |
| | | operationType.value = "edit"; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | | setForm(data); |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openAdd, |
| | | openEdit, |
| | | }); |
| | | const openView = async viewId => { |
| | | const { data } = await getRepairById(viewId); |
| | | id.value = viewId; |
| | | operationType.value = "view"; |
| | | visible.value = true; |
| | | await nextTick(); |
| | | await loadDeviceName(); |
| | | setForm(data); |
| | | }; |
| | | |
| | | defineExpose({ |
| | | openAdd, |
| | | openEdit, |
| | | openView, |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped></style> |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-form :model="filters" :inline="true"> |
| | | <el-form :model="filters" |
| | | :inline="true"> |
| | | <el-form-item label="设å¤åç§°"> |
| | | <el-input |
| | | v-model="filters.deviceName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥è®¾å¤åç§°" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" |
| | | /> |
| | | <el-input v-model="filters.deviceName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥è®¾å¤åç§°" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" /> |
| | | </el-form-item> |
| | | <el-form-item label="è§æ ¼åå·"> |
| | | <el-input |
| | | v-model="filters.deviceModel" |
| | | style="width: 240px" |
| | | placeholder="è¯·éæ©è§æ ¼åå·" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" |
| | | /> |
| | | <el-input v-model="filters.deviceModel" |
| | | style="width: 240px" |
| | | placeholder="è¯·éæ©è§æ ¼åå·" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ
éç°è±¡"> |
| | | <el-input |
| | | v-model="filters.remark" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥æ
éç°è±¡" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" |
| | | /> |
| | | <el-input v-model="filters.remark" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥æ
éç°è±¡" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" /> |
| | | </el-form-item> |
| | | <el-form-item label="维修人"> |
| | | <el-input |
| | | v-model="filters.maintenanceName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥ç»´ä¿®äºº" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" |
| | | /> |
| | | <el-input v-model="filters.maintenanceName" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥ç»´ä¿®äºº" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | @change="getTableData" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¥ä¿®æ¥æ"> |
| | | <el-date-picker |
| | | v-model="filters.repairTimeStr" |
| | | type="date" |
| | | placeholder="è¯·éæ©æ¥ä¿®æ¥æ" |
| | | size="default" |
| | | @change="(date) => handleDateChange(date,2)" |
| | | /> |
| | | <el-date-picker v-model="filters.repairTimeStr" |
| | | type="date" |
| | | placeholder="è¯·éæ©æ¥ä¿®æ¥æ" |
| | | size="default" |
| | | @change="(date) => handleDateChange(date,2)" /> |
| | | </el-form-item> |
| | | <el-form-item label="ç»´ä¿®æ¥æ"> |
| | | <el-date-picker |
| | | v-model="filters.maintenanceTimeStr" |
| | | type="date" |
| | | placeholder="è¯·éæ©ç»´ä¿®æ¥æ" |
| | | size="default" |
| | | @change="(date) => handleDateChange(date,1)" |
| | | /> |
| | | <el-date-picker v-model="filters.maintenanceTimeStr" |
| | | type="date" |
| | | placeholder="è¯·éæ©ç»´ä¿®æ¥æ" |
| | | size="default" |
| | | @change="(date) => handleDateChange(date,1)" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getTableData">æç´¢</el-button> |
| | | <el-button type="primary" |
| | | @click="getTableData">æç´¢</el-button> |
| | | <el-button @click="resetFilters">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="table_list"> |
| | | <div class="actions"> |
| | | <el-text class="mx-1" size="large">è®¾å¤æ¥ä¿®</el-text> |
| | | <el-text class="mx-1" |
| | | size="large">è®¾å¤æ¥ä¿®</el-text> |
| | | <div> |
| | | <el-button type="success" icon="Van" @click="addRepair"> |
| | | <el-button type="success" |
| | | icon="Van" |
| | | @click="addRepair"> |
| | | æ°å¢æ¥ä¿® |
| | | </el-button> |
| | | <el-button @click="handleOut"> |
| | | å¯¼åº |
| | | </el-button> |
| | | <el-button |
| | | type="danger" |
| | | icon="Delete" |
| | | :disabled="multipleList.length <= 0 || hasFinishedStatus" |
| | | @click="delRepairByIds(multipleList.map((item) => item.id))" |
| | | > |
| | | <el-button type="danger" |
| | | icon="Delete" |
| | | :disabled="multipleList.length <= 0 || hasFinishedStatus" |
| | | @click="delRepairByIds(multipleList.map((item) => item.id))"> |
| | | æ¹éå é¤ |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | isSelection |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :page="{ |
| | | <PIMTable rowKey="id" |
| | | isSelection |
| | | :column="columns" |
| | | :tableData="dataList" |
| | | :page="{ |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize, |
| | | total: pagination.total, |
| | | }" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="changePage" |
| | | > |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="changePage"> |
| | | <template #statusRef="{ row }"> |
| | | <el-tag v-if="row.status === 2" type="danger">失败</el-tag> |
| | | <el-tag v-if="row.status === 1" type="success">å®ç»</el-tag> |
| | | <el-tag v-if="row.status === 3" type="info">å¾
éªæ¶</el-tag> |
| | | <el-tag v-if="row.status === 0" type="warning">å¾
ç»´ä¿®</el-tag> |
| | | <el-tag v-if="row.status === 2" |
| | | type="danger">失败</el-tag> |
| | | <el-tag v-if="row.status === 1" |
| | | type="success">å®ç»</el-tag> |
| | | <el-tag v-if="row.status === 3" |
| | | type="info">å¾
éªæ¶</el-tag> |
| | | <el-tag v-if="row.status === 0" |
| | | type="warning">å¾
ç»´ä¿®</el-tag> |
| | | </template> |
| | | <template #operation="{ row }"> |
| | | <el-button |
| | | type="primary" |
| | | link |
| | | :disabled="row.status === 1 || row.status === 3" |
| | | @click="editRepair(row.id)" |
| | | > |
| | | <el-button type="primary" |
| | | link |
| | | @click="viewRepair(row.id)"> |
| | | 详æ
|
| | | </el-button> |
| | | <el-button type="primary" |
| | | link |
| | | :disabled="row.status === 1 || row.status === 3" |
| | | @click="editRepair(row.id)"> |
| | | ç¼è¾ |
| | | </el-button> |
| | | <el-button |
| | | type="success" |
| | | link |
| | | :disabled="row.status !== 0" |
| | | @click="addMaintain(row)" |
| | | > |
| | | <el-button type="success" |
| | | link |
| | | :disabled="row.status !== 0" |
| | | @click="addMaintain(row)"> |
| | | ç»´ä¿® |
| | | </el-button> |
| | | <el-button |
| | | type="warning" |
| | | link |
| | | :disabled="row.status !== 3" |
| | | @click="openAcceptance(row)" |
| | | > |
| | | <el-button type="warning" |
| | | link |
| | | :disabled="row.status !== 3" |
| | | @click="openAcceptance(row)"> |
| | | éªæ¶ |
| | | </el-button> |
| | | <el-button |
| | | type="danger" |
| | | link |
| | | :disabled="row.status === 1 || row.status === 3" |
| | | @click="delRepairByIds(row.id)" |
| | | > |
| | | <el-button type="danger" |
| | | link |
| | | :disabled="row.status === 1 || row.status === 3" |
| | | @click="delRepairByIds(row.id)"> |
| | | å é¤ |
| | | </el-button> |
| | | <el-button |
| | | type="primary" |
| | | link |
| | | @click="openFileDialog(row)" |
| | | > |
| | | <el-button type="primary" |
| | | link |
| | | @click="openFileDialog(row)"> |
| | | éä»¶ |
| | | </el-button> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | <RepairModal ref="repairModalRef" @ok="getTableData"/> |
| | | <MaintainModal ref="maintainModalRef" @ok="getTableData"/> |
| | | <AcceptanceModal ref="acceptanceModalRef" @ok="getTableData"/> |
| | | <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" :record-type="'device_repair'" :record-id="recordId" /> |
| | | <RepairModal ref="repairModalRef" |
| | | @ok="getTableData" /> |
| | | <MaintainModal ref="maintainModalRef" |
| | | @ok="getTableData" /> |
| | | <AcceptanceModal ref="acceptanceModalRef" |
| | | @ok="getTableData" /> |
| | | <FileList v-if="fileDialogVisible" |
| | | v-model:visible="fileDialogVisible" |
| | | :record-type="'device_repair'" |
| | | :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {onMounted, getCurrentInstance, computed, ref, defineAsyncComponent} from "vue"; |
| | | import {usePaginationApi} from "@/hooks/usePaginationApi"; |
| | | import {getRepairPage, delRepair} from "@/api/equipmentManagement/repair"; |
| | | import RepairModal from "./Modal/RepairModal.vue"; |
| | | import {ElMessageBox, ElMessage} from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import MaintainModal from "./Modal/MaintainModal.vue"; |
| | | import AcceptanceModal from "./Modal/AcceptanceModal.vue"; |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | import { |
| | | onMounted, |
| | | getCurrentInstance, |
| | | computed, |
| | | ref, |
| | | defineAsyncComponent, |
| | | } from "vue"; |
| | | import { usePaginationApi } from "@/hooks/usePaginationApi"; |
| | | import { getRepairPage, delRepair } from "@/api/equipmentManagement/repair"; |
| | | import RepairModal from "./Modal/RepairModal.vue"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import MaintainModal from "./Modal/MaintainModal.vue"; |
| | | import AcceptanceModal from "./Modal/AcceptanceModal.vue"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | ); |
| | | |
| | | defineOptions({ |
| | | name: "è®¾å¤æ¥ä¿®", |
| | | }); |
| | | defineOptions({ |
| | | name: "è®¾å¤æ¥ä¿®", |
| | | }); |
| | | |
| | | const {proxy} = getCurrentInstance(); |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | // æ¨¡ææ¡å®ä¾ |
| | | const repairModalRef = ref(); |
| | | const maintainModalRef = ref(); |
| | | const acceptanceModalRef = ref(); |
| | | // æ¨¡ææ¡å®ä¾ |
| | | const repairModalRef = ref(); |
| | | const maintainModalRef = ref(); |
| | | const acceptanceModalRef = ref(); |
| | | |
| | | // è¡¨æ ¼å¤éæ¡éä¸é¡¹ |
| | | const multipleList = ref([]); |
| | | // è¡¨æ ¼å¤éæ¡éä¸é¡¹ |
| | | const multipleList = ref([]); |
| | | |
| | | // è¡¨æ ¼é©å |
| | | const { |
| | | filters, |
| | | columns, |
| | | dataList, |
| | | pagination, |
| | | getTableData, |
| | | resetFilters, |
| | | onCurrentChange, |
| | | } = usePaginationApi( |
| | | // è¡¨æ ¼é©å |
| | | const { |
| | | filters, |
| | | columns, |
| | | dataList, |
| | | pagination, |
| | | getTableData, |
| | | resetFilters, |
| | | onCurrentChange, |
| | | } = usePaginationApi( |
| | | getRepairPage, |
| | | { |
| | | deviceName: undefined, |
| | |
| | | prop: "deviceModel", |
| | | }, |
| | | { |
| | | label: "æ¥ä¿®é¡¹ç®", |
| | | align: "center", |
| | | prop: "machineryCategory", |
| | | }, |
| | | { |
| | | label: "æ¥ä¿®æ¥æ", |
| | | align: "center", |
| | | prop: "repairTime", |
| | | formatData: (cell) => dayjs(cell).format("YYYY-MM-DD"), |
| | | formatData: cell => dayjs(cell).format("YYYY-MM-DD"), |
| | | }, |
| | | { |
| | | label: "æ¥ä¿®äºº", |
| | | align: "center", |
| | | prop: "repairName", |
| | | }, |
| | | { |
| | | label: "æ
éç°è±¡", |
| | | align: "center", |
| | | prop: "remark", |
| | | }, |
| | | { |
| | | label: "维修人", |
| | | align: "center", |
| | | prop: "maintenanceName", |
| | | }, |
| | | { |
| | | label: "ç»´ä¿®ç»æ", |
| | | align: "center", |
| | | prop: "maintenanceResult", |
| | | }, |
| | | { |
| | | label: "ç»´ä¿®æ¥æ", |
| | | align: "center", |
| | | prop: "maintenanceTime", |
| | | formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""), |
| | | }, |
| | | { |
| | | label: "éªæ¶äºº", |
| | | align: "center", |
| | | prop: "acceptanceName", |
| | | }, |
| | | { |
| | | label: "éªæ¶æ¶é´", |
| | | align: "center", |
| | | prop: "acceptanceTime", |
| | | formatData: (cell) => (cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : ""), |
| | | }, |
| | | { |
| | | label: "ç¶æ", |
| | |
| | | dataType: "slot", |
| | | slot: "operation", |
| | | align: "center", |
| | | width: "300px", |
| | | width: "320px", |
| | | }, |
| | | ] |
| | | ); |
| | | ); |
| | | |
| | | // type === 1 ç»´ä¿® 2æ¥ä¿®é´ |
| | | const handleDateChange = (value, type) => { |
| | | filters.maintenanceTimeStr = null |
| | | filters.c = null |
| | | if (type === 1) { |
| | | if (value) { |
| | | filters.maintenanceTimeStr = dayjs(value).format("YYYY-MM-DD"); |
| | | // type === 1 ç»´ä¿® 2æ¥ä¿®é´ |
| | | const handleDateChange = (value, type) => { |
| | | filters.maintenanceTimeStr = null; |
| | | filters.c = null; |
| | | if (type === 1) { |
| | | if (value) { |
| | | filters.maintenanceTimeStr = dayjs(value).format("YYYY-MM-DD"); |
| | | } |
| | | } else { |
| | | if (value) { |
| | | filters.repairTimeStr = dayjs(value).format("YYYY-MM-DD"); |
| | | } |
| | | } |
| | | } else { |
| | | if (value) { |
| | | filters.repairTimeStr = dayjs(value).format("YYYY-MM-DD"); |
| | | } |
| | | } |
| | | getTableData(); |
| | | }; |
| | | getTableData(); |
| | | }; |
| | | |
| | | // æå¼éä»¶å¼¹çª |
| | | const recordId =ref(0) |
| | | const fileDialogVisible = ref(false) |
| | | // æå¼éä»¶å¼¹çª |
| | | const recordId = ref(0); |
| | | const fileDialogVisible = ref(false); |
| | | |
| | | const openFileDialog = async (row) => { |
| | | recordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileDialogVisible.value = true; |
| | | }; |
| | | |
| | | // å¤éååä»ä¹ |
| | | const handleSelectionChange = (selectionList) => { |
| | | multipleList.value = selectionList; |
| | | }; |
| | | // å¤éååä»ä¹ |
| | | const handleSelectionChange = selectionList => { |
| | | multipleList.value = selectionList; |
| | | }; |
| | | |
| | | // æ£æ¥éä¸çè®°å½ä¸æ¯å¦æå®ç»ç¶æç |
| | | const hasFinishedStatus = computed(() => { |
| | | return multipleList.value.some(item => item.status === 1) |
| | | }) |
| | | |
| | | // æ°å¢æ¥ä¿® |
| | | const addRepair = () => { |
| | | repairModalRef.value.openAdd(); |
| | | }; |
| | | |
| | | // ç¼è¾æ¥ä¿® |
| | | const editRepair = (id) => { |
| | | repairModalRef.value.openEdit(id); |
| | | }; |
| | | |
| | | // æ°å¢ç»´ä¿® |
| | | const addMaintain = (row) => { |
| | | maintainModalRef.value.open(row.id, row); |
| | | }; |
| | | |
| | | // æå¼éªæ¶å¼¹çª |
| | | const openAcceptance = (row) => { |
| | | acceptanceModalRef.value.open(row); |
| | | }; |
| | | |
| | | const changePage = ({page, limit}) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | | onCurrentChange(page); |
| | | }; |
| | | |
| | | // åè¡å é¤ |
| | | const delRepairByIds = async (ids) => { |
| | | // æ£æ¥æ¯å¦æå®ç»ç¶æçè®°å½ |
| | | const idsArray = Array.isArray(ids) ? ids : [ids]; |
| | | const hasFinished = idsArray.some(id => { |
| | | const record = dataList.value.find(item => item.id === id); |
| | | return record && record.status === 1; |
| | | // æ£æ¥éä¸çè®°å½ä¸æ¯å¦æå®ç»ç¶æç |
| | | const hasFinishedStatus = computed(() => { |
| | | return multipleList.value.some(item => item.status === 1); |
| | | }); |
| | | |
| | | if (hasFinished) { |
| | | ElMessage.warning('ä¸è½å é¤ç¶æä¸ºå®ç»çè®°å½'); |
| | | return; |
| | | } |
| | | // æ°å¢æ¥ä¿® |
| | | const addRepair = () => { |
| | | repairModalRef.value.openAdd(); |
| | | }; |
| | | |
| | | ElMessageBox.confirm("确认å 餿¥ä¿®æ°æ®, æ¤æä½ä¸å¯é?", "è¦å", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(async () => { |
| | | const {code} = await delRepair(ids); |
| | | if (code === 200) { |
| | | ElMessage.success("å 餿å"); |
| | | getTableData(); |
| | | // 详æ
æ¥ç |
| | | const viewRepair = id => { |
| | | repairModalRef.value.openView(id); |
| | | }; |
| | | |
| | | // ç¼è¾æ¥ä¿® |
| | | const editRepair = id => { |
| | | repairModalRef.value.openEdit(id); |
| | | }; |
| | | |
| | | // æ°å¢ç»´ä¿® |
| | | const addMaintain = row => { |
| | | maintainModalRef.value.open(row.id, row); |
| | | }; |
| | | |
| | | // æå¼éªæ¶å¼¹çª |
| | | const openAcceptance = row => { |
| | | acceptanceModalRef.value.open(row); |
| | | }; |
| | | |
| | | const changePage = ({ page, limit }) => { |
| | | pagination.currentPage = page; |
| | | pagination.pageSize = limit; |
| | | onCurrentChange(page); |
| | | }; |
| | | |
| | | // åè¡å é¤ |
| | | const delRepairByIds = async ids => { |
| | | // æ£æ¥æ¯å¦æå®ç»ç¶æçè®°å½ |
| | | const idsArray = Array.isArray(ids) ? ids : [ids]; |
| | | const hasFinished = idsArray.some(id => { |
| | | const record = dataList.value.find(item => item.id === id); |
| | | return record && record.status === 1; |
| | | }); |
| | | |
| | | if (hasFinished) { |
| | | ElMessage.warning("ä¸è½å é¤ç¶æä¸ºå®ç»çè®°å½"); |
| | | return; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | ElMessageBox.confirm("确认å 餿¥ä¿®æ°æ®, æ¤æä½ä¸å¯é?", "è¦å", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }).then(async () => { |
| | | const { code } = await delRepair(ids); |
| | | if (code === 200) { |
| | | ElMessage.success("å 餿å"); |
| | | getTableData(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/device/repair/export", {}, "è®¾å¤æ¥ä¿®.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | ElMessage.info("已忶"); |
| | | }); |
| | | }; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getTableData(); |
| | | }); |
| | | onMounted(() => { |
| | | getTableData(); |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | | .table_list { |
| | | margin-top: unset; |
| | | } |
| | | .table_list { |
| | | margin-top: unset; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | } |
| | | .actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | margin-bottom: 10px; |
| | | } |
| | | </style> |
| | |
| | | <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType"> |
| | | <el-form-item label="æ¥æ" prop="frequencyDetail"> |
| | | <el-time-picker v-model="form.frequencyDetail" placeholder="éæ©æ¶é´" format="HH:mm" |
| | | value-format="HH:mm" /> |
| | | value-format="HH:mm" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType"> |
| | |
| | | <el-option label="卿¥" value="SUN"/> |
| | | </el-select> |
| | | <el-time-picker v-model="form.time" placeholder="éæ©æ¶é´" format="HH:mm" |
| | | value-format="HH:mm" style="width: 50%"/> |
| | | value-format="HH:mm" style="width: 50%"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType"> |
| | |
| | | format="MM,DD,HH:mm" |
| | | value-format="MM,DD,HH:mm" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="宿¶ä»»å¡"> |
| | | <el-switch |
| | | v-model="form.isActive" |
| | | :active-value="1" |
| | | :inactive-value="0" |
| | | active-text="å¼å¯" |
| | | inactive-text="å
³é" |
| | | inline-prompt |
| | | /> |
| | | <span style="margin-left: 12px; color: #909399; font-size: 12px;"> |
| | | {{ form.isActive === 1 ? 'ä»»å¡å°æè®¡åæ§è¡' : '任塿忧è¡' }} |
| | | </span> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | time: '', |
| | | deviceModel: undefined, // è§æ ¼åå· |
| | | registrationDate: '', |
| | | maintenancePerson: '' // ä¿å
»äºº |
| | | maintenancePerson: '', // ä¿å
»äºº |
| | | isActive: 0 // 宿¶ä»»å¡å¼å
³ï¼0=å
³éï¼1=å¼å¯ |
| | | }, |
| | | rules: { |
| | | taskId: [{ required: true, message: "è¯·éæ©è®¾å¤", trigger: "change" },], |
| | |
| | | time: '', |
| | | deviceModel: undefined, |
| | | registrationDate: '', |
| | | maintenancePerson: '' |
| | | maintenancePerson: '', |
| | | isActive: 0 |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | delete payload.inspector |
| | | delete payload.inspectorIds |
| | | |
| | | delete payload.active |
| | | |
| | | if (payload.frequencyType === 'WEEKLY') { |
| | | let frequencyDetail = '' |
| | | frequencyDetail = payload.week + ',' + payload.time |
| | | payload.frequencyDetail = frequencyDetail |
| | | } |
| | | |
| | | |
| | | // å½å
¥æ¥æï¼ç´æ¥ä½¿ç¨è¡¨åéç registrationDate åæ®µ |
| | | // ä¸äºé»è®¤ç¶æå段 |
| | | if (payload.status === undefined || payload.status === null || payload.status === '') { |
| | | payload.status = '0' // é»è®¤ç¶æï¼å¯æå®é
æä¸¾è°æ´ |
| | | } |
| | | payload.active = true |
| | | payload.deleted = 0 |
| | | |
| | | |
| | | if (operationType.value === 'edit') { |
| | | await deviceMaintenanceTaskEdit(payload) |
| | | } else { |
| | |
| | | }" |
| | | @selection-change="handleScheduledSelectionChange" |
| | | @pagination="changeScheduledPage"> |
| | | <template #isActiveRef="{ row }"> |
| | | <el-tag v-if="row.isActive === 1" |
| | | type="success">å¼å¯</el-tag> |
| | | <el-tag v-else |
| | | type="info">å
³é</el-tag> |
| | | </template> |
| | | <template #statusRef="{ row }"> |
| | | <el-tag v-if="row.status === 1" |
| | | type="success">å¯ç¨</el-tag> |
| | |
| | | { |
| | | prop: "frequencyType", |
| | | label: "颿¬¡", |
| | | minWidth: 150, |
| | | minWidth: 50, |
| | | // PIMTable 使ç¨çæ¯ formatDataï¼è䏿¯ Element-Plus ç formatter |
| | | formatData: cell => |
| | | ({ |
| | |
| | | { |
| | | prop: "frequencyDetail", |
| | | label: "å¼å§æ¥æä¸æ¶é´", |
| | | minWidth: 150, |
| | | minWidth: 130, |
| | | // åæ ·æ¹ç¨ formatDataï¼PIMTable å
é¨ä¼æåå
æ ¼å¼ä¼ è¿æ¥ |
| | | formatData: cell => { |
| | | if (typeof cell !== "string") return ""; |
| | |
| | | ); |
| | | }, |
| | | }, |
| | | { |
| | | prop: "isActive", |
| | | label: "宿¶ä»»å¡", |
| | | dataType: "slot", |
| | | slot: "isActiveRef", |
| | | align: "center", |
| | | minWidth: 100, |
| | | }, |
| | | { prop: "maintenancePerson", label: "ä¿å
»äºº", minWidth: 100 }, |
| | | { prop: "registrant", label: "ç»è®°äºº", minWidth: 100 }, |
| | | { |
| | |
| | | label: "ç»è®°æ¥æ", |
| | | minWidth: 100, |
| | | formatData: cell => |
| | | cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : "-", |
| | | cell ? dayjs(cell).format("YYYY-MM-DD") : "-", |
| | | }, |
| | | { |
| | | fixed: "right", |
| | |
| | | dataType: "slot", |
| | | slot: "operation", |
| | | align: "center", |
| | | width: "200px", |
| | | width: "150px", |
| | | }, |
| | | ]); |
| | | |
| | |
| | | clearable/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <!-- æé® --> |
| | | <el-col :span="4"> |
| | | <el-col :span="24" :sm="24" :md="12" :lg="12"> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="getList"> |
| | | æç´¢ |
| | | </el-button> |
| | | <div style="display: flex; align-items: center; gap: 4px; width: 100%; flex-wrap: wrap;"> |
| | | <el-button type="primary" @click="getList"> |
| | | æç´¢ |
| | | </el-button> |
| | | |
| | | <el-button @click="resetSearch"> |
| | | éç½® |
| | | </el-button> |
| | | <el-button @click="resetSearch"> |
| | | éç½® |
| | | </el-button> |
| | | <div style="display: flex; gap: 4px; margin-left: auto;"> |
| | | <el-button type="primary" @click="isShowNewModal = true"> |
| | | æ°å¢åºå |
| | | </el-button> |
| | | <el-button |
| | | type="info" |
| | | plain |
| | | icon="Upload" |
| | | @click="isShowImportModal = true" |
| | | > |
| | | 导å
¥åºå |
| | | </el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <div> |
| | | <el-button type="primary" @click="isShowNewModal = true" |
| | | >æ°å¢åºå</el-button |
| | | > |
| | | <el-button |
| | | type="info" |
| | | plain |
| | | icon="Upload" |
| | | @click="isShowImportModal = true" |
| | | > |
| | | 导å
¥åºå |
| | | </el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <el-table |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <FormDialog v-model="visible" title="éè´å°è´¦è¯¦æ
" width="70%" operation-type="detail" @close="handleClose"> |
| | | <el-form :model="form" label-width="140px" label-position="top"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éè´ååå·ï¼"> |
| | | <span class="readonly-text">{{ form.purchaseContractNumber || '--' }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col v-if="showSalesContractBinding" :span="12"> |
| | | <el-form-item label="éå®ååå·ï¼"> |
| | | <span class="readonly-text">{{ form.salesContractNo || '--' }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¾åºååç§°ï¼"> |
| | | <span class="readonly-text">{{ form.supplierName || '--' }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="项ç®åç§°ï¼"> |
| | | <span class="readonly-text">{{ form.projectName || '--' }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="仿¬¾æ¹å¼ï¼"> |
| | | <span class="readonly-text">{{ form.paymentMethod || '--' }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç¾è®¢æ¥æï¼"> |
| | | <span class="readonly-text">{{ form.executionDate || '--' }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å½å
¥äººï¼"> |
| | | <span class="readonly-text">{{ form.recorderName || '--' }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å½å
¥æ¥æï¼"> |
| | | <span class="readonly-text">{{ form.entryDate || '--' }}</span> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <div style="font-weight: bold; margin: 10px 0; color: #f56c6c"> |
| | | * 产åä¿¡æ¯ï¼ |
| | | </div> |
| | | <el-table :data="productData" border> |
| | | <el-table-column type="index" label="åºå·" width="60" align="center" /> |
| | | <el-table-column label="产å大类" prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" prop="specificationModel" /> |
| | | <el-table-column label="åä½" prop="unit" /> |
| | | <el-table-column label="æ°é" prop="quantity" /> |
| | | <el-table-column label="åºåé¢çæ°é" prop="stockReservedQuantity" /> |
| | | <el-table-column label="ç¨ç(%)" prop="taxRate" /> |
| | | <el-table-column label="å«ç¨åä»·(å
)" prop="taxInclusiveUnitPrice" :formatter="unitPriceFormattedNumber" width="150" /> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" width="150" /> |
| | | <el-table-column label="ä¸å«ç¨æ»ä»·(å
)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" width="150" /> |
| | | <template #append> |
| | | <div class="summary-row" v-if="productData.length > 0"> |
| | | <div class="summary-label">å计</div> |
| | | <div class="summary-value" style="width: 150px"> |
| | | {{ unitPriceFormattedNumber(null, null, sumTaxInclusiveUnitPrice) }} |
| | | </div> |
| | | <div class="summary-value" style="width: 150px"> |
| | | {{ formattedNumber(null, null, sumTaxInclusiveTotalPrice) }} |
| | | </div> |
| | | <div class="summary-value" style="width: 150px"> |
| | | {{ formattedNumber(null, null, sumTaxExclusiveTotalPrice) }} |
| | | </div> |
| | | </div> |
| | | </template> |
| | | </el-table> |
| | | |
| | | <el-row :gutter="30" style="margin-top: 20px;"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨ï¼"> |
| | | <div class="readonly-text-area">{{ form.remarks || '--' }}</div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="éä»¶ææï¼"> |
| | | <div class="table-container" style="width: 100%;"> |
| | | <el-table :data="fileList" border class="attachment-table" style="width: 100%;" |
| | | :height="fileList.length > 0 ? 'auto' : '120px'"> |
| | | <el-table-column label="éä»¶åç§°" prop="originalFilename" show-overflow-tooltip min-width="200"> |
| | | <template #default="scope"> |
| | | {{ scope.row.name || scope.row.originalFilename || ('éä»¶' + (scope.$index + 1)) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" label="æä½" :width="150" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" class="download-link" |
| | | @click="previewFile(scope.row.previewURL || scope.row.url)"> |
| | | é¢è§ |
| | | </el-button> |
| | | <el-button link type="primary" size="small" class="download-link" |
| | | @click="downloadFile(scope.row.downloadURL || scope.row.url)"> |
| | | ä¸è½½ |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | <filePreview ref="filePreviewRef" /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed } from 'vue' |
| | | import { ElMessage } from 'element-plus' |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue" |
| | | import filePreview from '@/components/filePreview/index.vue' |
| | | import { getPurchaseById } from "@/api/procurementManagement/procurementLedger" |
| | | |
| | | const visible = ref(false) |
| | | // æ¯å¦æ¾ç¤ºéå®ååå·ç»å® |
| | | const showSalesContractBinding = false |
| | | const form = ref({}) |
| | | const productData = ref([]) |
| | | const fileList = ref([]) |
| | | const filePreviewRef = ref() |
| | | |
| | | const open = (id) => { |
| | | visible.value = true |
| | | getPurchaseById({ id: id, type: 2 }).then(res => { |
| | | form.value = res.data ? res.data : res || {} |
| | | productData.value = form.value.purchaseLedgerProductList || form.value.productData || [] |
| | | fileList.value = form.value.storageBlobVOS || [] |
| | | }) |
| | | } |
| | | |
| | | // æ´é² open æ¹æ³ç»ç¶ç»ä»¶è°ç¨ |
| | | defineExpose({ |
| | | open |
| | | }) |
| | | |
| | | const handleClose = () => { |
| | | visible.value = false |
| | | form.value = {} |
| | | productData.value = [] |
| | | fileList.value = [] |
| | | } |
| | | |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | if (cellValue != null && !isNaN(cellValue)) { |
| | | return Number(cellValue).toFixed(2) |
| | | } |
| | | return cellValue |
| | | } |
| | | |
| | | |
| | | const unitPriceFormattedNumber = (row, column, cellValue) => { |
| | | if (cellValue != null && !isNaN(cellValue)) { |
| | | return Number(cellValue).toFixed(6) |
| | | } |
| | | return cellValue |
| | | } |
| | | |
| | | const sumTaxInclusiveUnitPrice = computed(() => { |
| | | return productData.value.reduce((sum, item) => { |
| | | return sum + (Number(item.taxInclusiveUnitPrice) || 0) |
| | | }, 0) |
| | | }) |
| | | |
| | | const sumTaxInclusiveTotalPrice = computed(() => { |
| | | return productData.value.reduce((sum, item) => { |
| | | return sum + (Number(item.taxInclusiveTotalPrice) || 0) |
| | | }, 0) |
| | | }) |
| | | |
| | | const sumTaxExclusiveTotalPrice = computed(() => { |
| | | return productData.value.reduce((sum, item) => { |
| | | return sum + (Number(item.taxExclusiveTotalPrice) || 0) |
| | | }, 0) |
| | | }) |
| | | |
| | | const previewFile = (url) => { |
| | | if (url) { |
| | | filePreviewRef.value.open(url) |
| | | } else { |
| | | ElMessage.warning('æä»¶å°åæ æï¼æ æ³é¢è§') |
| | | } |
| | | } |
| | | |
| | | const downloadFile = (url) => { |
| | | window.open(url, "_blank") |
| | | } |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .readonly-text { |
| | | width: 100%; |
| | | padding: 0 12px; |
| | | background-color: #f5f7fa; |
| | | color: #606266; |
| | | border-radius: 4px; |
| | | border: 1px solid #e4e7ed; |
| | | box-sizing: border-box; |
| | | min-height: 32px; |
| | | line-height: 32px; |
| | | display: inline-block; |
| | | } |
| | | |
| | | .readonly-text-area { |
| | | width: 100%; |
| | | padding: 8px 12px; |
| | | background-color: #f5f7fa; |
| | | color: #606266; |
| | | border-radius: 4px; |
| | | border: 1px solid #e4e7ed; |
| | | box-sizing: border-box; |
| | | min-height: 64px; |
| | | line-height: 1.5; |
| | | white-space: pre-wrap; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .summary-row { |
| | | display: flex; |
| | | background-color: #f5f7fa; |
| | | font-weight: bold; |
| | | border-top: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .summary-label { |
| | | flex: 1; |
| | | text-align: right; |
| | | padding: 12px; |
| | | color: #606266; |
| | | } |
| | | |
| | | .summary-value { |
| | | padding: 12px; |
| | | color: #606266; |
| | | border-left: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .table-container { |
| | | overflow-y: auto; |
| | | box-sizing: border-box; |
| | | } |
| | | </style> |
| | |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <el-form :model="searchForm" |
| | | :inline="true"> |
| | | <el-form :model="searchForm" :inline="true"> |
| | | <el-form-item label="ä¾åºååç§°ï¼"> |
| | | <el-input v-model="searchForm.supplierName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | <el-input v-model="searchForm.supplierName" placeholder="请è¾å
¥" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="éè´ååå·ï¼"> |
| | | <el-input v-model="searchForm.purchaseContractNumber" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" /> |
| | | <el-input v-model="searchForm.purchaseContractNumber" style="width: 240px" placeholder="请è¾å
¥" |
| | | @change="handleQuery" clearable :prefix-icon="Search" /> |
| | | </el-form-item> |
| | | <el-form-item label="éå®ååå·ï¼"> |
| | | <el-input v-model="searchForm.salesContractNo" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | <el-form-item v-if="showSalesContractBinding" label="éå®ååå·ï¼"> |
| | | <el-input v-model="searchForm.salesContractNo" placeholder="请è¾å
¥" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="项ç®åç§°ï¼"> |
| | | <el-input v-model="searchForm.projectName" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | <el-input v-model="searchForm.projectName" placeholder="请è¾å
¥" clearable prefix-icon="Search" |
| | | @change="handleQuery" /> |
| | | </el-form-item> |
| | | <el-form-item label="å½å
¥æ¥æï¼"> |
| | | <el-date-picker v-model="searchForm.entryDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="daterange" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | @change="changeDaterange" /> |
| | | <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" |
| | | type="daterange" placeholder="è¯·éæ©" clearable @change="changeDaterange" /> |
| | | </el-form-item> |
| | | <el-form-item label="å
¥åºç¶æï¼"> |
| | | <el-select v-model="searchForm.stockInStatus" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | style="width: 240px" |
| | | @change="handleQuery"> |
| | | <el-option label="å¾
å
¥åº" |
| | | value="å¾
å
¥åº" /> |
| | | <el-option label="å
¥åºä¸" |
| | | value="å
¥åºä¸" /> |
| | | <el-option label="å®å
¨å
¥åº" |
| | | value="å®å
¨å
¥åº" /> |
| | | <el-select v-model="searchForm.stockInStatus" placeholder="è¯·éæ©" clearable style="width: 240px" |
| | | @change="handleQuery"> |
| | | <el-option label="å¾
å
¥åº" value="å¾
å
¥åº" /> |
| | | <el-option label="å
¥åºä¸" value="å
¥åºä¸" /> |
| | | <el-option label="å®å
¨å
¥åº" value="å®å
¨å
¥åº" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery"> æç´¢ |
| | | <el-button type="primary" @click="handleQuery"> æç´¢ |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | |
| | | </div> |
| | | <div class="table_list"> |
| | | <div style="display: flex;justify-content: flex-end;margin-bottom: 20px;"> |
| | | <el-button type="primary" |
| | | @click="openForm('add')">æ°å¢å°è´¦</el-button> |
| | | <el-button type="primary" |
| | | plain |
| | | @click="handleImport">导å
¥</el-button> |
| | | <el-button type="primary" @click="openForm('add')">æ°å¢å°è´¦</el-button> |
| | | <el-button type="primary" plain @click="handleImport">导å
¥</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤ |
| | | <el-button type="danger" plain @click="handleDelete">å é¤ |
| | | </el-button> |
| | | </div> |
| | | <el-table :data="tableData" |
| | | border |
| | | v-loading="tableLoading" |
| | | @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" |
| | | :row-key="(row) => row.id" |
| | | show-summary |
| | | :summary-method="summarizeMainTable" |
| | | @expand-change="expandChange" |
| | | height="calc(100vh - 21.5em)"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | width="55" /> |
| | | <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" :row-key="(row) => row.id" show-summary :summary-method="summarizeMainTable" |
| | | @expand-change="expandChange" height="calc(100vh - 21.5em)"> |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column type="expand"> |
| | | <template #default="props"> |
| | | <el-table :data="props.row.children" |
| | | border |
| | | show-summary |
| | | :summary-method="summarizeChildrenTable"> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="产å大类" |
| | | prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="specificationModel" /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" /> |
| | | <el-table-column label="å
¥åºå®¡æ ¸ç¶æ" |
| | | prop="stockInApprovalStatus" |
| | | width="120"> |
| | | <el-table :data="props.row.children" border show-summary :summary-method="summarizeChildrenTable"> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="产å大类" prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" prop="specificationModel" /> |
| | | <el-table-column label="åä½" prop="unit" /> |
| | | <el-table-column label="å
¥åºå®¡æ ¸ç¶æ" prop="stockInApprovalStatus" width="120"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getStockInApprovalStatusType(scope.row.stockInApprovalStatus)" |
| | | size="small"> |
| | | <el-tag :type="getStockInApprovalStatusType(scope.row.stockInApprovalStatus)" size="small"> |
| | | {{ scope.row.stockInApprovalStatus || '--' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æ°é" |
| | | prop="quantity" /> |
| | | <el-table-column label="å¯ç¨æ°é" |
| | | prop="availableQuality" /> |
| | | <el-table-column label="éè´§æ°é" |
| | | prop="returnQuality" /> |
| | | <el-table-column label="ç¨ç(%)" |
| | | prop="taxRate" /> |
| | | <el-table-column label="å«ç¨åä»·(å
)" |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" |
| | | prop="taxInclusiveTotalPrice" |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="ä¸å«ç¨æ»ä»·(å
)" |
| | | prop="taxExclusiveTotalPrice" |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="æ°é" prop="quantity" /> |
| | | <el-table-column label="å¯ç¨æ°é" prop="availableQuality" /> |
| | | <el-table-column label="éè´§æ°é" prop="returnQuality" /> |
| | | <el-table-column label="ç¨ç(%)" prop="taxRate" /> |
| | | <el-table-column label="å«ç¨åä»·(å
)" prop="taxInclusiveUnitPrice" :formatter="unitPriceFormatter" /> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" /> |
| | | <el-table-column label="ä¸å«ç¨æ»ä»·(å
)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" /> |
| | | </el-table> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="éè´ååå·" |
| | | prop="purchaseContractNumber" |
| | | width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="éå®ååå·" |
| | | prop="salesContractNo" |
| | | width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ä¾åºååç§°" |
| | | prop="supplierName" |
| | | width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="项ç®åç§°" |
| | | prop="projectName" |
| | | width="320" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="审æ¹ç¶æ" |
| | | prop="approvalStatus" |
| | | width="100" |
| | | show-overflow-tooltip> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="éè´ååå·" prop="purchaseContractNumber" width="160" show-overflow-tooltip /> |
| | | <el-table-column v-if="showSalesContractBinding" label="éå®ååå·" prop="salesContractNo" width="160" show-overflow-tooltip /> |
| | | <el-table-column label="ä¾åºååç§°" prop="supplierName" width="160" show-overflow-tooltip /> |
| | | <el-table-column label="项ç®åç§°" prop="projectName" width="320" show-overflow-tooltip /> |
| | | <el-table-column label="审æ¹ç¶æ" prop="approvalStatus" width="100" show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag :type="getApprovalStatusType(scope.row.approvalStatus)" |
| | | size="small"> |
| | | <el-tag :type="getApprovalStatusType(scope.row.approvalStatus)" size="small"> |
| | | {{ approvalStatusText[scope.row.approvalStatus] || 'æªç¥ç¶æ' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å
¥åºç¶æ" |
| | | prop="stockInStatus" |
| | | width="100" |
| | | show-overflow-tooltip> |
| | | <el-table-column label="å
¥åºç¶æ" prop="stockInStatus" width="100" show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | <el-tag :type="getStockInStatusType(scope.row.stockInStatus)" |
| | | size="small"> |
| | | <el-tag :type="getStockInStatusType(scope.row.stockInStatus)" size="small"> |
| | | {{ scope.row.stockInStatus || '--' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="ç¾è®¢æ¥æ" |
| | | prop="executionDate" |
| | | width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="仿¬¾æ¹å¼" |
| | | width="100" |
| | | prop="paymentMethod" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ååéé¢(å
)" |
| | | prop="contractAmount" |
| | | width="200" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="å½å
¥äºº" |
| | | prop="recorderName" |
| | | width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="å½å
¥æ¥æ" |
| | | prop="entryDate" |
| | | width="100" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="夿³¨" |
| | | prop="remarks" |
| | | width="200" |
| | | show-overflow-tooltip /> |
| | | <el-table-column fixed="right" |
| | | label="æä½" |
| | | width="120" |
| | | align="center"> |
| | | <el-table-column label="ç¾è®¢æ¥æ" prop="executionDate" width="100" show-overflow-tooltip /> |
| | | <el-table-column label="仿¬¾æ¹å¼" width="100" prop="paymentMethod" show-overflow-tooltip /> |
| | | <el-table-column label="ååéé¢(å
)" prop="contractAmount" width="200" show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="å½å
¥äºº" prop="recorderName" width="120" show-overflow-tooltip /> |
| | | <el-table-column label="å½å
¥æ¥æ" prop="entryDate" width="100" show-overflow-tooltip /> |
| | | <el-table-column label="夿³¨" prop="remarks" width="200" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="æä½" width="180" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openForm('edit', scope.row)" |
| | | :disabled="scope.row.stockInStatus === 'å®å
¨å
¥åº'">ç¼è¾ |
| | | <el-button link type="primary" @click="openForm('detail', scope.row)">详æ
|
| | | </el-button> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openFileDialog(scope.row)">éä»¶</el-button> |
| | | <el-button link type="primary" @click="openForm('edit', scope.row)" |
| | | :disabled="scope.row.stockInStatus === 'å®å
¨å
¥åº'">ç¼è¾ |
| | | </el-button> |
| | | <el-button link type="primary" @click="openFileDialog(scope.row)">éä»¶</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <pagination v-show="total > 0" |
| | | :total="total" |
| | | layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" |
| | | :limit="page.size" |
| | | @pagination="paginationChange" /> |
| | | <pagination v-show="total > 0" :total="total" layout="total, sizes, prev, pager, next, jumper" |
| | | :page="page.current" :limit="page.size" @pagination="paginationChange" /> |
| | | </div> |
| | | <FormDialog v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢éè´å°è´¦é¡µé¢' : 'ç¼è¾éè´å°è´¦é¡µé¢'" |
| | | :width="'70%'" |
| | | :operation-type="operationType" |
| | | @close="closeDia" |
| | | @confirm="submitForm" |
| | | @cancel="closeDia"> |
| | | <el-form :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef"> |
| | | :title="operationType === 'add' ? 'æ°å¢éè´å°è´¦é¡µé¢' : operationType === 'edit' ? 'ç¼è¾éè´å°è´¦é¡µé¢' : 'éè´å°è´¦è¯¦æ
'" :width="'70%'" |
| | | :operation-type="operationType" @close="closeDia" @confirm="submitForm" @cancel="closeDia"> |
| | | <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éè´ååå·ï¼" |
| | | prop="purchaseContractNumber"> |
| | | <el-input v-model="form.purchaseContractNumber" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | <el-form-item label="éè´ååå·ï¼" prop="purchaseContractNumber"> |
| | | <el-input v-model="form.purchaseContractNumber" placeholder="请è¾å
¥" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éå®ååå·ï¼" |
| | | prop="salesLedgerId"> |
| | | <el-select v-model="form.salesLedgerId" |
| | | placeholder="è¯·éæ©" |
| | | filterable |
| | | clearable |
| | | @change="salesLedgerChange"> |
| | | <el-option v-for="item in salesContractList" |
| | | :key="item.id" |
| | | :label="item.salesContractNo" |
| | | :value="item.id" /> |
| | | <el-col v-if="showSalesContractBinding" :span="12"> |
| | | <el-form-item label="éå®ååå·ï¼" prop="salesLedgerId"> |
| | | <el-select v-model="form.salesLedgerId" placeholder="è¯·éæ©" filterable clearable @change="salesLedgerChange"> |
| | | <el-option v-for="item in salesContractList" :key="item.id" :label="item.salesContractNo" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¾åºååç§°ï¼" |
| | | prop="supplierId"> |
| | | <el-select v-model="form.supplierId" |
| | | placeholder="è¯·éæ©" |
| | | filterable |
| | | clearable> |
| | | <el-option v-for="item in supplierList" |
| | | :key="item.id" |
| | | :label="item.supplierName" |
| | | :value="item.id">{{ item.supplierName + '---' + item.supplierType }} |
| | | </el-option> |
| | | <el-form-item label="ä¾åºååç§°ï¼" prop="supplierId"> |
| | | <el-select v-model="form.supplierId" placeholder="è¯·éæ©" filterable clearable> |
| | | <el-option v-for="item in supplierList" :key="item.id" :label="item.supplierName" :value="item.id">{{ item.supplierName + '---' + item.supplierType }}</el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="项ç®åç§°" |
| | | prop="projectName"> |
| | | <el-input v-model="form.projectName" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | <el-form-item label="项ç®åç§°" prop="projectName"> |
| | | <el-input v-model="form.projectName" placeholder="请è¾å
¥" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="仿¬¾æ¹å¼"> |
| | | <el-input v-model="form.paymentMethod" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | <el-input v-model="form.paymentMethod" placeholder="请è¾å
¥" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç¾è®¢æ¥æï¼" |
| | | prop="executionDate"> |
| | | <el-date-picker style="width: 100%" |
| | | v-model="form.executionDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable /> |
| | | <el-form-item label="ç¾è®¢æ¥æï¼" prop="executionDate"> |
| | | <el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="è¯·éæ©" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å½å
¥äººï¼" |
| | | prop="recorderId"> |
| | | <el-select v-model="form.recorderId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable> |
| | | <el-option v-for="item in userList" |
| | | :key="item.userId" |
| | | :label="item.nickName" |
| | | :value="item.userId" /> |
| | | <el-form-item label="å½å
¥äººï¼" prop="recorderId"> |
| | | <el-select v-model="form.recorderId" placeholder="è¯·éæ©" clearable filterable> |
| | | <el-option v-for="item in userList" :key="item.userId" :label="item.nickName" :value="item.userId" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å½å
¥æ¥æï¼" |
| | | prop="entryDate"> |
| | | <el-date-picker style="width: 100%" |
| | | v-model="form.entryDate" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable /> |
| | | <el-form-item label="å½å
¥æ¥æï¼" prop="entryDate"> |
| | | <el-date-picker style="width: 100%" v-model="form.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="date" placeholder="è¯·éæ©" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-form-item label="产åä¿¡æ¯ï¼" |
| | | prop="entryDate"> |
| | | <el-button type="primary" |
| | | @click="openProductForm('add')">æ·»å |
| | | </el-button> |
| | | <el-button plain |
| | | type="danger" |
| | | @click="deleteProduct">å é¤ |
| | | </el-button> |
| | | <el-form-item label="产åä¿¡æ¯ï¼" prop="entryDate"> |
| | | <el-button type="primary" @click="openProductForm('add')">æ·»å </el-button> |
| | | <el-button plain type="danger" @click="deleteProduct">å é¤</el-button> |
| | | </el-form-item> |
| | | <div class="select-button-group" |
| | | style="width: 500px; margin: 20px 0;" |
| | | v-if="operationType === 'add'"> |
| | | <el-select filterable |
| | | allow-create |
| | | :reserve-keyword="true" |
| | | :default-first-option="false" |
| | | clearable |
| | | v-model="templateName" |
| | | :input-value="filterInputValue" |
| | | @filter-change="onTemplateFilterChange" |
| | | @change="onTemplateChange" |
| | | @focus="getTemplateList" |
| | | style="width: 500px;" |
| | | placeholder="è¯·éæ©æ¨¡çæè
è¾å
¥æ°ç模çåç§°åéæ©" |
| | | class="no-arrow-select"> |
| | | <el-option v-for="item in templateList" |
| | | :key="item.id || item.value" |
| | | :label="item.templateName" |
| | | :value="item.templateName"> |
| | | <div class="select-button-group" style="width: 500px; margin: 20px 0;" v-if="operationType === 'add'"> |
| | | <el-select filterable allow-create :reserve-keyword="true" :default-first-option="false" clearable |
| | | v-model="templateName" :input-value="filterInputValue" @filter-change="onTemplateFilterChange" |
| | | @change="onTemplateChange" @focus="getTemplateList" style="width: 500px;" placeholder="è¯·éæ©æ¨¡çæè
è¾å
¥æ°ç模çåç§°åéæ©" |
| | | class="no-arrow-select"> |
| | | <el-option v-for="item in templateList" :key="item.id || item.value" :label="item.templateName" |
| | | :value="item.templateName"> |
| | | <div style="display: flex; justify-content: space-between; align-items: center;"> |
| | | <span>{{ item.templateName }}</span> |
| | | <el-icon v-if="item.id" |
| | | class="delete-icon" |
| | | @click.stop="handleDeleteTemplate(item)" |
| | | style="cursor: pointer; color: #f56c6c; font-size: 14px; margin-left: 8px;"> |
| | | <el-icon v-if="item.id" class="delete-icon" @click.stop="handleDeleteTemplate(item)" |
| | | style="cursor: pointer; color: #f56c6c; font-size: 14px; margin-left: 8px;"> |
| | | <Delete /> |
| | | </el-icon> |
| | | </div> |
| | | </el-option> |
| | | </el-select> |
| | | <!-- æé®ï¼ä¸ Select é«åº¦å¹é
ï¼å»æå·¦ä¾§è¾¹æ¡ï¼æ ç¼è¡æ¥ --> |
| | | <el-button size="small" |
| | | style="height: 32px;margin-left: 8px;" |
| | | @click="handleButtonClick" |
| | | :disabled="!templateName || templateName.trim() === '' || (!currentTemplateId && isTemplateNameDuplicate)"> |
| | | <el-button size="small" style="height: 32px;margin-left: 8px;" @click="handleButtonClick" |
| | | :disabled="!templateName || templateName.trim() === '' || (!currentTemplateId && isTemplateNameDuplicate)"> |
| | | ä¿å |
| | | </el-button> |
| | | </div> |
| | | </el-row> |
| | | <el-table :data="productData" |
| | | border |
| | | @selection-change="productSelected" |
| | | show-summary |
| | | :summary-method="summarizeProTable"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | width="55" /> |
| | | <el-table-column align="center" |
| | | label="åºå·" |
| | | type="index" |
| | | width="60" /> |
| | | <el-table-column label="产å大类" |
| | | prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" |
| | | prop="specificationModel" /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | width="70" /> |
| | | <el-table-column label="æ°é" |
| | | prop="quantity" |
| | | width="70" /> |
| | | <el-table-column label="åºåé¢è¦æ°é" |
| | | prop="warnNum" |
| | | width="120" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="ç¨ç(%)" |
| | | prop="taxRate" |
| | | width="80" /> |
| | | <el-table-column label="å«ç¨åä»·(å
)" |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" /> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" |
| | | prop="taxInclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" /> |
| | | <el-table-column label="ä¸å«ç¨æ»ä»·(å
)" |
| | | prop="taxExclusiveTotalPrice" |
| | | :formatter="formattedNumber" |
| | | width="150" /> |
| | | <el-table-column label="æ¯å¦è´¨æ£" |
| | | prop="isChecked" |
| | | width="150"> |
| | | <el-table :data="productData" border @selection-change="productSelected" show-summary |
| | | :summary-method="summarizeProTable"> |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="åºå·" type="index" width="60" /> |
| | | <el-table-column label="产å大类" prop="productCategory" /> |
| | | <el-table-column label="è§æ ¼åå·" prop="specificationModel" /> |
| | | <el-table-column label="åä½" prop="unit" width="70" /> |
| | | <el-table-column label="æ°é" prop="quantity" width="70" /> |
| | | <el-table-column label="åºåé¢è¦æ°é" prop="warnNum" width="120" show-overflow-tooltip /> |
| | | <el-table-column label="ç¨ç(%)" prop="taxRate" width="80" /> |
| | | <el-table-column label="å«ç¨åä»·(å
)" prop="taxInclusiveUnitPrice" :formatter="unitPriceFormatter" width="150" /> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" prop="taxInclusiveTotalPrice" :formatter="formattedNumber" width="150" /> |
| | | <el-table-column label="ä¸å«ç¨æ»ä»·(å
)" prop="taxExclusiveTotalPrice" :formatter="formattedNumber" width="150" /> |
| | | <el-table-column label="æ¯å¦è´¨æ£" prop="isChecked" width="150"> |
| | | <template #default="scope"> |
| | | <el-tag :type="scope.row.isChecked ? 'success' : 'info'"> |
| | | {{ scope.row.isChecked ? 'æ¯' : 'å¦' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="å
¥åºå®¡æ ¸ç¶æ" |
| | | prop="stockInApprovalStatus" |
| | | width="120"> |
| | | <el-table-column label="å
¥åºå®¡æ ¸ç¶æ" prop="stockInApprovalStatus" width="120"> |
| | | <template #default="scope"> |
| | | <el-tag :type="getStockInApprovalStatusType(scope.row.stockInApprovalStatus)" |
| | | size="small"> |
| | | <el-tag :type="getStockInApprovalStatusType(scope.row.stockInApprovalStatus)" size="small"> |
| | | {{ scope.row.stockInApprovalStatus || '--' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column fixed="right" |
| | | label="æä½" |
| | | min-width="60" |
| | | align="center"> |
| | | <el-table-column fixed="right" label="æä½" min-width="60" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openProductForm('edit', scope.row, scope.$index)" |
| | | :disabled="scope.row.stockInApprovalStatus === 'å®å
¨å
¥åº'">ç¼è¾ |
| | | <el-button link type="primary" |
| | | @click="openProductForm('edit', scope.row, scope.$index)" |
| | | :disabled="scope.row.stockInApprovalStatus === 'å®å
¨å
¥åº'">ç¼è¾ |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="夿³¨Â·ï¼" |
| | | prop="remarks"> |
| | | <el-input v-model="form.remarks" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | type="textarea" |
| | | :rows="2" /> |
| | | <el-form-item label="夿³¨Â·ï¼" prop="remarks"> |
| | | <el-input v-model="form.remarks" placeholder="请è¾å
¥" clearable type="textarea" :rows="2" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="éä»¶ææï¼" |
| | | prop="purchaseLedgerFiles"> |
| | | <el-form-item label="éä»¶ææï¼" prop="purchaseLedgerFiles"> |
| | | <FileUpload v-model:file-list="fileList" /> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | </el-form> |
| | | </FormDialog> |
| | | <!-- 导å
¥å¼¹çª --> |
| | | <FormDialog v-model="importUpload.open" |
| | | :title="importUpload.title" |
| | | :width="'600px'" |
| | | @close="importUpload.open = false" |
| | | @confirm="submitImportFile" |
| | | @cancel="importUpload.open = false"> |
| | | <el-upload ref="importUploadRef" |
| | | :limit="1" |
| | | accept=".xlsx,.xls" |
| | | :action="importUpload.url" |
| | | :headers="importUpload.headers" |
| | | :before-upload="importUpload.beforeUpload" |
| | | :on-success="importUpload.onSuccess" |
| | | :on-error="importUpload.onError" |
| | | :on-progress="importUpload.onProgress" |
| | | :on-change="importUpload.onChange" |
| | | :auto-upload="false" |
| | | drag> |
| | | <FormDialog v-model="importUpload.open" :title="importUpload.title" :width="'600px'" |
| | | @close="importUpload.open = false" @confirm="submitImportFile" @cancel="importUpload.open = false"> |
| | | <el-upload ref="importUploadRef" :limit="1" accept=".xlsx,.xls" :action="importUpload.url" |
| | | :headers="importUpload.headers" :before-upload="importUpload.beforeUpload" :on-success="importUpload.onSuccess" |
| | | :on-error="importUpload.onError" :on-progress="importUpload.onProgress" :on-change="importUpload.onChange" |
| | | :auto-upload="false" drag> |
| | | <i class="el-icon-upload"></i> |
| | | <div class="el-upload__text"> |
| | | å°æä»¶æå°æ¤å¤ï¼æ<em>ç¹å»ä¸ä¼ </em> |
| | |
| | | <template #tip> |
| | | <div class="el-upload__tip"> |
| | | ä»
æ¯æ xls/xlsxï¼å¤§å°ä¸è¶
è¿ 10MBã |
| | | <el-button link |
| | | type="primary" |
| | | @click="downloadTemplate">ä¸è½½å¯¼å
¥æ¨¡æ¿</el-button> |
| | | <el-button link type="primary" @click="downloadTemplate">ä¸è½½å¯¼å
¥æ¨¡æ¿</el-button> |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | </FormDialog> |
| | | <FormDialog v-model="productFormVisible" |
| | | :title="productOperationType === 'add' ? 'æ°å¢äº§å' : 'ç¼è¾äº§å'" |
| | | :width="'40%'" |
| | | :operation-type="productOperationType" |
| | | @close="closeProductDia" |
| | | @confirm="submitProduct" |
| | | @cancel="closeProductDia"> |
| | | <el-form :model="productForm" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="productRules" |
| | | ref="productFormRef"> |
| | | <FormDialog v-model="productFormVisible" :title="productOperationType === 'add' ? 'æ°å¢äº§å' : 'ç¼è¾äº§å'" :width="'40%'" |
| | | :operation-type="productOperationType" @close="closeProductDia" @confirm="submitProduct" |
| | | @cancel="closeProductDia"> |
| | | <el-form :model="productForm" label-width="140px" label-position="top" :rules="productRules" ref="productFormRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="产å大类ï¼" |
| | | prop="productId"> |
| | | <el-tree-select v-model="productForm.productId" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | filterable |
| | | check-strictly |
| | | @change="getModels" |
| | | :data="productOptions" |
| | | :render-after-expand="false" |
| | | style="width: 100%" /> |
| | | <el-form-item label="产å大类ï¼" prop="productId"> |
| | | <el-tree-select v-model="productForm.productId" placeholder="è¯·éæ©" clearable filterable check-strictly |
| | | @change="getModels" :data="productOptions" :render-after-expand="false" style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="è§æ ¼åå·ï¼" |
| | | prop="productModelId"> |
| | | <el-select v-model="productForm.productModelId" |
| | | placeholder="è¯·éæ©" |
| | | filterable |
| | | clearable |
| | | @change="getProductModel"> |
| | | <el-option v-for="item in modelOptions" |
| | | :key="item.id" |
| | | :label="item.model" |
| | | :value="item.id" /> |
| | | <el-form-item label="è§æ ¼åå·ï¼" prop="productModelId"> |
| | | <el-select v-model="productForm.productModelId" placeholder="è¯·éæ©" filterable clearable |
| | | @change="getProductModel"> |
| | | <el-option v-for="item in modelOptions" :key="item.id" :label="item.model" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åä½ï¼" |
| | | prop="unit"> |
| | | <el-input v-model="productForm.unit" |
| | | placeholder="请è¾å
¥" |
| | | clearable /> |
| | | <el-form-item label="åä½ï¼" prop="unit"> |
| | | <el-input v-model="productForm.unit" placeholder="请è¾å
¥" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç¨ç(%)ï¼" |
| | | prop="taxRate"> |
| | | <el-select v-model="productForm.taxRate" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | @change="mathNum"> |
| | | <el-option v-for="dict in tax_rate" |
| | | :key="dict.value" |
| | | :label="dict.label" |
| | | :value="dict.value" /> |
| | | <el-form-item label="ç¨ç(%)ï¼" prop="taxRate"> |
| | | <el-select v-model="productForm.taxRate" placeholder="è¯·éæ©" clearable @change="mathNum"> |
| | | <el-option v-for="dict in tax_rate" :key="dict.value" :label="dict.label" :value="dict.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å«ç¨åä»·(å
)ï¼" |
| | | prop="taxInclusiveUnitPrice"> |
| | | <el-input-number v-model="productForm.taxInclusiveUnitPrice" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="mathNum" /> |
| | | <el-form-item label="å«ç¨åä»·(å
)ï¼" prop="taxInclusiveUnitPrice"> |
| | | <el-input-number v-model="productForm.taxInclusiveUnitPrice" :precision="6" :step="0.1" :min="0" clearable |
| | | style="width: 100%" @change="mathNum" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ°éï¼" |
| | | prop="quantity"> |
| | | <el-input-number :step="0.1" |
| | | clearable |
| | | :precision="2" |
| | | :min="0" |
| | | style="width: 100%" |
| | | v-model="productForm.quantity" |
| | | placeholder="请è¾å
¥" |
| | | @change="mathNum" /> |
| | | <el-form-item label="æ°éï¼" prop="quantity"> |
| | | <el-input-number :step="0.1" clearable :precision="2" :min="0" style="width: 100%" |
| | | v-model="productForm.quantity" placeholder="请è¾å
¥" @change="mathNum" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å«ç¨æ»ä»·(å
)ï¼" |
| | | prop="taxInclusiveTotalPrice"> |
| | | <el-input-number v-model="productForm.taxInclusiveTotalPrice" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="reverseMathNum('taxInclusiveTotalPrice')" /> |
| | | <el-form-item label="å«ç¨æ»ä»·(å
)ï¼" prop="taxInclusiveTotalPrice"> |
| | | <el-input-number v-model="productForm.taxInclusiveTotalPrice" :precision="2" :step="0.1" :min="0" |
| | | clearable style="width: 100%" @change="reverseMathNum('taxInclusiveTotalPrice')" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ä¸å«ç¨æ»ä»·(å
)ï¼" |
| | | prop="taxExclusiveTotalPrice"> |
| | | <el-input-number v-model="productForm.taxExclusiveTotalPrice" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="reverseMathNum('taxExclusiveTotalPrice')" /> |
| | | <el-form-item label="ä¸å«ç¨æ»ä»·(å
)ï¼" prop="taxExclusiveTotalPrice"> |
| | | <el-input-number v-model="productForm.taxExclusiveTotalPrice" :precision="2" :step="0.1" :min="0" |
| | | clearable style="width: 100%" @change="reverseMathNum('taxExclusiveTotalPrice')" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å票类åï¼" |
| | | prop="invoiceType"> |
| | | <el-select v-model="productForm.invoiceType" |
| | | placeholder="è¯·éæ©" |
| | | clearable> |
| | | <el-option label="墿®ç¥¨" |
| | | value="墿®ç¥¨" /> |
| | | <el-option label="å¢ä¸ç¥¨" |
| | | value="å¢ä¸ç¥¨" /> |
| | | <el-form-item label="å票类åï¼" prop="invoiceType"> |
| | | <el-select v-model="productForm.invoiceType" placeholder="è¯·éæ©" clearable> |
| | | <el-option label="墿®ç¥¨" value="墿®ç¥¨" /> |
| | | <el-option label="å¢ä¸ç¥¨" value="å¢ä¸ç¥¨" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="åºåé¢è¦æ°éï¼" |
| | | prop="warnNum"> |
| | | <el-input-number v-model="productForm.warnNum" |
| | | :precision="2" |
| | | :step="0.1" |
| | | :min="0" |
| | | clearable |
| | | style="width: 100%" /> |
| | | <el-form-item label="åºåé¢è¦æ°éï¼" prop="warnNum"> |
| | | <el-input-number v-model="productForm.warnNum" :precision="2" :step="0.1" :min="0" clearable |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ¯å¦è´¨æ£ï¼" |
| | | prop="isChecked"> |
| | | <el-form-item label="æ¯å¦è´¨æ£ï¼" prop="isChecked"> |
| | | <el-radio-group v-model="productForm.isChecked"> |
| | | <el-radio label="æ¯" |
| | | :value="true" /> |
| | | <el-radio label="å¦" |
| | | :value="false" /> |
| | | <el-radio label="æ¯" :value="true" /> |
| | | <el-radio label="å¦" :value="false" /> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | <FileList v-if="fileListDialogVisible" |
| | | v-model:visible="fileListDialogVisible" |
| | | record-type="purchase_ledger" |
| | | :record-id="recordId" /> |
| | | <FileList v-if="fileListDialogVisible" v-model:visible="fileListDialogVisible" record-type="purchase_ledger" |
| | | :record-id="recordId" /> |
| | | <Detail ref="detailRef" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { |
| | | ref, |
| | | onMounted, |
| | | reactive, |
| | | toRefs, |
| | | getCurrentInstance, |
| | | nextTick, |
| | | } from "vue"; |
| | | import { Search, Delete } from "@element-plus/icons-vue"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addOrUpdateSalesLedgerProduct, |
| | | delProduct, |
| | | delLedgerFile, |
| | | getProductInfoByContractNo, |
| | | } from "@/api/salesManagement/salesLedger.js"; |
| | | import { |
| | | addOrEditPurchase, |
| | | addPurchaseTemplate, |
| | | updatePurchaseTemplate, |
| | | createPurchaseNo, |
| | | delPurchase, |
| | | getSalesNo, |
| | | purchaseListPage, |
| | | productList, |
| | | getPurchaseById, |
| | | getOptions, |
| | | getPurchaseTemplateList, |
| | | delPurchaseTemplate, |
| | | } from "@/api/procurementManagement/procurementLedger.js"; |
| | | import useFormData from "@/hooks/useFormData.js"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import Detail from "./detail.vue"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { |
| | | ref, |
| | | onMounted, |
| | | reactive, |
| | | toRefs, |
| | | getCurrentInstance, |
| | | nextTick, |
| | | } from "vue"; |
| | | import { Search, Delete } from "@element-plus/icons-vue"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import { |
| | | addOrUpdateSalesLedgerProduct, |
| | | delProduct, |
| | | delLedgerFile, |
| | | getProductInfoByContractNo, |
| | | } from "@/api/salesManagement/salesLedger.js"; |
| | | import { |
| | | addOrEditPurchase, |
| | | addPurchaseTemplate, |
| | | updatePurchaseTemplate, |
| | | createPurchaseNo, |
| | | delPurchase, |
| | | getSalesNo, |
| | | purchaseListPage, |
| | | productList, |
| | | getPurchaseById, |
| | | getOptions, |
| | | getPurchaseTemplateList, |
| | | delPurchaseTemplate, |
| | | } from "@/api/procurementManagement/procurementLedger.js"; |
| | | import useFormData from "@/hooks/useFormData.js"; |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | ); |
| | | |
| | | const detailRef = ref(null); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const { tax_rate } = proxy.useDict("tax_rate"); |
| | | const tableData = ref([]); |
| | | const productData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const productSelectedRows = ref([]); |
| | | const modelOptions = ref([]); |
| | | const userList = ref([]); |
| | | const productOptions = ref([]); |
| | | const salesContractList = ref([]); |
| | | const supplierList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const recordId = ref(); |
| | | const fileListDialogVisible = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | const fileList = ref([]); |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { modelList, productTreeList } from "@/api/basicData/product.js"; |
| | | import dayjs from "dayjs"; |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | |
| | | const userStore = useUserStore(); |
| | | |
| | | // æ¯å¦æ¾ç¤ºéå®ååå·ç»å® |
| | | const showSalesContractBinding = false; |
| | | |
| | | // 订å审æ¹ç¶ææ¾ç¤ºææ¬ |
| | | const approvalStatusText = { |
| | | 1: "å¾
å®¡æ ¸", |
| | | 2: "审æ¹ä¸", |
| | | 3: "审æ¹éè¿", |
| | | 4: "审æ¹å¤±è´¥", |
| | | }; |
| | | |
| | | // è·å审æ¹ç¶ææ ç¾ç±»å |
| | | const getApprovalStatusType = status => { |
| | | const typeMap = { |
| | | 1: "info", // å¾
å®¡æ ¸ - ç°è² |
| | | 2: "warning", // 审æ¹ä¸ - æ©è² |
| | | 3: "success", // 审æ¹éè¿ - ç»¿è² |
| | | 4: "danger", // 审æ¹å¤±è´¥ - çº¢è² |
| | | }; |
| | | return typeMap[status] || ""; |
| | | }; |
| | | |
| | | // è·åå
¥åºç¶ææ ç¾ç±»å |
| | | const getStockInStatusType = status => { |
| | | const typeMap = { |
| | | "å¾
å
¥åº": "info", // å¾
å
¥åº - ç°è² |
| | | "å
¥åºä¸": "warning", // å
¥åºä¸ - æ©è² |
| | | "å®å
¨å
¥åº": "success", // å®å
¨å
¥åº - ç»¿è² |
| | | }; |
| | | return typeMap[status] || ""; |
| | | }; |
| | | |
| | | // è·åå
¥åºå®¡æ ¸ç¶ææ ç¾ç±»å |
| | | const getStockInApprovalStatusType = status => { |
| | | const typeMap = { |
| | | "å¾
å
¥åº": "info", // å¾
å
¥åº - ç°è² |
| | | "å
¥åºä¸": "warning", // å
¥åºä¸ - æ©è² |
| | | "å®å
¨å
¥åº": "success", // å®å
¨å
¥åº - ç»¿è² |
| | | }; |
| | | return typeMap[status] || ""; |
| | | }; |
| | | |
| | | const templateName = ref(""); |
| | | const filterInputValue = ref(""); |
| | | const templateList = ref([]); |
| | | const isTemplateNameDuplicate = ref(false); // æ 记模æ¿åç§°æ¯å¦éå¤ |
| | | // å½åéä¸ç模æ¿IDï¼ç¨äºåºåæ°å¢æ¨¡æ¿è¿æ¯æ´æ°æ¨¡æ¿ï¼ |
| | | const currentTemplateId = ref(null); |
| | | |
| | | // æ£æ¥æ¨¡æ¿åç§°æ¯å¦éå¤ |
| | | const checkTemplateNameDuplicate = name => { |
| | | if (!name || name.trim() === "") { |
| | | isTemplateNameDuplicate.value = false; |
| | | return false; |
| | | } |
| | | const isDuplicate = templateList.value.some( |
| | | item => item.templateName === name.trim() |
| | | ); |
| | | isTemplateNameDuplicate.value = isDuplicate; |
| | | return isDuplicate; |
| | | }; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const { tax_rate } = proxy.useDict("tax_rate"); |
| | | const tableData = ref([]); |
| | | const productData = ref([]); |
| | | const selectedRows = ref([]); |
| | | const productSelectedRows = ref([]); |
| | | const modelOptions = ref([]); |
| | | const userList = ref([]); |
| | | const productOptions = ref([]); |
| | | const salesContractList = ref([]); |
| | | const supplierList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const recordId = ref(); |
| | | const fileListDialogVisible = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | }); |
| | | const total = ref(0); |
| | | const fileList = ref([]); |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { modelList, productTreeList } from "@/api/basicData/product.js"; |
| | | import dayjs from "dayjs"; |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | // 夿æä»¶æ¯å¦ä¸ºå¾ç |
| | | const isImage = (filename) => { |
| | | if (!filename) return false; |
| | | const ext = filename.substring(filename.lastIndexOf('.')).toLowerCase(); |
| | | return ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.bmp'].includes(ext); |
| | | }; |
| | | |
| | | const userStore = useUserStore(); |
| | | |
| | | // 订å审æ¹ç¶ææ¾ç¤ºææ¬ |
| | | const approvalStatusText = { |
| | | 1: "å¾
å®¡æ ¸", |
| | | 2: "审æ¹ä¸", |
| | | 3: "审æ¹éè¿", |
| | | 4: "审æ¹å¤±è´¥", |
| | | }; |
| | | |
| | | // è·å审æ¹ç¶ææ ç¾ç±»å |
| | | const getApprovalStatusType = status => { |
| | | const typeMap = { |
| | | 1: "info", // å¾
å®¡æ ¸ - ç°è² |
| | | 2: "warning", // 审æ¹ä¸ - æ©è² |
| | | 3: "success", // 审æ¹éè¿ - ç»¿è² |
| | | 4: "danger", // 审æ¹å¤±è´¥ - çº¢è² |
| | | }; |
| | | return typeMap[status] || ""; |
| | | }; |
| | | |
| | | // è·åå
¥åºç¶ææ ç¾ç±»å |
| | | const getStockInStatusType = status => { |
| | | const typeMap = { |
| | | "å¾
å
¥åº": "info", // å¾
å
¥åº - ç°è² |
| | | "å
¥åºä¸": "warning", // å
¥åºä¸ - æ©è² |
| | | "å®å
¨å
¥åº": "success", // å®å
¨å
¥åº - ç»¿è² |
| | | }; |
| | | return typeMap[status] || ""; |
| | | }; |
| | | |
| | | // è·åå
¥åºå®¡æ ¸ç¶ææ ç¾ç±»å |
| | | const getStockInApprovalStatusType = status => { |
| | | const typeMap = { |
| | | "å¾
å
¥åº": "info", // å¾
å
¥åº - ç°è² |
| | | "å
¥åºä¸": "warning", // å
¥åºä¸ - æ©è² |
| | | "å®å
¨å
¥åº": "success", // å®å
¨å
¥åº - ç»¿è² |
| | | }; |
| | | return typeMap[status] || ""; |
| | | }; |
| | | |
| | | const templateName = ref(""); |
| | | const filterInputValue = ref(""); |
| | | const templateList = ref([]); |
| | | const isTemplateNameDuplicate = ref(false); // æ 记模æ¿åç§°æ¯å¦éå¤ |
| | | // å½åéä¸ç模æ¿IDï¼ç¨äºåºåæ°å¢æ¨¡æ¿è¿æ¯æ´æ°æ¨¡æ¿ï¼ |
| | | const currentTemplateId = ref(null); |
| | | |
| | | // æ£æ¥æ¨¡æ¿åç§°æ¯å¦éå¤ |
| | | const checkTemplateNameDuplicate = name => { |
| | | if (!name || name.trim() === "") { |
| | | isTemplateNameDuplicate.value = false; |
| | | return false; |
| | | } |
| | | const isDuplicate = templateList.value.some( |
| | | item => item.templateName === name.trim() |
| | | ); |
| | | isTemplateNameDuplicate.value = isDuplicate; |
| | | return isDuplicate; |
| | | }; |
| | | |
| | | // 鲿宿¶å¨ |
| | | let duplicateCheckTimer = null; |
| | | const onTemplateFilterChange = val => { |
| | | filterInputValue.value = val ?? ""; |
| | | // æ¸
é¤ä¹åç宿¶å¨ |
| | | if (duplicateCheckTimer) { |
| | | clearTimeout(duplicateCheckTimer); |
| | | } |
| | | // 宿¶æ£æ¥æ¨¡æ¿åç§°æ¯å¦éå¤ï¼é²æå¤çï¼é¿å
é¢ç¹æç¤ºï¼ |
| | | if (val && val.trim()) { |
| | | duplicateCheckTimer = setTimeout(() => { |
| | | const isDuplicate = checkTemplateNameDuplicate(val); |
| | | if (isDuplicate) { |
| | | ElMessage({ |
| | | message: "模æ¿åç§°å·²åå¨ï¼è¯·æ´æ¢æ¨¡æ¿åç§°", |
| | | type: "warning", |
| | | duration: 2000, |
| | | }); |
| | | } |
| | | }, 300); // 300ms 鲿 |
| | | } else { |
| | | isTemplateNameDuplicate.value = false; |
| | | } |
| | | }; |
| | | |
| | | // allow-create æ¶ï¼è¾å
¥ä¸åå¨çå
容ä¼ä½ä¸º string å¼è¿åï¼è¿é忥åè¾å
¥æ¡ä»¥ç¡®ä¿æåä¸ä¸¢ |
| | | const onTemplateChange = async val => { |
| | | if (typeof val === "string") { |
| | | filterInputValue.value = val; |
| | | // éæ©æè¾å
¥æ¶æ£æ¥éå¤ |
| | | checkTemplateNameDuplicate(val); |
| | | } |
| | | |
| | | // è¿æ»¤æ°æ®ï¼æ¥æ¾å¹é
çæ¨¡æ¿ |
| | | const matchedTemplate = templateList.value.find( |
| | | item => item.templateName === val |
| | | ); |
| | | |
| | | if (matchedTemplate?.id) { |
| | | // è®°å½å½åéä¸ç模æ¿IDï¼åç»ä¿åæ¶è¿è¡æ´æ°æä½ |
| | | currentTemplateId.value = matchedTemplate.id; |
| | | // éä¸å·²ææ¨¡æ¿æ¶ï¼ä¸åºè§ä¸ºâ模æ¿åç§°éå¤å¯¼è´ä¸å¯ä¿åâ |
| | | isTemplateNameDuplicate.value = false; |
| | | // 妿æ¾å°æ¨¡æ¿ï¼åªèµå¼ä¾åºåã项ç®åç§°ã仿¬¾æ¹å¼å产åä¿¡æ¯ |
| | | if (matchedTemplate.supplierId) { |
| | | form.value.supplierId = matchedTemplate.supplierId; |
| | | } |
| | | if (matchedTemplate.supplierName) { |
| | | form.value.supplierName = matchedTemplate.supplierName; |
| | | } |
| | | if (matchedTemplate.projectName) { |
| | | form.value.projectName = matchedTemplate.projectName; |
| | | } |
| | | if (matchedTemplate.paymentMethod) { |
| | | form.value.paymentMethod = matchedTemplate.paymentMethod; |
| | | } |
| | | // æ¨¡æ¿æ°æ®ä¸ç产ååæ®µæ¯ productListï¼éè¦è½¬æ¢ä¸º productData |
| | | productData.value = |
| | | matchedTemplate.productList || matchedTemplate.productData || []; |
| | | } else { |
| | | // æªå¹é
å°å·²ææ¨¡æ¿ï¼è§ä¸ºæ°æ¨¡æ¿ |
| | | currentTemplateId.value = null; |
| | | // å¦ææ²¡ææ¾å°æ¨¡æ¿ï¼é置表åï¼ä¿æå½å表åç¶æï¼ |
| | | const currentFormData = { ...form.value }; |
| | | const currentProductData = [...productData.value]; |
| | | |
| | | // å¦æå¯¹è¯æ¡æªæå¼ï¼å
æå¼ |
| | | if (!dialogFormVisible.value) { |
| | | operationType.value = "add"; |
| | | dialogFormVisible.value = true; |
| | | } |
| | | |
| | | // çå¾
ä¸ä¸ä¸ª tick 忢夿°æ® |
| | | await nextTick(); |
| | | form.value = { |
| | | ...form.value, |
| | | ...currentFormData, |
| | | }; |
| | | productData.value = currentProductData; |
| | | } |
| | | }; |
| | | |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", // ä¾åºååç§° |
| | | purchaseContractNumber: "", // éè´ååç¼å· |
| | | salesContractNo: "", // éå®ååç¼å· |
| | | projectName: "", // 项ç®åç§° |
| | | entryDate: null, // å½å
¥æ¥æ |
| | | entryDateStart: undefined, |
| | | entryDateEnd: undefined, |
| | | }, |
| | | form: { |
| | | purchaseContractNumber: "", |
| | | salesLedgerId: "", |
| | | projectName: "", |
| | | recorderId: "", |
| | | entryDate: "", |
| | | productData: [], |
| | | supplierName: "", |
| | | supplierId: "", |
| | | paymentMethod: "", |
| | | executionDate: "", |
| | | isChecked: false, |
| | | }, |
| | | rules: { |
| | | purchaseContractNumber: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | projectName: [ |
| | | { required: true, message: "请è¾å
¥é¡¹ç®åç§°", trigger: "blur" }, |
| | | ], |
| | | supplierId: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | entryDate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | executionDate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | const { form: searchForm } = useFormData({ |
| | | ...data.searchForm, |
| | | // 设置å½å
¥æ¥æèå´ä¸ºå½å¤© |
| | | entryDate: [ |
| | | dayjs().startOf("day").format("YYYY-MM-DD"), |
| | | dayjs().endOf("day").format("YYYY-MM-DD"), |
| | | ], |
| | | entryDateStart: dayjs().startOf("day").format("YYYY-MM-DD"), |
| | | entryDateEnd: dayjs().endOf("day").format("YYYY-MM-DD"), |
| | | }); |
| | | |
| | | // 产å表åå¼¹æ¡æ°æ® |
| | | const productFormVisible = ref(false); |
| | | const productOperationType = ref(""); |
| | | const productOperationIndex = ref(""); |
| | | const currentId = ref(""); |
| | | const productFormData = reactive({ |
| | | productForm: { |
| | | productId: "", |
| | | productCategory: "", |
| | | productModelId: "", |
| | | specificationModel: "", |
| | | unit: "", |
| | | quantity: "", |
| | | taxInclusiveUnitPrice: "", |
| | | taxRate: "", |
| | | taxInclusiveTotalPrice: "", |
| | | taxExclusiveTotalPrice: "", |
| | | invoiceType: "", |
| | | warnNum: "", |
| | | isChecked: false, |
| | | }, |
| | | productRules: { |
| | | productId: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | productModelId: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | unit: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxInclusiveUnitPrice: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | taxRate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | warnNum: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | taxInclusiveTotalPrice: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | taxExclusiveTotalPrice: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | invoiceType: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | isChecked: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { productForm, productRules } = toRefs(productFormData); |
| | | const upload = reactive({ |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/file/upload", |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | }); |
| | | |
| | | // 导å
¥ç¸å
³ |
| | | const importUploadRef = ref(null); |
| | | const importUpload = reactive({ |
| | | title: "导å
¥éè´å°è´¦", |
| | | open: false, |
| | | url: import.meta.env.VITE_APP_BASE_API + "/purchase/ledger/import", |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | isUploading: false, |
| | | beforeUpload: file => { |
| | | const isExcel = file.name.endsWith(".xlsx") || file.name.endsWith(".xls"); |
| | | const isLt10M = file.size / 1024 / 1024 < 10; |
| | | if (!isExcel) { |
| | | proxy.$modal.msgError("ä¸ä¼ æä»¶åªè½æ¯ xlsx/xls æ ¼å¼!"); |
| | | return false; |
| | | } |
| | | if (!isLt10M) { |
| | | proxy.$modal.msgError("ä¸ä¼ æä»¶å¤§å°ä¸è½è¶
è¿ 10MB!"); |
| | | return false; |
| | | } |
| | | return true; |
| | | }, |
| | | onChange: (file, fileList) => { |
| | | // noop |
| | | }, |
| | | onProgress: (event, file, fileList) => { |
| | | // noop |
| | | }, |
| | | onSuccess: (response, file, fileList) => { |
| | | importUpload.isUploading = false; |
| | | if (response?.code === 200) { |
| | | proxy.$modal.msgSuccess("导å
¥æå"); |
| | | importUpload.open = false; |
| | | if (importUploadRef.value) { |
| | | importUploadRef.value.clearFiles?.(); |
| | | } |
| | | getList(); |
| | | } else { |
| | | proxy.$modal.msgError(response?.msg || "导å
¥å¤±è´¥"); |
| | | } |
| | | }, |
| | | onError: () => { |
| | | importUpload.isUploading = false; |
| | | proxy.$modal.msgError("导å
¥å¤±è´¥ï¼è¯·éè¯"); |
| | | }, |
| | | }); |
| | | |
| | | const handleImport = () => { |
| | | importUpload.title = "导å
¥éè´å°è´¦"; |
| | | importUpload.open = true; |
| | | importUpload.isUploading = false; |
| | | if (importUploadRef.value) { |
| | | importUploadRef.value.clearFiles?.(); |
| | | } |
| | | }; |
| | | |
| | | // ä¸è½½å¯¼å
¥æ¨¡æ¿ï¼å¦å端路å¾ä¸åï¼å¯å¨æ¤å¤è°æ´ï¼ |
| | | const downloadTemplate = () => { |
| | | proxy.download( |
| | | "/purchase/ledger/exportTemplate", |
| | | {}, |
| | | "éè´å°è´¦å¯¼å
¥æ¨¡æ¿.xlsx" |
| | | ); |
| | | }; |
| | | |
| | | const submitImportFile = () => { |
| | | importUpload.isUploading = true; |
| | | proxy.$refs["importUploadRef"]?.submit?.(); |
| | | }; |
| | | |
| | | const changeDaterange = value => { |
| | | if (value) { |
| | | searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD"); |
| | | searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD"); |
| | | } else { |
| | | searchForm.entryDateStart = undefined; |
| | | searchForm.entryDateEnd = undefined; |
| | | } |
| | | handleQuery(); |
| | | }; |
| | | |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | // ä¿åæ¨¡æ¿ |
| | | const handleButtonClick = async () => { |
| | | // æ£æ¥æ¨¡æ¿åç§°æ¯å¦ä¸ºç©º |
| | | if (!templateName.value || templateName.value.trim() === "") { |
| | | ElMessage({ |
| | | message: "请è¾å
¥æ¨¡æ¿åç§°", |
| | | type: "warning", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // 妿æ¯âæ°å¢æ¨¡æ¿âï¼æ²¡æéä¸å·²ææ¨¡æ¿ï¼ï¼æéè¦åéåæ ¡éªï¼ |
| | | // è¥æ¯éä¸å·²ææ¨¡æ¿åä¿®æ¹ï¼åå
许使ç¨ååç§°ï¼è§ä¸ºæ´æ°ï¼ |
| | | if (!currentTemplateId.value) { |
| | | const isDuplicate = checkTemplateNameDuplicate(templateName.value); |
| | | // 鲿宿¶å¨ |
| | | let duplicateCheckTimer = null; |
| | | const onTemplateFilterChange = val => { |
| | | filterInputValue.value = val ?? ""; |
| | | // æ¸
é¤ä¹åç宿¶å¨ |
| | | if (duplicateCheckTimer) { |
| | | clearTimeout(duplicateCheckTimer); |
| | | } |
| | | // 宿¶æ£æ¥æ¨¡æ¿åç§°æ¯å¦éå¤ï¼é²æå¤çï¼é¿å
é¢ç¹æç¤ºï¼ |
| | | if (val && val.trim()) { |
| | | duplicateCheckTimer = setTimeout(() => { |
| | | const isDuplicate = checkTemplateNameDuplicate(val); |
| | | if (isDuplicate) { |
| | | ElMessage({ |
| | | message: "模æ¿åç§°å·²åå¨ï¼è¯·æ´æ¢æ¨¡æ¿åç§°", |
| | | type: "warning", |
| | | duration: 2000, |
| | | }); |
| | | return; |
| | | } |
| | | }, 300); // 300ms 鲿 |
| | | } else { |
| | | isTemplateNameDuplicate.value = false; |
| | | } |
| | | }; |
| | | |
| | | // allow-create æ¶ï¼è¾å
¥ä¸åå¨çå
容ä¼ä½ä¸º string å¼è¿åï¼è¿é忥åè¾å
¥æ¡ä»¥ç¡®ä¿æåä¸ä¸¢ |
| | | const onTemplateChange = async val => { |
| | | if (typeof val === "string") { |
| | | filterInputValue.value = val; |
| | | // éæ©æè¾å
¥æ¶æ£æ¥éå¤ |
| | | checkTemplateNameDuplicate(val); |
| | | } |
| | | |
| | | // è¿æ»¤æ°æ®ï¼æ¥æ¾å¹é
çæ¨¡æ¿ |
| | | const matchedTemplate = templateList.value.find( |
| | | item => item.templateName === val |
| | | ); |
| | | |
| | | if (matchedTemplate?.id) { |
| | | // è®°å½å½åéä¸ç模æ¿IDï¼åç»ä¿åæ¶è¿è¡æ´æ°æä½ |
| | | currentTemplateId.value = matchedTemplate.id; |
| | | // éä¸å·²ææ¨¡æ¿æ¶ï¼ä¸åºè§ä¸ºâ模æ¿åç§°éå¤å¯¼è´ä¸å¯ä¿åâ |
| | | isTemplateNameDuplicate.value = false; |
| | | // 妿æ¾å°æ¨¡æ¿ï¼åªèµå¼ä¾åºåã项ç®åç§°ã仿¬¾æ¹å¼å产åä¿¡æ¯ |
| | | if (matchedTemplate.supplierId) { |
| | | form.value.supplierId = matchedTemplate.supplierId; |
| | | } |
| | | if (matchedTemplate.supplierName) { |
| | | form.value.supplierName = matchedTemplate.supplierName; |
| | | } |
| | | if (matchedTemplate.projectName) { |
| | | form.value.projectName = matchedTemplate.projectName; |
| | | } |
| | | if (matchedTemplate.paymentMethod) { |
| | | form.value.paymentMethod = matchedTemplate.paymentMethod; |
| | | } |
| | | // æ¨¡æ¿æ°æ®ä¸ç产ååæ®µæ¯ productListï¼éè¦è½¬æ¢ä¸º productData |
| | | productData.value = |
| | | matchedTemplate.productList || matchedTemplate.productData || []; |
| | | } else { |
| | | // æªå¹é
å°å·²ææ¨¡æ¿ï¼è§ä¸ºæ°æ¨¡æ¿ |
| | | currentTemplateId.value = null; |
| | | // å¦ææ²¡ææ¾å°æ¨¡æ¿ï¼é置表åï¼ä¿æå½å表åç¶æï¼ |
| | | const currentFormData = { ...form.value }; |
| | | const currentProductData = [...productData.value]; |
| | | |
| | | // å¦æå¯¹è¯æ¡æªæå¼ï¼å
æå¼ |
| | | if (!dialogFormVisible.value) { |
| | | operationType.value = "add"; |
| | | dialogFormVisible.value = true; |
| | | } |
| | | |
| | | // æ£æ¥ä¾åºåæ¯å¦éæ© |
| | | if (!form.value.supplierId) { |
| | | // çå¾
ä¸ä¸ä¸ª tick 忢夿°æ® |
| | | await nextTick(); |
| | | form.value = { |
| | | ...form.value, |
| | | ...currentFormData, |
| | | }; |
| | | productData.value = currentProductData; |
| | | } |
| | | }; |
| | | |
| | | // ç¨æ·ä¿¡æ¯è¡¨åå¼¹æ¡æ°æ® |
| | | const operationType = ref(""); |
| | | const dialogFormVisible = ref(false); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | supplierName: "", // ä¾åºååç§° |
| | | purchaseContractNumber: "", // éè´ååç¼å· |
| | | salesContractNo: "", // éå®ååç¼å· |
| | | projectName: "", // 项ç®åç§° |
| | | entryDate: null, // å½å
¥æ¥æ |
| | | entryDateStart: undefined, |
| | | entryDateEnd: undefined, |
| | | }, |
| | | form: { |
| | | purchaseContractNumber: "", |
| | | salesLedgerId: "", |
| | | projectName: "", |
| | | recorderId: "", |
| | | entryDate: "", |
| | | productData: [], |
| | | supplierName: "", |
| | | supplierId: "", |
| | | paymentMethod: "", |
| | | executionDate: "", |
| | | isChecked: false, |
| | | }, |
| | | rules: { |
| | | purchaseContractNumber: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | projectName: [ |
| | | { required: true, message: "请è¾å
¥é¡¹ç®åç§°", trigger: "blur" }, |
| | | ], |
| | | supplierId: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | entryDate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | executionDate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | const { form: searchForm } = useFormData({ |
| | | ...data.searchForm, |
| | | // 设置å½å
¥æ¥æèå´ä¸ºå½å¤© |
| | | entryDate: [ |
| | | dayjs().startOf("day").format("YYYY-MM-DD"), |
| | | dayjs().endOf("day").format("YYYY-MM-DD"), |
| | | ], |
| | | entryDateStart: dayjs().startOf("day").format("YYYY-MM-DD"), |
| | | entryDateEnd: dayjs().endOf("day").format("YYYY-MM-DD"), |
| | | }); |
| | | |
| | | // 产å表åå¼¹æ¡æ°æ® |
| | | const productFormVisible = ref(false); |
| | | const productOperationType = ref(""); |
| | | const productOperationIndex = ref(""); |
| | | const currentId = ref(""); |
| | | const productFormData = reactive({ |
| | | productForm: { |
| | | productId: "", |
| | | productCategory: "", |
| | | productModelId: "", |
| | | specificationModel: "", |
| | | unit: "", |
| | | quantity: "", |
| | | taxInclusiveUnitPrice: "", |
| | | taxRate: "", |
| | | taxInclusiveTotalPrice: "", |
| | | taxExclusiveTotalPrice: "", |
| | | invoiceType: "", |
| | | warnNum: "", |
| | | isChecked: false, |
| | | }, |
| | | productRules: { |
| | | productId: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | productModelId: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | unit: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | taxInclusiveUnitPrice: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | taxRate: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | warnNum: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | taxInclusiveTotalPrice: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | taxExclusiveTotalPrice: [ |
| | | { required: true, message: "请è¾å
¥", trigger: "blur" }, |
| | | ], |
| | | invoiceType: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | isChecked: [{ required: true, message: "è¯·éæ©", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { productForm, productRules } = toRefs(productFormData); |
| | | const upload = reactive({ |
| | | // ä¸ä¼ çå°å |
| | | url: import.meta.env.VITE_APP_BASE_API + "/file/upload", |
| | | // 设置ä¸ä¼ ç请æ±å¤´é¨ |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | }); |
| | | |
| | | // 导å
¥ç¸å
³ |
| | | const importUploadRef = ref(null); |
| | | const importUpload = reactive({ |
| | | title: "导å
¥éè´å°è´¦", |
| | | open: false, |
| | | url: import.meta.env.VITE_APP_BASE_API + "/purchase/ledger/import", |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | isUploading: false, |
| | | beforeUpload: file => { |
| | | const isExcel = file.name.endsWith(".xlsx") || file.name.endsWith(".xls"); |
| | | const isLt10M = file.size / 1024 / 1024 < 10; |
| | | if (!isExcel) { |
| | | proxy.$modal.msgError("ä¸ä¼ æä»¶åªè½æ¯ xlsx/xls æ ¼å¼!"); |
| | | return false; |
| | | } |
| | | if (!isLt10M) { |
| | | proxy.$modal.msgError("ä¸ä¼ æä»¶å¤§å°ä¸è½è¶
è¿ 10MB!"); |
| | | return false; |
| | | } |
| | | return true; |
| | | }, |
| | | onChange: (file, fileList) => { |
| | | // noop |
| | | }, |
| | | onProgress: (event, file, fileList) => { |
| | | // noop |
| | | }, |
| | | onSuccess: (response, file, fileList) => { |
| | | importUpload.isUploading = false; |
| | | if (response?.code === 200) { |
| | | proxy.$modal.msgSuccess("导å
¥æå"); |
| | | importUpload.open = false; |
| | | if (importUploadRef.value) { |
| | | importUploadRef.value.clearFiles?.(); |
| | | } |
| | | getList(); |
| | | } else { |
| | | proxy.$modal.msgError(response?.msg || "导å
¥å¤±è´¥"); |
| | | } |
| | | }, |
| | | onError: () => { |
| | | importUpload.isUploading = false; |
| | | proxy.$modal.msgError("导å
¥å¤±è´¥ï¼è¯·éè¯"); |
| | | }, |
| | | }); |
| | | |
| | | const handleImport = () => { |
| | | importUpload.title = "导å
¥éè´å°è´¦"; |
| | | importUpload.open = true; |
| | | importUpload.isUploading = false; |
| | | if (importUploadRef.value) { |
| | | importUploadRef.value.clearFiles?.(); |
| | | } |
| | | }; |
| | | |
| | | // ä¸è½½å¯¼å
¥æ¨¡æ¿ï¼å¦å端路å¾ä¸åï¼å¯å¨æ¤å¤è°æ´ï¼ |
| | | const downloadTemplate = () => { |
| | | proxy.download( |
| | | "/purchase/ledger/exportTemplate", |
| | | {}, |
| | | "éè´å°è´¦å¯¼å
¥æ¨¡æ¿.xlsx" |
| | | ); |
| | | }; |
| | | |
| | | const submitImportFile = () => { |
| | | importUpload.isUploading = true; |
| | | proxy.$refs["importUploadRef"]?.submit?.(); |
| | | }; |
| | | |
| | | const changeDaterange = value => { |
| | | if (value) { |
| | | searchForm.entryDateStart = dayjs(value[0]).format("YYYY-MM-DD"); |
| | | searchForm.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD"); |
| | | } else { |
| | | searchForm.entryDateStart = undefined; |
| | | searchForm.entryDateEnd = undefined; |
| | | } |
| | | handleQuery(); |
| | | }; |
| | | |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | }; |
| | | const unitPriceFormatter = (row, column, cellValue) => { |
| | | return parseFloat(cellValue).toFixed(6); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | /** æç´¢æé®æä½ */ |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | // ä¿åæ¨¡æ¿ |
| | | const handleButtonClick = async () => { |
| | | // æ£æ¥æ¨¡æ¿åç§°æ¯å¦ä¸ºç©º |
| | | if (!templateName.value || templateName.value.trim() === "") { |
| | | ElMessage({ |
| | | message: "请è¾å
¥æ¨¡æ¿åç§°", |
| | | type: "warning", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // 妿æ¯âæ°å¢æ¨¡æ¿âï¼æ²¡æéä¸å·²ææ¨¡æ¿ï¼ï¼æéè¦åéåæ ¡éªï¼ |
| | | // è¥æ¯éä¸å·²ææ¨¡æ¿åä¿®æ¹ï¼åå
许使ç¨ååç§°ï¼è§ä¸ºæ´æ°ï¼ |
| | | if (!currentTemplateId.value) { |
| | | const isDuplicate = checkTemplateNameDuplicate(templateName.value); |
| | | if (isDuplicate) { |
| | | ElMessage({ |
| | | message: "请å
éæ©ä¾åºå", |
| | | message: "模æ¿åç§°å·²åå¨ï¼è¯·æ´æ¢æ¨¡æ¿åç§°", |
| | | type: "warning", |
| | | }); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // æ£æ¥æ¯å¦æäº§åæ°æ® |
| | | if (!productData.value || productData.value.length === 0) { |
| | | ElMessage({ |
| | | message: "请å
æ·»å 产åä¿¡æ¯", |
| | | type: "warning", |
| | | // æ£æ¥ä¾åºåæ¯å¦éæ© |
| | | if (!form.value.supplierId) { |
| | | ElMessage({ |
| | | message: "请å
éæ©ä¾åºå", |
| | | type: "warning", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // æ£æ¥æ¯å¦æäº§åæ°æ® |
| | | if (!productData.value || productData.value.length === 0) { |
| | | ElMessage({ |
| | | message: "请å
æ·»å 产åä¿¡æ¯", |
| | | type: "warning", |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | let params = { |
| | | productData: proxy.HaveJson(productData.value), |
| | | supplierId: form.value.supplierId, |
| | | paymentMethod: form.value.paymentMethod, |
| | | recorderId: form.value.recorderId, |
| | | projectName: form.value.projectName, |
| | | templateName: templateName.value.trim(), |
| | | }; |
| | | console.log( |
| | | "template params ===>", |
| | | params, |
| | | "currentTemplateId:", |
| | | currentTemplateId.value |
| | | ); |
| | | |
| | | // 妿 currentTemplateId æå¼ï¼è¯´æå½åæ¯âç¼è¾å·²ææ¨¡æ¿â â è°ç¨æ´æ°æ¥å£ |
| | | // å¦åä¸ºâæ°å»ºæ¨¡æ¿â â è°ç¨æ°å¢æ¥å£ |
| | | let res; |
| | | if (currentTemplateId.value) { |
| | | res = await updatePurchaseTemplate({ |
| | | id: currentTemplateId.value, |
| | | ...params, |
| | | }); |
| | | return; |
| | | } else { |
| | | res = await addPurchaseTemplate(params); |
| | | } |
| | | |
| | | try { |
| | | let params = { |
| | | productData: proxy.HaveJson(productData.value), |
| | | supplierId: form.value.supplierId, |
| | | paymentMethod: form.value.paymentMethod, |
| | | recorderId: form.value.recorderId, |
| | | projectName: form.value.projectName, |
| | | templateName: templateName.value.trim(), |
| | | }; |
| | | console.log( |
| | | "template params ===>", |
| | | params, |
| | | "currentTemplateId:", |
| | | currentTemplateId.value |
| | | ); |
| | | |
| | | // 妿 currentTemplateId æå¼ï¼è¯´æå½åæ¯âç¼è¾å·²ææ¨¡æ¿â â è°ç¨æ´æ°æ¥å£ |
| | | // å¦åä¸ºâæ°å»ºæ¨¡æ¿â â è°ç¨æ°å¢æ¥å£ |
| | | let res; |
| | | if (currentTemplateId.value) { |
| | | res = await updatePurchaseTemplate({ |
| | | id: currentTemplateId.value, |
| | | ...params, |
| | | }); |
| | | } else { |
| | | res = await addPurchaseTemplate(params); |
| | | } |
| | | |
| | | if (res && res.code === 200) { |
| | | ElMessage({ |
| | | message: currentTemplateId.value ? "æ¨¡æ¿æ´æ°æå" : "模æ¿ä¿åæå", |
| | | type: "success", |
| | | }); |
| | | // ä¿åæååéæ°è·å模æ¿å表 |
| | | await getTemplateList(); |
| | | // æ¸
空模æ¿åç§°è¾å
¥ |
| | | templateName.value = ""; |
| | | filterInputValue.value = ""; |
| | | isTemplateNameDuplicate.value = false; |
| | | // ä¿å/æ´æ°å®æåï¼éç½®å½å模æ¿ID |
| | | currentTemplateId.value = null; |
| | | } else { |
| | | ElMessage({ |
| | | message: res?.msg || "模æ¿ä¿å失败", |
| | | type: "error", |
| | | }); |
| | | } |
| | | } catch (error) { |
| | | console.error("ä¿å模æ¿å¤±è´¥:", error); |
| | | if (res && res.code === 200) { |
| | | ElMessage({ |
| | | message: "模æ¿ä¿å失败ï¼è¯·ç¨åéè¯", |
| | | message: currentTemplateId.value ? "æ¨¡æ¿æ´æ°æå" : "模æ¿ä¿åæå", |
| | | type: "success", |
| | | }); |
| | | // ä¿åæååéæ°è·å模æ¿å表 |
| | | await getTemplateList(); |
| | | // æ¸
空模æ¿åç§°è¾å
¥ |
| | | templateName.value = ""; |
| | | filterInputValue.value = ""; |
| | | isTemplateNameDuplicate.value = false; |
| | | // ä¿å/æ´æ°å®æåï¼éç½®å½å模æ¿ID |
| | | currentTemplateId.value = null; |
| | | } else { |
| | | ElMessage({ |
| | | message: res?.msg || "模æ¿ä¿å失败", |
| | | type: "error", |
| | | }); |
| | | } |
| | | }; |
| | | // å表åè®¡æ¹æ³ |
| | | const summarizeChildrenTable = param => { |
| | | return proxy.summarizeTable( |
| | | param, |
| | | [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | "ticketsNum", |
| | | "ticketsAmount", |
| | | "futureTickets", |
| | | "futureTicketsAmount", |
| | | ], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | } |
| | | ); |
| | | }; |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const { entryDate, ...rest } = searchForm; |
| | | purchaseListPage({ ...rest, ...page }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | // tableData.value = res.data.records; |
| | | tableData.value = res.data.records.map(record => ({ |
| | | ...record, |
| | | })); |
| | | // åå§ååæ°æ®æ°ç» |
| | | tableData.value.forEach(item => { |
| | | item.children = []; |
| | | }); |
| | | total.value = res.data.total; |
| | | expandedRowKeys.value = []; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | const productSelected = selectedRows => { |
| | | productSelectedRows.value = selectedRows; |
| | | }; |
| | | const expandedRowKeys = ref([]); |
| | | // å±å¼è¡ |
| | | const expandChange = async (row, expandedRows) => { |
| | | if (expandedRows.length > 0) { |
| | | expandedRowKeys.value = []; |
| | | try { |
| | | const res = await productList({ salesLedgerId: row.id, type: 2 }); |
| | | const index = tableData.value.findIndex(item => item.id === row.id); |
| | | if (index > -1) { |
| | | tableData.value[index].children = res.data || []; |
| | | expandedRowKeys.value.push(row.id); |
| | | } |
| | | } catch (error) { |
| | | console.error("å 载产åå表失败:", error); |
| | | proxy.$modal.msgError("å 载产åå表失败"); |
| | | // å±å¼å¤±è´¥æ¶ï¼ç§»é¤å±å¼ç¶æ |
| | | const index = expandedRows.findIndex(item => item.id === row.id); |
| | | if (index > -1) { |
| | | expandedRows.splice(index, 1); |
| | | } |
| | | } |
| | | } else { |
| | | expandedRowKeys.value = []; |
| | | } |
| | | }; |
| | | // 主表åè®¡æ¹æ³ |
| | | const summarizeMainTable = param => { |
| | | return proxy.summarizeTable(param, ["contractAmount"]); |
| | | }; |
| | | // å表åè®¡æ¹æ³ |
| | | const summarizeProTable = param => { |
| | | return proxy.summarizeTable(param, [ |
| | | } catch (error) { |
| | | console.error("ä¿å模æ¿å¤±è´¥:", error); |
| | | ElMessage({ |
| | | message: "模æ¿ä¿å失败ï¼è¯·ç¨åéè¯", |
| | | type: "error", |
| | | }); |
| | | } |
| | | }; |
| | | // å表åè®¡æ¹æ³ |
| | | const summarizeChildrenTable = param => { |
| | | return proxy.summarizeTable( |
| | | param, |
| | | [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | "ticketsNum", |
| | | "ticketsAmount", |
| | | "futureTickets", |
| | | "futureTicketsAmount", |
| | | ], |
| | | { |
| | | ticketsNum: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | futureTickets: { noDecimal: true }, // ä¸ä¿çå°æ° |
| | | } |
| | | ); |
| | | }; |
| | | const paginationChange = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const { entryDate, ...rest } = searchForm; |
| | | purchaseListPage({ ...rest, ...page }) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | // tableData.value = res.data.records; |
| | | tableData.value = res.data.records.map(record => ({ |
| | | ...record, |
| | | })); |
| | | // åå§ååæ°æ®æ°ç» |
| | | tableData.value.forEach(item => { |
| | | item.children = []; |
| | | }); |
| | | total.value = res.data.total; |
| | | expandedRowKeys.value = []; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | const productSelected = selectedRows => { |
| | | productSelectedRows.value = selectedRows; |
| | | }; |
| | | const expandedRowKeys = ref([]); |
| | | // å±å¼è¡ |
| | | const expandChange = async (row, expandedRows) => { |
| | | if (expandedRows.length > 0) { |
| | | expandedRowKeys.value = []; |
| | | try { |
| | | const res = await productList({ salesLedgerId: row.id, type: 2 }); |
| | | const index = tableData.value.findIndex(item => item.id === row.id); |
| | | if (index > -1) { |
| | | tableData.value[index].children = res.data || []; |
| | | expandedRowKeys.value.push(row.id); |
| | | } |
| | | } catch (error) { |
| | | console.error("å 载产åå表失败:", error); |
| | | proxy.$modal.msgError("å 载产åå表失败"); |
| | | // å±å¼å¤±è´¥æ¶ï¼ç§»é¤å±å¼ç¶æ |
| | | const index = expandedRows.findIndex(item => item.id === row.id); |
| | | if (index > -1) { |
| | | expandedRows.splice(index, 1); |
| | | } |
| | | } |
| | | } else { |
| | | expandedRowKeys.value = []; |
| | | } |
| | | }; |
| | | // 主表åè®¡æ¹æ³ |
| | | const summarizeMainTable = param => { |
| | | return proxy.summarizeTable(param, ["contractAmount"]); |
| | | }; |
| | | // å表åè®¡æ¹æ³ |
| | | const summarizeProTable = param => { |
| | | return proxy.summarizeTable(param, [ |
| | | "taxInclusiveUnitPrice", |
| | | "taxInclusiveTotalPrice", |
| | | "taxExclusiveTotalPrice", |
| | | ]); |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = async (type, row) => { |
| | | if (type === 'detail') { |
| | | detailRef.value.open(row.id); |
| | | return; |
| | | } |
| | | // ç¼è¾æ¶æ£æ¥å
¥åºç¶æï¼å®å
¨å
¥åºæ¶ä¸è½ç¼è¾ |
| | | if (type === "edit" && row) { |
| | | if (row.stockInStatus === 'å®å
¨å
¥åº') { |
| | | proxy.$modal.msgWarning("å®å
¨å
¥åºç¶æçè®°å½ä¸è½ç¼è¾"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | await getTemplateList(); |
| | | await userListNoPage().then(res => { |
| | | userList.value = res.data; |
| | | }); |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | productData.value = []; |
| | | fileList.value = []; |
| | | templateName.value = ""; |
| | | filterInputValue.value = ""; |
| | | isTemplateNameDuplicate.value = false; |
| | | try { |
| | | // å¹¶è¡å è½½åºç¡æ°æ® |
| | | const [salesRes, supplierRes] = await Promise.all([ |
| | | getSalesNo(), |
| | | getOptions(), |
| | | ]); |
| | | }; |
| | | // æå¼å¼¹æ¡ |
| | | const openForm = async (type, row) => { |
| | | // ç¼è¾æ¶æ£æ¥å
¥åºç¶æï¼å®å
¨å
¥åºæ¶ä¸è½ç¼è¾ |
| | | if (type === "edit" && row) { |
| | | if (row.stockInStatus === 'å®å
¨å
¥åº') { |
| | | proxy.$modal.msgWarning("å®å
¨å
¥åºç¶æçè®°å½ä¸è½ç¼è¾"); |
| | | |
| | | salesContractList.value = salesRes || []; |
| | | // ä¾åºåè¿æ»¤åºisWhite=0 çæ°æ® |
| | | supplierList.value = (supplierRes.data || []).filter( |
| | | item => item.isWhite === 0 |
| | | ); |
| | | |
| | | form.value.entryDate = getCurrentDate(); |
| | | |
| | | if (type === "add") { |
| | | // æ°å¢æ¶çæéè´ååå· |
| | | try { |
| | | const purchaseNoRes = await createPurchaseNo(); |
| | | if (purchaseNoRes?.data) { |
| | | form.value.purchaseContractNumber = purchaseNoRes.data; |
| | | } |
| | | } catch (error) { |
| | | console.error("çæéè´ååå·å¤±è´¥:", error); |
| | | proxy.$modal.msgWarning("çæéè´ååå·å¤±è´¥"); |
| | | } |
| | | } else if (type === "edit" && row?.id) { |
| | | // ç¼è¾æ¶å è½½æ°æ® |
| | | currentId.value = row.id; |
| | | try { |
| | | const purchaseRes = await getPurchaseById({ id: row.id, type: 2 }); |
| | | form.value = { ...purchaseRes, stockInStatus: row.stockInStatus }; |
| | | fileList.value = purchaseRes.storageBlobVOS || []; |
| | | // ä½¿ç¨ productList æ¥å£è·å产åå表ï¼ä»¥è·åå
¥åºå®¡æ ¸ç¶æ |
| | | const productRes = await productList({ salesLedgerId: row.id, type: 2 }); |
| | | productData.value = productRes.data || []; |
| | | } catch (error) { |
| | | console.error("å è½½éè´å°è´¦æ°æ®å¤±è´¥:", error); |
| | | proxy.$modal.msgError("å è½½æ°æ®å¤±è´¥"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | await getTemplateList(); |
| | | await userListNoPage().then(res => { |
| | | userList.value = res.data; |
| | | }); |
| | | operationType.value = type; |
| | | form.value = {}; |
| | | productData.value = []; |
| | | fileList.value = []; |
| | | templateName.value = ""; |
| | | filterInputValue.value = ""; |
| | | isTemplateNameDuplicate.value = false; |
| | | if (form.value.salesLedgerId == -1) { |
| | | form.value.salesLedgerId = null; |
| | | } |
| | | dialogFormVisible.value = true; |
| | | } catch (error) { |
| | | console.error("æå¼è¡¨å失败:", error); |
| | | proxy.$modal.msgError("å è½½åºç¡æ°æ®å¤±è´¥"); |
| | | } |
| | | }; |
| | | |
| | | // ä¸ä¼ åæ ¡æ£ |
| | | function handleBeforeUpload(file) { |
| | | // æ ¡æ£æä»¶å¤§å° |
| | | if (file.size > 1024 * 1024 * 10) { |
| | | proxy.$modal.msgError("ä¸ä¼ æä»¶å¤§å°ä¸è½è¶
è¿10MB!"); |
| | | return false; |
| | | } |
| | | proxy.$modal.loading("æ£å¨ä¸ä¼ æä»¶ï¼è¯·ç¨å..."); |
| | | return true; |
| | | } |
| | | |
| | | // ä¸ä¼ 失败 |
| | | function handleUploadError(err) { |
| | | proxy.$modal.msgError("ä¸ä¼ æä»¶å¤±è´¥"); |
| | | proxy.$modal.closeLoading(); |
| | | } |
| | | |
| | | // ä¸ä¼ æååè° |
| | | function handleUploadSuccess(res, file, uploadFiles) { |
| | | proxy.$modal.closeLoading(); |
| | | if (res.code === 200) { |
| | | file.tempId = res.data.tempId; |
| | | proxy.$modal.msgSuccess("ä¸ä¼ æå"); |
| | | } else { |
| | | proxy.$modal.msgError(res.msg); |
| | | proxy.$refs.fileUpload.handleRemove(file); |
| | | } |
| | | } |
| | | |
| | | // ç§»é¤æä»¶ |
| | | async function handleRemove(file) { |
| | | if (!file?.id) { |
| | | return; |
| | | } |
| | | console.log("handleRemove", file.id); |
| | | if (file.size > 1024 * 1024 * 10) { |
| | | // ä»
å端æ¸
çï¼ä¸è°ç¨å 餿¥å£åæç¤º |
| | | return; |
| | | } |
| | | |
| | | if (operationType.value === "edit" && file.id) { |
| | | try { |
| | | // å¹¶è¡å è½½åºç¡æ°æ® |
| | | const [salesRes, supplierRes] = await Promise.all([ |
| | | getSalesNo(), |
| | | getOptions(), |
| | | ]); |
| | | |
| | | salesContractList.value = salesRes || []; |
| | | // ä¾åºåè¿æ»¤åºisWhite=0 çæ°æ® |
| | | supplierList.value = (supplierRes.data || []).filter( |
| | | item => item.isWhite === 0 |
| | | ); |
| | | |
| | | form.value.entryDate = getCurrentDate(); |
| | | |
| | | if (type === "add") { |
| | | // æ°å¢æ¶çæéè´ååå· |
| | | try { |
| | | const purchaseNoRes = await createPurchaseNo(); |
| | | if (purchaseNoRes?.data) { |
| | | form.value.purchaseContractNumber = purchaseNoRes.data; |
| | | } |
| | | } catch (error) { |
| | | console.error("çæéè´ååå·å¤±è´¥:", error); |
| | | proxy.$modal.msgWarning("çæéè´ååå·å¤±è´¥"); |
| | | } |
| | | } else if (type === "edit" && row?.id) { |
| | | // ç¼è¾æ¶å è½½æ°æ® |
| | | currentId.value = row.id; |
| | | try { |
| | | const purchaseRes = await getPurchaseById({ id: row.id, type: 2 }); |
| | | form.value = { ...purchaseRes, stockInStatus: row.stockInStatus }; |
| | | fileList.value = purchaseRes.storageBlobVOS || []; |
| | | // ä½¿ç¨ productList æ¥å£è·å产åå表ï¼ä»¥è·åå
¥åºå®¡æ ¸ç¶æ |
| | | const productRes = await productList({ salesLedgerId: row.id, type: 2 }); |
| | | productData.value = productRes.data || []; |
| | | } catch (error) { |
| | | console.error("å è½½éè´å°è´¦æ°æ®å¤±è´¥:", error); |
| | | proxy.$modal.msgError("å è½½æ°æ®å¤±è´¥"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | if (form.value.salesLedgerId == -1) { |
| | | form.value.salesLedgerId = null; |
| | | } |
| | | console.log(form.value, "form.value==========="); |
| | | dialogFormVisible.value = true; |
| | | await delLedgerFile([file.id]); |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | } catch (error) { |
| | | console.error("æå¼è¡¨å失败:", error); |
| | | proxy.$modal.msgError("å è½½åºç¡æ°æ®å¤±è´¥"); |
| | | } |
| | | }; |
| | | |
| | | // ä¸ä¼ åæ ¡æ£ |
| | | function handleBeforeUpload(file) { |
| | | // æ ¡æ£æä»¶å¤§å° |
| | | if (file.size > 1024 * 1024 * 10) { |
| | | proxy.$modal.msgError("ä¸ä¼ æä»¶å¤§å°ä¸è½è¶
è¿10MB!"); |
| | | return false; |
| | | } |
| | | proxy.$modal.loading("æ£å¨ä¸ä¼ æä»¶ï¼è¯·ç¨å..."); |
| | | return true; |
| | | } |
| | | |
| | | // ä¸ä¼ 失败 |
| | | function handleUploadError(err) { |
| | | proxy.$modal.msgError("ä¸ä¼ æä»¶å¤±è´¥"); |
| | | proxy.$modal.closeLoading(); |
| | | } |
| | | |
| | | // ä¸ä¼ æååè° |
| | | function handleUploadSuccess(res, file, uploadFiles) { |
| | | proxy.$modal.closeLoading(); |
| | | if (res.code === 200) { |
| | | file.tempId = res.data.tempId; |
| | | proxy.$modal.msgSuccess("ä¸ä¼ æå"); |
| | | } else { |
| | | proxy.$modal.msgError(res.msg); |
| | | proxy.$refs.fileUpload.handleRemove(file); |
| | | console.error("å é¤æä»¶å¤±è´¥:", error); |
| | | proxy.$modal.msgError("å é¤æä»¶å¤±è´¥"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // ç§»é¤æä»¶ |
| | | async function handleRemove(file) { |
| | | if (!file?.id) { |
| | | return; |
| | | } |
| | | console.log("handleRemove", file.id); |
| | | if (file.size > 1024 * 1024 * 10) { |
| | | // ä»
å端æ¸
çï¼ä¸è°ç¨å 餿¥å£åæç¤º |
| | | return; |
| | | } |
| | | |
| | | if (operationType.value === "edit" && file.id) { |
| | | try { |
| | | await delLedgerFile([file.id]); |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | } catch (error) { |
| | | console.error("å é¤æä»¶å¤±è´¥:", error); |
| | | proxy.$modal.msgError("å é¤æä»¶å¤±è´¥"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | if (productData.value.length > 0) { |
| | | // æ°å¢æ¶ï¼éè¦ä»æ¯ä¸ªäº§å对象ä¸å é¤ id åæ®µ |
| | | let processedProductData = productData.value; |
| | | if (operationType.value === "add") { |
| | | processedProductData = productData.value.map(product => { |
| | | const { id, ...rest } = product; |
| | | return rest; |
| | | }); |
| | | } |
| | | form.value.productData = proxy.HaveJson(processedProductData); |
| | | } else { |
| | | proxy.$modal.msgWarning("请添å 产åä¿¡æ¯"); |
| | | return; |
| | | } |
| | | form.value.storageBlobDTOS = fileList.value; |
| | | form.value.type = 2; |
| | | |
| | | // 妿salesLedgerId为空ï¼åä¸ä¼ ésalesContractNo |
| | | if (!form.value.salesLedgerId) { |
| | | form.value.salesContractNo = ""; |
| | | } |
| | | |
| | | // æ°å¢æ¶ä¸ä¼ éid |
| | | const submitData = { ...form.value }; |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | | if (valid) { |
| | | if (productData.value.length > 0) { |
| | | // æ°å¢æ¶ï¼éè¦ä»æ¯ä¸ªäº§å对象ä¸å é¤ id åæ®µ |
| | | let processedProductData = productData.value; |
| | | if (operationType.value === "add") { |
| | | delete submitData.id; |
| | | processedProductData = productData.value.map(product => { |
| | | const { id, ...rest } = product; |
| | | return rest; |
| | | }); |
| | | } |
| | | |
| | | addOrEditPurchase(submitData).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | form.value.productData = proxy.HaveJson(processedProductData); |
| | | } else { |
| | | proxy.$modal.msgWarning("请添å 产åä¿¡æ¯"); |
| | | return; |
| | | } |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // æå¼äº§åå¼¹æ¡ |
| | | const openProductForm = async (type, row, index) => { |
| | | // ç¼è¾æ¶æ£æ¥äº§åå
¥åºå®¡æ ¸ç¶æï¼å®å
¨å
¥åºæ¶ä¸è½ç¼è¾ |
| | | if (type === "edit" && row && row.stockInApprovalStatus === 'å®å
¨å
¥åº') { |
| | | proxy.$modal.msgWarning("å®å
¨å
¥åºç¶æç产åä¸è½ç¼è¾"); |
| | | return; |
| | | form.value.storageBlobDTOS = fileList.value; |
| | | form.value.type = 2; |
| | | |
| | | // 妿salesLedgerId为空ï¼åä¸ä¼ ésalesContractNo |
| | | if (!form.value.salesLedgerId) { |
| | | form.value.salesContractNo = ""; |
| | | } |
| | | |
| | | // æ°å¢æ¶ä¸ä¼ éid |
| | | const submitData = { ...form.value }; |
| | | if (operationType.value === "add") { |
| | | delete submitData.id; |
| | | } |
| | | |
| | | addOrEditPurchase(submitData).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeDia(); |
| | | getList(); |
| | | }); |
| | | } |
| | | }); |
| | | }; |
| | | // å
³éå¼¹æ¡ |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | }; |
| | | // æå¼äº§åå¼¹æ¡ |
| | | const openProductForm = async (type, row, index) => { |
| | | // ç¼è¾æ¶æ£æ¥äº§åå
¥åºå®¡æ ¸ç¶æï¼å®å
¨å
¥åºæ¶ä¸è½ç¼è¾ |
| | | if (type === "edit" && row && row.stockInApprovalStatus === 'å®å
¨å
¥åº') { |
| | | proxy.$modal.msgWarning("å®å
¨å
¥åºç¶æç产åä¸è½ç¼è¾"); |
| | | return; |
| | | } |
| | | |
| | | productOperationType.value = type; |
| | | productOperationIndex.value = index; |
| | | productForm.value = {}; |
| | | proxy.resetForm("productFormRef"); |
| | | productFormVisible.value = true; |
| | | productOperationType.value = type; |
| | | productOperationIndex.value = index; |
| | | productForm.value = {}; |
| | | proxy.resetForm("productFormRef"); |
| | | productFormVisible.value = true; |
| | | |
| | | // å
è·å产åé项ï¼ç¡®ä¿æ°æ®å è½½å®æ |
| | | await getProductOptions(); |
| | | // å
è·å产åé项ï¼ç¡®ä¿æ°æ®å è½½å®æ |
| | | await getProductOptions(); |
| | | |
| | | // çå¾
DOM æ´æ° |
| | | await nextTick(); |
| | | // çå¾
DOM æ´æ° |
| | | await nextTick(); |
| | | |
| | | if (type === "add") { |
| | | productForm.value.isChecked = false; |
| | | } |
| | | if (type === "add") { |
| | | productForm.value.isChecked = false; |
| | | } |
| | | |
| | | if (type === "edit") { |
| | | // å¤å¶è¡æ°æ® |
| | | productForm.value = { ...row }; |
| | | if (type === "edit") { |
| | | // å¤å¶è¡æ°æ® |
| | | productForm.value = { ...row }; |
| | | |
| | | // 妿æ¯ä»æ¨¡æ¿å è½½çæ°æ®ï¼å¯è½æ²¡æ productId å productModelId |
| | | // éè¦æ ¹æ® productCategory å specificationModel æ¥æ¥æ¾å¯¹åºç ID |
| | | if (!productForm.value.productId && productForm.value.productCategory) { |
| | | // æ ¹æ® productCategory æ¥æ¾ productId |
| | | const findProductIdByCategory = (nodes, categoryName) => { |
| | | for (let i = 0; i < nodes.length; i++) { |
| | | if (nodes[i].label === categoryName) { |
| | | return nodes[i].value; |
| | | } |
| | | if (nodes[i].children && nodes[i].children.length > 0) { |
| | | const found = findProductIdByCategory( |
| | | nodes[i].children, |
| | | categoryName |
| | | ); |
| | | if (found) return found; |
| | | } |
| | | // 妿æ¯ä»æ¨¡æ¿å è½½çæ°æ®ï¼å¯è½æ²¡æ productId å productModelId |
| | | // éè¦æ ¹æ® productCategory å specificationModel æ¥æ¥æ¾å¯¹åºç ID |
| | | if (!productForm.value.productId && productForm.value.productCategory) { |
| | | // æ ¹æ® productCategory æ¥æ¾ productId |
| | | const findProductIdByCategory = (nodes, categoryName) => { |
| | | for (let i = 0; i < nodes.length; i++) { |
| | | if (nodes[i].label === categoryName) { |
| | | return nodes[i].value; |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const productId = findProductIdByCategory( |
| | | productOptions.value, |
| | | productForm.value.productCategory |
| | | ); |
| | | if (productId) { |
| | | productForm.value.productId = productId; |
| | | // è·ååå·å表并çå¾
宿 |
| | | const modelRes = await modelList({ id: productId }); |
| | | modelOptions.value = modelRes; |
| | | |
| | | // çå¾
DOM æ´æ° |
| | | await nextTick(); |
| | | |
| | | // æ ¹æ® specificationModel æ¥æ¾ productModelId |
| | | if ( |
| | | productForm.value.specificationModel && |
| | | modelOptions.value.length > 0 |
| | | ) { |
| | | const modelItem = modelOptions.value.find( |
| | | item => item.model === productForm.value.specificationModel |
| | | if (nodes[i].children && nodes[i].children.length > 0) { |
| | | const found = findProductIdByCategory( |
| | | nodes[i].children, |
| | | categoryName |
| | | ); |
| | | if (modelItem) { |
| | | productForm.value.productModelId = modelItem.id; |
| | | // è®¾ç½®è§æ ¼åå·ååä½ |
| | | getProductModel(modelItem.id); |
| | | } |
| | | if (found) return found; |
| | | } |
| | | } |
| | | } else if (productForm.value.productId) { |
| | | // 妿æ productIdï¼æ£å¸¸å è½½åå·å表 |
| | | await getModels(productForm.value.productId); |
| | | return null; |
| | | }; |
| | | |
| | | const productId = findProductIdByCategory( |
| | | productOptions.value, |
| | | productForm.value.productCategory |
| | | ); |
| | | if (productId) { |
| | | productForm.value.productId = productId; |
| | | // è·ååå·å表并çå¾
宿 |
| | | const modelRes = await modelList({ id: productId }); |
| | | modelOptions.value = modelRes; |
| | | |
| | | // çå¾
DOM æ´æ° |
| | | await nextTick(); |
| | | |
| | | if (productForm.value.productModelId) { |
| | | getProductModel(productForm.value.productModelId); |
| | | // æ ¹æ® specificationModel æ¥æ¾ productModelId |
| | | if ( |
| | | productForm.value.specificationModel && |
| | | modelOptions.value.length > 0 |
| | | ) { |
| | | const modelItem = modelOptions.value.find( |
| | | item => item.model === productForm.value.specificationModel |
| | | ); |
| | | if (modelItem) { |
| | | productForm.value.productModelId = modelItem.id; |
| | | // è®¾ç½®è§æ ¼åå·ååä½ |
| | | getProductModel(modelItem.id); |
| | | } |
| | | } |
| | | } |
| | | } else if (productForm.value.productId) { |
| | | // 妿æ productIdï¼æ£å¸¸å è½½åå·å表 |
| | | await getModels(productForm.value.productId); |
| | | |
| | | // æååçå¾
䏿¬¡ DOM æ´æ°ï¼ç¡®ä¿æææ°æ®é½å·²è®¾ç½® |
| | | // çå¾
DOM æ´æ° |
| | | await nextTick(); |
| | | |
| | | if (productForm.value.productModelId) { |
| | | getProductModel(productForm.value.productModelId); |
| | | } |
| | | } |
| | | }; |
| | | const getProductOptions = () => { |
| | | return productTreeList().then(res => { |
| | | productOptions.value = convertIdToValue(res); |
| | | |
| | | // æååçå¾
䏿¬¡ DOM æ´æ°ï¼ç¡®ä¿æææ°æ®é½å·²è®¾ç½® |
| | | await nextTick(); |
| | | } |
| | | }; |
| | | const getProductOptions = () => { |
| | | return productTreeList().then(res => { |
| | | productOptions.value = convertIdToValue(res); |
| | | return res; |
| | | }); |
| | | }; |
| | | const getModels = value => { |
| | | if (value) { |
| | | productForm.value.productCategory = |
| | | findNodeById(productOptions.value, value) || ""; |
| | | return modelList({ id: value }).then(res => { |
| | | modelOptions.value = res; |
| | | return res; |
| | | }); |
| | | }; |
| | | const getModels = value => { |
| | | if (value) { |
| | | productForm.value.productCategory = |
| | | findNodeById(productOptions.value, value) || ""; |
| | | return modelList({ id: value }).then(res => { |
| | | modelOptions.value = res; |
| | | return res; |
| | | }); |
| | | } else { |
| | | productForm.value.productCategory = ""; |
| | | modelOptions.value = []; |
| | | return Promise.resolve([]); |
| | | } else { |
| | | productForm.value.productCategory = ""; |
| | | modelOptions.value = []; |
| | | return Promise.resolve([]); |
| | | } |
| | | }; |
| | | const getProductModel = value => { |
| | | const index = modelOptions.value.findIndex(item => item.id === value); |
| | | if (index !== -1) { |
| | | productForm.value.specificationModel = modelOptions.value[index].model; |
| | | productForm.value.unit = modelOptions.value[index].unit; |
| | | } else { |
| | | productForm.value.specificationModel = null; |
| | | productForm.value.unit = null; |
| | | } |
| | | }; |
| | | const findNodeById = (nodes, productId) => { |
| | | for (let i = 0; i < nodes.length; i++) { |
| | | if (nodes[i].value === productId) { |
| | | return nodes[i].label; // æ¾å°èç¹ï¼è¿å该èç¹çlabel |
| | | } |
| | | }; |
| | | const getProductModel = value => { |
| | | const index = modelOptions.value.findIndex(item => item.id === value); |
| | | if (index !== -1) { |
| | | productForm.value.specificationModel = modelOptions.value[index].model; |
| | | productForm.value.unit = modelOptions.value[index].unit; |
| | | } else { |
| | | productForm.value.specificationModel = null; |
| | | productForm.value.unit = null; |
| | | } |
| | | }; |
| | | const findNodeById = (nodes, productId) => { |
| | | for (let i = 0; i < nodes.length; i++) { |
| | | if (nodes[i].value === productId) { |
| | | return nodes[i].label; // æ¾å°èç¹ï¼è¿å该èç¹çlabel |
| | | if (nodes[i].children && nodes[i].children.length > 0) { |
| | | const foundNode = findNodeById(nodes[i].children, productId); |
| | | if (foundNode) { |
| | | return foundNode; // å¨åèç¹ä¸æ¾å°ï¼ç´æ¥è¿åï¼å·²ç»æ¯labelåç¬¦ä¸²ï¼ |
| | | } |
| | | if (nodes[i].children && nodes[i].children.length > 0) { |
| | | const foundNode = findNodeById(nodes[i].children, productId); |
| | | if (foundNode) { |
| | | return foundNode; // å¨åèç¹ä¸æ¾å°ï¼ç´æ¥è¿åï¼å·²ç»æ¯labelåç¬¦ä¸²ï¼ |
| | | } |
| | | } |
| | | return null; // æ²¡ææ¾å°èç¹ï¼è¿ånull |
| | | }; |
| | | |
| | | function convertIdToValue(data) { |
| | | return data.map(item => { |
| | | const { id, children, ...rest } = item; |
| | | const newItem = { |
| | | ...rest, |
| | | value: id, // å° id æ¹ä¸º value |
| | | }; |
| | | if (children && children.length > 0) { |
| | | newItem.children = convertIdToValue(children); |
| | | } |
| | | |
| | | return newItem; |
| | | }); |
| | | } |
| | | |
| | | // æäº¤äº§å表å |
| | | const submitProduct = () => { |
| | | proxy.$refs["productFormRef"].validate(valid => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| | | submitProductEdit(); |
| | | } else { |
| | | if (productOperationType.value === "add") { |
| | | productData.value.push({ ...productForm.value }); |
| | | console.log("productData.value---", productData.value); |
| | | } else { |
| | | productData.value[productOperationIndex.value] = { |
| | | ...productForm.value, |
| | | }; |
| | | } |
| | | closeProductDia(); |
| | | } |
| | | } |
| | | return null; // æ²¡ææ¾å°èç¹ï¼è¿ånull |
| | | }; |
| | | |
| | | function convertIdToValue(data) { |
| | | return data.map(item => { |
| | | const { id, children, ...rest } = item; |
| | | const newItem = { |
| | | ...rest, |
| | | value: id, // å° id æ¹ä¸º value |
| | | }; |
| | | if (children && children.length > 0) { |
| | | newItem.children = convertIdToValue(children); |
| | | } |
| | | |
| | | return newItem; |
| | | }); |
| | | }; |
| | | const submitProductEdit = () => { |
| | | productForm.value.salesLedgerId = currentId.value; |
| | | productForm.value.type = 2; |
| | | addOrUpdateSalesLedgerProduct(productForm.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeProductDia(); |
| | | // ä½¿ç¨ productList æ¥å£å·æ°äº§åå表ï¼ä»¥è·åå
¥åºå®¡æ ¸ç¶æ |
| | | productList({ salesLedgerId: currentId.value, type: 2 }).then(res => { |
| | | productData.value = res.data || []; |
| | | }); |
| | | }); |
| | | }; |
| | | // å é¤äº§å |
| | | const deleteProduct = () => { |
| | | if (productSelectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | // æ£æ¥éä¸ç产å䏿¯å¦æå®å
¨å
¥åºç |
| | | const hasFullyStocked = productSelectedRows.value.some( |
| | | row => row.stockInApprovalStatus === 'å®å
¨å
¥åº' |
| | | ); |
| | | if (hasFullyStocked) { |
| | | proxy.$modal.msgWarning("éä¸ç产åä¸å
å«å®å
¨å
¥åºç产åï¼æ æ³å é¤"); |
| | | return; |
| | | } |
| | | if (operationType.value === "add") { |
| | | productData.value = productData.value.filter( |
| | | item => !productSelectedRows.value.includes(item) |
| | | ); |
| | | productSelectedRows.value = []; |
| | | } else { |
| | | let ids = []; |
| | | if (productSelectedRows.value.length > 0) { |
| | | ids = productSelectedRows.value.map(item => item.id); |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delProduct(ids).then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | closeProductDia(); |
| | | // ä½¿ç¨ productList æ¥å£å·æ°äº§åå表ï¼ä»¥è·åå
¥åºå®¡æ ¸ç¶æ |
| | | productList({ salesLedgerId: currentId.value, type: 2 }).then(res => { |
| | | productData.value = res.data || []; |
| | | }); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | } |
| | | }; |
| | | // å
³é产åå¼¹æ¡ |
| | | const closeProductDia = () => { |
| | | proxy.resetForm("productFormRef"); |
| | | productFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/purchase/ledger/export", {}, "éè´å°è´¦.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value |
| | | .filter(item => item.salesLedgerId === null) |
| | | .map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delPurchase(ids).then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | |
| | | const mathNum = () => { |
| | | if (!productForm.value.taxRate) { |
| | | proxy.$modal.msgWarning("请å
éæ©ç¨ç"); |
| | | return; |
| | | } |
| | | if (!productForm.value.taxInclusiveUnitPrice) { |
| | | return; |
| | | } |
| | | if (!productForm.value.quantity) { |
| | | return; |
| | | } |
| | | // å«ç¨æ»ä»·è®¡ç® |
| | | productForm.value.taxInclusiveTotalPrice = |
| | | proxy.calculateTaxIncludeTotalPrice( |
| | | productForm.value.taxInclusiveUnitPrice, |
| | | productForm.value.quantity |
| | | ); |
| | | if (productForm.value.taxRate) { |
| | | // ä¸å«ç¨æ»ä»·è®¡ç® |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | proxy.calculateTaxExclusiveTotalPrice( |
| | | productForm.value.taxInclusiveTotalPrice, |
| | | productForm.value.taxRate |
| | | ); |
| | | } |
| | | }; |
| | | const reverseMathNum = field => { |
| | | if (!productForm.value.taxRate) { |
| | | proxy.$modal.msgWarning("请å
éæ©ç¨ç"); |
| | | return; |
| | | } |
| | | const taxRate = Number(productForm.value.taxRate); |
| | | if (!taxRate) return; |
| | | |
| | | // ç¡®ä¿è¾å
¥å¼ä¸ä¸ºè´æ° |
| | | if ( |
| | | field === "taxInclusiveTotalPrice" || |
| | | field === "taxExclusiveTotalPrice" |
| | | ) { |
| | | const value = Number(productForm.value[field]); |
| | | if (value < 0) { |
| | | productForm.value[field] = "0"; |
| | | proxy.$modal.msgWarning("å¼ä¸è½å°äº0"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // æäº¤äº§å表å |
| | | const submitProduct = () => { |
| | | proxy.$refs["productFormRef"].validate(valid => { |
| | | if (valid) { |
| | | if (operationType.value === "edit") { |
| | | submitProductEdit(); |
| | | } else { |
| | | if (productOperationType.value === "add") { |
| | | productData.value.push({ ...productForm.value }); |
| | | console.log("productData.value---", productData.value); |
| | | } else { |
| | | productData.value[productOperationIndex.value] = { |
| | | ...productForm.value, |
| | | }; |
| | | } |
| | | closeProductDia(); |
| | | } |
| | | if (field === "taxInclusiveTotalPrice") { |
| | | // å·²ç¥å«ç¨æ»ä»·åæ°éï¼åç®å«ç¨åä»· |
| | | if (productForm.value.quantity) { |
| | | productForm.value.taxInclusiveUnitPrice = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.quantity) |
| | | ).toFixed(6); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.taxInclusiveUnitPrice) < 0) { |
| | | productForm.value.taxInclusiveUnitPrice = "0"; |
| | | } |
| | | }); |
| | | }; |
| | | const submitProductEdit = () => { |
| | | productForm.value.salesLedgerId = currentId.value; |
| | | productForm.value.type = 2; |
| | | addOrUpdateSalesLedgerProduct(productForm.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeProductDia(); |
| | | // ä½¿ç¨ productList æ¥å£å·æ°äº§åå表ï¼ä»¥è·åå
¥åºå®¡æ ¸ç¶æ |
| | | productList({ salesLedgerId: currentId.value, type: 2 }).then(res => { |
| | | productData.value = res.data || []; |
| | | }); |
| | | }); |
| | | }; |
| | | // å é¤äº§å |
| | | const deleteProduct = () => { |
| | | if (productSelectedRows.value.length === 0) { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | // æ£æ¥éä¸ç产å䏿¯å¦æå®å
¨å
¥åºç |
| | | const hasFullyStocked = productSelectedRows.value.some( |
| | | row => row.stockInApprovalStatus === 'å®å
¨å
¥åº' |
| | | ); |
| | | if (hasFullyStocked) { |
| | | proxy.$modal.msgWarning("éä¸ç产åä¸å
å«å®å
¨å
¥åºç产åï¼æ æ³å é¤"); |
| | | return; |
| | | } |
| | | if (operationType.value === "add") { |
| | | productSelectedRows.value.forEach(selectedRow => { |
| | | const index = productData.value.findIndex( |
| | | product => product.id === selectedRow.id |
| | | ); |
| | | if (index !== -1) { |
| | | productData.value.splice(index, 1); |
| | | } |
| | | }); |
| | | } else { |
| | | let ids = []; |
| | | if (productSelectedRows.value.length > 0) { |
| | | ids = productSelectedRows.value.map(item => item.id); |
| | | // å·²ç¥å«ç¨æ»ä»·åå«ç¨åä»·ï¼åç®æ°é |
| | | else if (productForm.value.taxInclusiveUnitPrice) { |
| | | productForm.value.quantity = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.taxInclusiveUnitPrice) |
| | | ).toFixed(2); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.quantity) < 0) { |
| | | productForm.value.quantity = "0"; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | } |
| | | // åç®ä¸å«ç¨æ»ä»· |
| | | productForm.value.taxExclusiveTotalPrice = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | (1 + taxRate / 100) |
| | | ).toFixed(2); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.taxExclusiveTotalPrice) < 0) { |
| | | productForm.value.taxExclusiveTotalPrice = "0"; |
| | | } |
| | | } else if (field === "taxExclusiveTotalPrice") { |
| | | // åç®å«ç¨æ»ä»· |
| | | productForm.value.taxInclusiveTotalPrice = ( |
| | | Number(productForm.value.taxExclusiveTotalPrice) * |
| | | (1 + taxRate / 100) |
| | | ).toFixed(2); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.taxInclusiveTotalPrice) < 0) { |
| | | productForm.value.taxInclusiveTotalPrice = "0"; |
| | | } |
| | | // å·²ç¥æ°éï¼åç®å«ç¨åä»· |
| | | if (productForm.value.quantity) { |
| | | productForm.value.taxInclusiveUnitPrice = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.quantity) |
| | | ).toFixed(6); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.taxInclusiveUnitPrice) < 0) { |
| | | productForm.value.taxInclusiveUnitPrice = "0"; |
| | | } |
| | | } |
| | | // å·²ç¥å«ç¨åä»·ï¼åç®æ°é |
| | | else if (productForm.value.taxInclusiveUnitPrice) { |
| | | productForm.value.quantity = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.taxInclusiveUnitPrice) |
| | | ).toFixed(2); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.quantity) < 0) { |
| | | productForm.value.quantity = "0"; |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | // éå®ååéæ©æ¹åæ¹æ³ |
| | | const salesLedgerChange = async row => { |
| | | var index = salesContractList.value.findIndex(item => item.id == row); |
| | | if (index > -1) { |
| | | await querygProductInfoByContractNo(); |
| | | } |
| | | }; |
| | | |
| | | const querygProductInfoByContractNo = async () => { |
| | | const { code, data } = await getProductInfoByContractNo({ |
| | | contractNo: form.value.salesLedgerId, |
| | | }); |
| | | if (code == 200) { |
| | | productData.value = data; |
| | | } |
| | | }; |
| | | |
| | | // è·å模æ¿ä¿¡æ¯ |
| | | const getTemplateList = async () => { |
| | | let res = await getPurchaseTemplateList(); |
| | | if (res && res.code === 200 && Array.isArray(res.data)) { |
| | | templateList.value = res.data; |
| | | } |
| | | }; |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | |
| | | // å 餿¨¡æ¿ |
| | | const handleDeleteTemplate = async item => { |
| | | if (!item.id) { |
| | | proxy.$modal.msgWarning("æ æ³å é¤è¯¥æ¨¡æ¿"); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | await ElMessageBox.confirm( |
| | | `ç¡®å®è¦å 餿¨¡æ¿"${item.templateName}"åï¼`, |
| | | "å é¤ç¡®è®¤", |
| | | { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delProduct(ids).then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | closeProductDia(); |
| | | // ä½¿ç¨ productList æ¥å£å·æ°äº§åå表ï¼ä»¥è·åå
¥åºå®¡æ ¸ç¶æ |
| | | productList({ salesLedgerId: currentId.value, type: 2 }).then(res => { |
| | | productData.value = res.data || []; |
| | | }); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | } |
| | | }; |
| | | // å
³é产åå¼¹æ¡ |
| | | const closeProductDia = () => { |
| | | proxy.resetForm("productFormRef"); |
| | | productFormVisible.value = false; |
| | | }; |
| | | // å¯¼åº |
| | | const handleOut = () => { |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å¯¼åºï¼æ¯å¦ç¡®è®¤å¯¼åºï¼", "导åº", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | proxy.download("/purchase/ledger/export", {}, "éè´å°è´¦.xlsx"); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | } |
| | | ); |
| | | |
| | | const res = await delPurchaseTemplate([item.id]); |
| | | if (res && res.code === 200) { |
| | | ElMessage({ |
| | | message: "å 餿å", |
| | | type: "success", |
| | | }); |
| | | }; |
| | | // å é¤ |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value |
| | | .filter(item => item.salesLedgerId === null) |
| | | .map(item => item.id); |
| | | // 妿å é¤çæ¯å½åéä¸ç模æ¿ï¼æ¸
ç©ºéæ© |
| | | if (templateName.value === item.templateName) { |
| | | templateName.value = ""; |
| | | filterInputValue.value = ""; |
| | | } |
| | | // éæ°è·å模æ¿å表 |
| | | await getTemplateList(); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm("éä¸çå
容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤", { |
| | | confirmButtonText: "确认", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | delPurchase(ids).then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => { |
| | | proxy.$modal.msg("已忶"); |
| | | ElMessage({ |
| | | message: res?.msg || "å é¤å¤±è´¥", |
| | | type: "error", |
| | | }); |
| | | }; |
| | | |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | | const year = today.getFullYear(); |
| | | const month = String(today.getMonth() + 1).padStart(2, "0"); // æä»½ä»0å¼å§ |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | } catch (error) { |
| | | if (error !== "cancel") { |
| | | console.error("å 餿¨¡æ¿å¤±è´¥:", error); |
| | | ElMessage({ |
| | | message: "å é¤å¤±è´¥ï¼è¯·ç¨åéè¯", |
| | | type: "error", |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | const mathNum = () => { |
| | | if (!productForm.value.taxRate) { |
| | | proxy.$modal.msgWarning("请å
éæ©ç¨ç"); |
| | | return; |
| | | } |
| | | if (!productForm.value.taxInclusiveUnitPrice) { |
| | | return; |
| | | } |
| | | if (!productForm.value.quantity) { |
| | | return; |
| | | } |
| | | // å«ç¨æ»ä»·è®¡ç® |
| | | productForm.value.taxInclusiveTotalPrice = |
| | | proxy.calculateTaxIncludeTotalPrice( |
| | | productForm.value.taxInclusiveUnitPrice, |
| | | productForm.value.quantity |
| | | ); |
| | | if (productForm.value.taxRate) { |
| | | // ä¸å«ç¨æ»ä»·è®¡ç® |
| | | productForm.value.taxExclusiveTotalPrice = |
| | | proxy.calculateTaxExclusiveTotalPrice( |
| | | productForm.value.taxInclusiveTotalPrice, |
| | | productForm.value.taxRate |
| | | ); |
| | | } |
| | | }; |
| | | const reverseMathNum = field => { |
| | | if (!productForm.value.taxRate) { |
| | | proxy.$modal.msgWarning("请å
éæ©ç¨ç"); |
| | | return; |
| | | } |
| | | const taxRate = Number(productForm.value.taxRate); |
| | | if (!taxRate) return; |
| | | |
| | | // ç¡®ä¿è¾å
¥å¼ä¸ä¸ºè´æ° |
| | | if ( |
| | | field === "taxInclusiveTotalPrice" || |
| | | field === "taxExclusiveTotalPrice" |
| | | ) { |
| | | const value = Number(productForm.value[field]); |
| | | if (value < 0) { |
| | | productForm.value[field] = "0"; |
| | | proxy.$modal.msgWarning("å¼ä¸è½å°äº0"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | if (field === "taxInclusiveTotalPrice") { |
| | | // å·²ç¥å«ç¨æ»ä»·åæ°éï¼åç®å«ç¨åä»· |
| | | if (productForm.value.quantity) { |
| | | productForm.value.taxInclusiveUnitPrice = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.quantity) |
| | | ).toFixed(2); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.taxInclusiveUnitPrice) < 0) { |
| | | productForm.value.taxInclusiveUnitPrice = "0"; |
| | | } |
| | | } |
| | | // å·²ç¥å«ç¨æ»ä»·åå«ç¨åä»·ï¼åç®æ°é |
| | | else if (productForm.value.taxInclusiveUnitPrice) { |
| | | productForm.value.quantity = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.taxInclusiveUnitPrice) |
| | | ).toFixed(2); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.quantity) < 0) { |
| | | productForm.value.quantity = "0"; |
| | | } |
| | | } |
| | | // åç®ä¸å«ç¨æ»ä»· |
| | | productForm.value.taxExclusiveTotalPrice = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | (1 + taxRate / 100) |
| | | ).toFixed(2); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.taxExclusiveTotalPrice) < 0) { |
| | | productForm.value.taxExclusiveTotalPrice = "0"; |
| | | } |
| | | } else if (field === "taxExclusiveTotalPrice") { |
| | | // åç®å«ç¨æ»ä»· |
| | | productForm.value.taxInclusiveTotalPrice = ( |
| | | Number(productForm.value.taxExclusiveTotalPrice) * |
| | | (1 + taxRate / 100) |
| | | ).toFixed(2); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.taxInclusiveTotalPrice) < 0) { |
| | | productForm.value.taxInclusiveTotalPrice = "0"; |
| | | } |
| | | // å·²ç¥æ°éï¼åç®å«ç¨åä»· |
| | | if (productForm.value.quantity) { |
| | | productForm.value.taxInclusiveUnitPrice = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.quantity) |
| | | ).toFixed(2); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.taxInclusiveUnitPrice) < 0) { |
| | | productForm.value.taxInclusiveUnitPrice = "0"; |
| | | } |
| | | } |
| | | // å·²ç¥å«ç¨åä»·ï¼åç®æ°é |
| | | else if (productForm.value.taxInclusiveUnitPrice) { |
| | | productForm.value.quantity = ( |
| | | Number(productForm.value.taxInclusiveTotalPrice) / |
| | | Number(productForm.value.taxInclusiveUnitPrice) |
| | | ).toFixed(2); |
| | | // ç¡®ä¿ç»æä¸ä¸ºè´æ° |
| | | if (Number(productForm.value.quantity) < 0) { |
| | | productForm.value.quantity = "0"; |
| | | } |
| | | } |
| | | } |
| | | }; |
| | | // éå®ååéæ©æ¹åæ¹æ³ |
| | | const salesLedgerChange = async row => { |
| | | console.log("row", row); |
| | | var index = salesContractList.value.findIndex(item => item.id == row); |
| | | console.log("index", index); |
| | | if (index > -1) { |
| | | await querygProductInfoByContractNo(); |
| | | } |
| | | }; |
| | | |
| | | const querygProductInfoByContractNo = async () => { |
| | | const { code, data } = await getProductInfoByContractNo({ |
| | | contractNo: form.value.salesLedgerId, |
| | | }); |
| | | if (code == 200) { |
| | | productData.value = data; |
| | | } |
| | | }; |
| | | |
| | | // è·å模æ¿ä¿¡æ¯ |
| | | const getTemplateList = async () => { |
| | | let res = await getPurchaseTemplateList(); |
| | | if (res && res.code === 200 && Array.isArray(res.data)) { |
| | | templateList.value = res.data; |
| | | } |
| | | }; |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async row => { |
| | | recordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | |
| | | // å 餿¨¡æ¿ |
| | | const handleDeleteTemplate = async item => { |
| | | if (!item.id) { |
| | | proxy.$modal.msgWarning("æ æ³å é¤è¯¥æ¨¡æ¿"); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | await ElMessageBox.confirm( |
| | | `ç¡®å®è¦å 餿¨¡æ¿"${item.templateName}"åï¼`, |
| | | "å é¤ç¡®è®¤", |
| | | { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | } |
| | | ); |
| | | |
| | | const res = await delPurchaseTemplate([item.id]); |
| | | if (res && res.code === 200) { |
| | | ElMessage({ |
| | | message: "å 餿å", |
| | | type: "success", |
| | | }); |
| | | // 妿å é¤çæ¯å½åéä¸ç模æ¿ï¼æ¸
ç©ºéæ© |
| | | if (templateName.value === item.templateName) { |
| | | templateName.value = ""; |
| | | filterInputValue.value = ""; |
| | | } |
| | | // éæ°è·å模æ¿å表 |
| | | await getTemplateList(); |
| | | } else { |
| | | ElMessage({ |
| | | message: res?.msg || "å é¤å¤±è´¥", |
| | | type: "error", |
| | | }); |
| | | } |
| | | } catch (error) { |
| | | if (error !== "cancel") { |
| | | console.error("å 餿¨¡æ¿å¤±è´¥:", error); |
| | | ElMessage({ |
| | | message: "å é¤å¤±è´¥ï¼è¯·ç¨åéè¯", |
| | | type: "error", |
| | | }); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | getTemplateList(); |
| | | }); |
| | | onMounted(() => { |
| | | getList(); |
| | | getTemplateList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .invalid-row { |
| | | opacity: 0.6; |
| | | background-color: #f5f7fa; |
| | | } |
| | | .invalid-row { |
| | | opacity: 0.6; |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | .el-row { |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | .el-row { |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .no-arrow-select { |
| | | --el-select-suffix-icon-color: transparent; /* éèé»è®¤ä¸æç®å¤´ */ |
| | | } |
| | | .no-arrow-select { |
| | | --el-select-suffix-icon-color: transparent; |
| | | /* éèé»è®¤ä¸æç®å¤´ */ |
| | | } |
| | | |
| | | .select-button-group { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | .readonly-text { |
| | | display: inline-block; |
| | | width: 100%; |
| | | padding: 0 15px; |
| | | height: 32px; |
| | | line-height: 32px; |
| | | background-color: var(--el-fill-color-light); |
| | | border-radius: var(--el-border-radius-base); |
| | | color: var(--el-text-color-regular); |
| | | font-size: var(--el-font-size-base); |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | // 审æ¹äººèç¹å®¹å¨æ ·å¼ |
| | | .approver-nodes-container { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 16px; |
| | | padding: 16px; |
| | | background-color: #f8f9fa; |
| | | border-radius: 4px; |
| | | border: 1px solid #e4e7ed; |
| | | } |
| | | .readonly-text-area { |
| | | width: 100%; |
| | | min-height: 52px; |
| | | padding: 5px 15px; |
| | | background-color: var(--el-fill-color-light); |
| | | border-radius: var(--el-border-radius-base); |
| | | color: var(--el-text-color-regular); |
| | | font-size: var(--el-font-size-base); |
| | | box-sizing: border-box; |
| | | white-space: pre-wrap; |
| | | word-break: break-all; |
| | | } |
| | | |
| | | .detail-file-list { |
| | | width: 100%; |
| | | padding: 10px 15px; |
| | | background-color: var(--el-fill-color-light); |
| | | border-radius: var(--el-border-radius-base); |
| | | } |
| | | |
| | | .detail-file-item { |
| | | line-height: 24px; |
| | | margin-bottom: 5px; |
| | | } |
| | | |
| | | .detail-file-item:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .select-button-group { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | // 审æ¹äººèç¹å®¹å¨æ ·å¼ |
| | | .approver-nodes-container { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 16px; |
| | | padding: 16px; |
| | | background-color: #f8f9fa; |
| | | border-radius: 4px; |
| | | border: 1px solid #e4e7ed; |
| | | } |
| | | |
| | | .approver-node-item { |
| | | flex: 0 0 calc(33.333% - 12px); |
| | | min-width: 200px; |
| | | padding: 12px; |
| | | background-color: #fff; |
| | | border-radius: 4px; |
| | | border: 1px solid #dcdfe6; |
| | | transition: all 0.3s; |
| | | |
| | | &:hover { |
| | | border-color: #409eff; |
| | | box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1); |
| | | } |
| | | } |
| | | |
| | | .approver-node-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .approver-node-label { |
| | | font-size: 13px; |
| | | font-weight: 500; |
| | | color: #606266; |
| | | } |
| | | |
| | | @media (max-width: 1200px) { |
| | | .approver-node-item { |
| | | flex: 0 0 calc(33.333% - 12px); |
| | | min-width: 200px; |
| | | padding: 12px; |
| | | background-color: #fff; |
| | | border-radius: 4px; |
| | | border: 1px solid #dcdfe6; |
| | | transition: all 0.3s; |
| | | |
| | | &:hover { |
| | | border-color: #409eff; |
| | | box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1); |
| | | } |
| | | flex: 0 0 calc(50% - 8px); |
| | | } |
| | | } |
| | | |
| | | .approver-node-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 8px; |
| | | @media (max-width: 768px) { |
| | | .approver-node-item { |
| | | flex: 0 0 100%; |
| | | } |
| | | } |
| | | |
| | | .approver-node-label { |
| | | font-size: 13px; |
| | | font-weight: 500; |
| | | color: #606266; |
| | | // å é¤å¾æ æ ·å¼ |
| | | .delete-icon { |
| | | transition: all 0.3s; |
| | | |
| | | &:hover { |
| | | color: #f56c6c !important; |
| | | transform: scale(1.2); |
| | | } |
| | | |
| | | @media (max-width: 1200px) { |
| | | .approver-node-item { |
| | | flex: 0 0 calc(50% - 8px); |
| | | } |
| | | } |
| | | |
| | | @media (max-width: 768px) { |
| | | .approver-node-item { |
| | | flex: 0 0 100%; |
| | | } |
| | | } |
| | | |
| | | // å é¤å¾æ æ ·å¼ |
| | | .delete-icon { |
| | | transition: all 0.3s; |
| | | |
| | | &:hover { |
| | | color: #f56c6c !important; |
| | | transform: scale(1.2); |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | |
| | | <el-dialog |
| | | v-model="isShow" |
| | | title="æ°å¢éè´éè´§" |
| | | width="1600" |
| | | width="70%" |
| | | top="3vh" |
| | | @close="closeModal" |
| | | class="purchase-return-dialog" |
| | | > |
| | | <el-form label-width="140px" :model="formState" label-position="top" ref="formRef" :inline="true"> |
| | | <div class="section-title"> |
| | |
| | | <el-input style="width: 240px" v-model="formState.remark" :rows="1" type="textarea" placeholder="请è¾å
¥å¤æ³¨"/> |
| | | </el-form-item> |
| | | |
| | | <div style="margin: 20px 0;"> |
| | | <div style="margin:20px 0;min-width:0;"> |
| | | <div class="section-title"> |
| | | <span class="title-dot"></span> |
| | | <span class="title-text">产åå表</span> |
| | | </div> |
| | | <el-button type="primary" size="small" style="margin-bottom: 20px" @click="isShowProductsModal = true" :disabled="!formState.purchaseLedgerId">æ·»å 产å</el-button> |
| | | <div class="product-table-scroll"> |
| | | <el-table class="product-table-inner" |
| | | <el-button type="primary" size="small" style="margin-bottom:20px" @click="isShowProductsModal = true" :disabled="!formState.purchaseLedgerId">æ·»å 产å</el-button> |
| | | <el-table |
| | | :data="formState.purchaseReturnOrderProductsDtos" |
| | | border |
| | | max-height="400" |
| | | show-summary |
| | | :summary-method="summarizeChildrenTable"> |
| | | :summary-method="summarizeChildrenTable" |
| | | style="width:100%;min-width:0;"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | width="55" /> |
| | |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="section-title"> |
| | |
| | | }); |
| | | |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | return parseFloat(cellValue).toFixed(6); |
| | | }; |
| | | |
| | | const formatAmount = (value) => { |
| | |
| | | margin-right: 8px; |
| | | } |
| | | |
| | | .product-table-scroll { |
| | | width: 100%; |
| | | overflow-x: auto; |
| | | } |
| | | |
| | | .product-table-inner { |
| | | min-width: 1280px; |
| | | } |
| | | </style> |
| | |
| | | return params == "éå®" ? "éå®" : "å
é¨"; |
| | | }, |
| | | }, |
| | | { |
| | | label: "éå®ååå·", |
| | | prop: "salesContractNo", |
| | | width: "200px", |
| | | dataType: "slot", |
| | | slot: "salesContractNo", |
| | | }, |
| | | |
| | | { |
| | | label: "产ååç§°", |
| | |
| | | label: "æéæ°é", |
| | | prop: "qtyRequired", |
| | | width: "150px", |
| | | align: "right", |
| | | dataType: "slot", |
| | | slot: "qtyRequired", |
| | | className: "volume-cell", |
| | |
| | | className: "date-cell", |
| | | formatData: cell => (cell ? dayjs(cell).format("YYYY-MM-DD") : ""), |
| | | }, |
| | | { |
| | | label: "éå®ååå·", |
| | | prop: "salesContractNo", |
| | | width: "200px", |
| | | dataType: "slot", |
| | | slot: "salesContractNo", |
| | | }, |
| | | |
| | | { |
| | | label: "客æ·åç§°", |
| | | prop: "customerName", |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµç»æï¼" prop="checkResult"> |
| | | <el-select v-model="form.checkResult" :disabled="isViewMode"> |
| | | <el-option label="åæ ¼" value="åæ ¼" /> |
| | | <el-option label="ä¸åæ ¼" value="ä¸åæ ¼" /> |
| | | <el-option label="é¨ååæ ¼" value="é¨ååæ ¼" /> |
| | | </el-select> |
| | | <el-form-item label="åæ ¼çï¼"> |
| | | <el-tag :type="passRateTagType">{{ passRateDisplayText }}</el-tag> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | }, |
| | | rules: { |
| | | checkTime: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | |
| | | qualifiedQuantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | unqualifiedQuantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkCompany: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkResult: [{ required: true, message: "请è¾å
¥", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | // æ¯å¦ä¸ºæ¥çæ¨¡å¼ |
| | | const isViewMode = computed(() => operationType.value === 'view'); |
| | | |
| | | const passRateValue = computed(() => { |
| | | const fromApi = form.value.passRate; |
| | | if (fromApi != null && fromApi !== '') { |
| | | const n = Number(fromApi); |
| | | if (!Number.isNaN(n)) return n; |
| | | } |
| | | const quantity = Number(form.value.quantity); |
| | | const qualified = Number(form.value.qualifiedQuantity); |
| | | if (!quantity || Number.isNaN(quantity)) return null; |
| | | const qualifiedNum = Number.isNaN(qualified) ? 0 : qualified; |
| | | return (qualifiedNum / quantity) * 100; |
| | | }); |
| | | |
| | | const passRateDisplayText = computed(() => { |
| | | const params = passRateValue.value; |
| | | if (params == null || params === '') return 'â'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'â'; |
| | | return `${n.toFixed(2)}%`; |
| | | }); |
| | | |
| | | const passRateTagType = computed(() => { |
| | | const params = passRateValue.value; |
| | | if (params == null || params === '') return 'info'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'info'; |
| | | if (n >= 100) return 'success'; |
| | | if (n >= 90) return 'warning'; |
| | | return 'danger'; |
| | | }); |
| | | // ç¼è¾æ¶ï¼productMainId æ purchaseLedgerId 任䏿å¼åå·¥åºãæ°éç½®ç° |
| | | const processQuantityDisabled = computed(() => { |
| | | const v = form.value || {}; |
| | |
| | | width: 120 |
| | | }, |
| | | { |
| | | label: "æ£æµç»æ", |
| | | prop: "checkResult", |
| | | label: "åæ ¼ç", |
| | | prop: "passRate", |
| | | width: 100, |
| | | dataType: "tag", |
| | | formatData: (params) => { |
| | | if (params == null || params === '') return 'â'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'â'; |
| | | return `${n.toFixed(2)}%`; |
| | | }, |
| | | formatType: (params) => { |
| | | if (params == 'ä¸åæ ¼') { |
| | | return "danger"; |
| | | } else if (params == 'åæ ¼') { |
| | | return "success"; |
| | | } else { |
| | | return 'danger'; |
| | | } |
| | | if (params == null || params === '') return 'info'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'info'; |
| | | if (n === 100) return 'success'; |
| | | if (n >= 75) return 'primary'; |
| | | if (n >= 50) return 'warning'; |
| | | if (n >= 25) return 'danger'; |
| | | return 'danger'; |
| | | }, |
| | | }, |
| | | { |
| | | label: "æäº¤ç¶æ", |
| | | prop: "inspectState", |
| | | dataType: "tag", |
| | | formatData: (params) => { |
| | | if (params) { |
| | | return "å·²æäº¤"; |
| | |
| | | return "æªæäº¤"; |
| | | } |
| | | }, |
| | | formatType: (params) => { |
| | | if (params) { |
| | | return "success"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµç»æï¼" |
| | | prop="checkResult"> |
| | | <el-select v-model="form.checkResult" :disabled="isViewMode"> |
| | | <el-option label="åæ ¼" |
| | | value="åæ ¼" /> |
| | | <el-option label="ä¸åæ ¼" |
| | | value="ä¸åæ ¼" /> |
| | | <el-option label="é¨ååæ ¼" |
| | | value="é¨ååæ ¼" /> |
| | | </el-select> |
| | | <el-form-item label="åæ ¼çï¼"> |
| | | <el-tag :type="passRateTagType">{{ passRateDisplayText }}</el-tag> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | qualifiedQuantity: "", |
| | | unqualifiedQuantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | }, |
| | | rules: { |
| | | checkTime: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | |
| | | qualifiedQuantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | unqualifiedQuantity: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkCompany: [{ required: false, message: "请è¾å
¥", trigger: "blur" }], |
| | | checkResult: [{ required: true, message: "请è¾å
¥", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const userList = ref([]); |
| | | const { form, rules } = toRefs(data); |
| | | // æ¯å¦ä¸ºæ¥çæ¨¡å¼ |
| | | const isViewMode = computed(() => operationType.value === 'view'); |
| | | |
| | | const passRateValue = computed(() => { |
| | | const fromApi = form.value.passRate; |
| | | if (fromApi != null && fromApi !== '') { |
| | | const n = Number(fromApi); |
| | | if (!Number.isNaN(n)) return n; |
| | | } |
| | | const quantity = Number(form.value.quantity); |
| | | const qualified = Number(form.value.qualifiedQuantity); |
| | | if (!quantity || Number.isNaN(quantity)) return null; |
| | | const qualifiedNum = Number.isNaN(qualified) ? 0 : qualified; |
| | | return (qualifiedNum / quantity) * 100; |
| | | }); |
| | | |
| | | const passRateDisplayText = computed(() => { |
| | | const params = passRateValue.value; |
| | | if (params == null || params === '') return 'â'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'â'; |
| | | return `${n.toFixed(2)}%`; |
| | | }); |
| | | |
| | | const passRateTagType = computed(() => { |
| | | const params = passRateValue.value; |
| | | if (params == null || params === '') return 'info'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'info'; |
| | | if (n >= 100) return 'success'; |
| | | if (n >= 90) return 'warning'; |
| | | return 'danger'; |
| | | }); |
| | | // ç¼è¾æ¶ï¼productMainId æ purchaseLedgerId 任䏿å¼åå·¥åºãæ°éç½®ç° |
| | | const processQuantityDisabled = computed(() => { |
| | | const v = form.value || {}; |
| | |
| | | unit: "", |
| | | quantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | }; |
| | | testStandardOptions.value = []; |
| | | tableData.value = []; |
| | |
| | | width: 120 |
| | | }, |
| | | { |
| | | label: "æ£æµç»æ", |
| | | prop: "checkResult", |
| | | label: "åæ ¼ç", |
| | | prop: "passRate", |
| | | width: 100, |
| | | dataType: "tag", |
| | | formatData: (params) => { |
| | | if (params == null || params === '') return 'â'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'â'; |
| | | return `${n.toFixed(2)}%`; |
| | | }, |
| | | formatType: (params) => { |
| | | if (params == 'ä¸åæ ¼') { |
| | | return "danger"; |
| | | } else if (params == 'åæ ¼') { |
| | | return "success"; |
| | | } else { |
| | | return 'danger'; |
| | | } |
| | | if (params == null || params === '') return 'info'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'info'; |
| | | if (n === 100) return 'success'; |
| | | if (n >= 75) return 'primary'; |
| | | if (n >= 50) return 'warning'; |
| | | if (n >= 25) return 'danger'; |
| | | return 'danger'; |
| | | }, |
| | | }, |
| | | { |
| | | label: "æäº¤ç¶æ", |
| | | prop: "inspectState", |
| | | dataType: "tag", |
| | | formatData: (params) => { |
| | | if (params) { |
| | | return "å·²æäº¤"; |
| | |
| | | return "æªæäº¤"; |
| | | } |
| | | }, |
| | | formatType: (params) => { |
| | | if (params) { |
| | | return "success"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="æ£æµç»æï¼" prop="checkResult"> |
| | | <el-select v-model="form.checkResult" :disabled="isViewMode"> |
| | | <el-option label="åæ ¼" value="åæ ¼"/> |
| | | <el-option label="ä¸åæ ¼" value="ä¸åæ ¼"/> |
| | | <el-option label="é¨ååæ ¼" value="é¨ååæ ¼"/> |
| | | </el-select> |
| | | <el-form-item label="åæ ¼çï¼"> |
| | | <el-tag :type="passRateTagType">{{ passRateDisplayText }}</el-tag> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | unit: "", |
| | | quantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | }, |
| | | rules: { |
| | | checkTime: [{required: true, message: "请è¾å
¥", trigger: "blur"},], |
| | |
| | | qualifiedQuantity: [{required: true, message: "请è¾å
¥", trigger: "blur"}], |
| | | unqualifiedQuantity: [{required: true, message: "请è¾å
¥", trigger: "blur"}], |
| | | checkCompany: [{required: false, message: "请è¾å
¥", trigger: "blur"}], |
| | | checkResult: [{required: true, message: "è¯·éæ©æ£æµç»æ", trigger: "change"}], |
| | | }, |
| | | }); |
| | | const tableColumn = ref([ |
| | |
| | | // æ¯å¦ä¸ºæ¥çæ¨¡å¼ |
| | | const isViewMode = computed(() => operationType.value === 'view'); |
| | | |
| | | const passRateValue = computed(() => { |
| | | const fromApi = form.value.passRate; |
| | | if (fromApi != null && fromApi !== '') { |
| | | const n = Number(fromApi); |
| | | if (!Number.isNaN(n)) return n; |
| | | } |
| | | const quantity = Number(form.value.quantity); |
| | | const qualified = Number(form.value.qualifiedQuantity); |
| | | if (!quantity || Number.isNaN(quantity)) return null; |
| | | const qualifiedNum = Number.isNaN(qualified) ? 0 : qualified; |
| | | return (qualifiedNum / quantity) * 100; |
| | | }); |
| | | |
| | | const passRateDisplayText = computed(() => { |
| | | const params = passRateValue.value; |
| | | if (params == null || params === '') return 'â'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'â'; |
| | | return `${n.toFixed(2)}%`; |
| | | }); |
| | | |
| | | const passRateTagType = computed(() => { |
| | | const params = passRateValue.value; |
| | | if (params == null || params === '') return 'info'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'info'; |
| | | if (n >= 100) return 'success'; |
| | | if (n >= 90) return 'warning'; |
| | | return 'danger'; |
| | | }); |
| | | |
| | | // ç¼è¾æ¶ï¼productMainId æ purchaseLedgerId 任䏿å¼åä¾åºåãæ°éç½®ç° |
| | | const supplierQuantityDisabled = computed(() => { |
| | | const v = form.value || {}; |
| | |
| | | unit: "", |
| | | quantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | } |
| | | testStandardOptions.value = []; |
| | | tableData.value = []; |
| | |
| | | width: 120 |
| | | }, |
| | | { |
| | | label: "æ£æµåä½", |
| | | prop: "checkCompany", |
| | | width: 120 |
| | | }, |
| | | { |
| | | label: "æ£æµç»æ", |
| | | prop: "checkResult", |
| | | label: "åæ ¼ç", |
| | | prop: "passRate", |
| | | width: 100, |
| | | dataType: "tag", |
| | | formatData: (params) => { |
| | | if (params == null || params === '') return 'â'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'â'; |
| | | return `${n.toFixed(2)}%`; |
| | | }, |
| | | formatType: (params) => { |
| | | if (params === 'ä¸åæ ¼') { |
| | | return "danger"; |
| | | } else if (params === 'åæ ¼') { |
| | | return "success"; |
| | | } else { |
| | | return 'danger'; |
| | | } |
| | | if (params == null || params === '') return 'info'; |
| | | const n = Number(params); |
| | | if (Number.isNaN(n)) return 'info'; |
| | | if (n === 100) return 'success'; |
| | | if (n >= 75) return 'primary'; |
| | | if (n >= 50) return 'warning'; |
| | | if (n >= 25) return 'danger'; |
| | | return 'danger'; |
| | | }, |
| | | }, |
| | | { |
| | | label: "æäº¤ç¶æ", |
| | | prop: "inspectState", |
| | | dataType: "tag", |
| | | formatData: (params) => { |
| | | if (params) { |
| | | return "å·²æäº¤"; |
| | |
| | | return "æªæäº¤"; |
| | | } |
| | | }, |
| | | formatType: (params) => { |
| | | if (params) { |
| | | return "success"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }, |
| | | }, |
| | | { |
| | | dataType: "action", |
| | |
| | | show-overflow-tooltip |
| | | width="200" /> |
| | | <el-table-column label="ååéé¢(å
)" |
| | | prop="invoiceTotal" |
| | | prop="contractAmounts" |
| | | show-overflow-tooltip |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | |
| | | :formatter="formattedNumber" |
| | | width="200" /> |
| | | <el-table-column label="åºæ¶éé¢(å
)" |
| | | prop="unReceiptPaymentAmount" |
| | | prop="receiptableAmount" |
| | | show-overflow-tooltip |
| | | width="200"> |
| | | <template #default="{ row, column }"> |
| | | <el-text type="danger"> |
| | | {{ formattedNumber(row, column, row.unReceiptPaymentAmount) }} |
| | | {{ formattedNumber(row, column, row.receiptableAmount) }} |
| | | </el-text> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | prop="taxRate" /> |
| | | <el-table-column label="å«ç¨åä»·(å
)" |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="sensitiveAmountFormatter" /> |
| | | :formatter="sensitiveUnitPriceFormatter" /> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" |
| | | prop="taxInclusiveTotalPrice" |
| | | :formatter="sensitiveAmountFormatter" /> |
| | |
| | | show-overflow-tooltip /> |
| | | <el-table-column fixed="right" |
| | | label="æä½" |
| | | width="130" |
| | | width="220" |
| | | align="center"> |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openForm('view', scope.row)">详æ
|
| | | </el-button> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openForm('edit', scope.row)" |
| | |
| | | @pagination="paginationChange" /> |
| | | </div> |
| | | <FormDialog v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? 'æ°å¢éå®å°è´¦é¡µé¢' : 'ç¼è¾éå®å°è´¦é¡µé¢'" |
| | | :title="operationType === 'add' ? 'æ°å¢éå®å°è´¦é¡µé¢' : (operationType === 'edit' ? 'ç¼è¾éå®å°è´¦é¡µé¢' : 'éå®å°è´¦è¯¦æ
')" |
| | | :width="'70%'" |
| | | :operation-type="operationType" |
| | | @close="closeDia" |
| | |
| | | <el-form-item label="éå®ååå·ï¼" |
| | | prop="salesContractNo"> |
| | | <div style="display: flex; align-items: center; gap: 12px;width: 100%;"> |
| | | <el-checkbox v-model="form.autoGenerateContractNo" v-if="operationType === 'add'">èªå¨çæ |
| | | <el-checkbox v-model="form.autoGenerateContractNo" |
| | | v-if="operationType === 'add'">èªå¨çæ |
| | | </el-checkbox> |
| | | <el-input v-model="form.salesContractNo" |
| | | :placeholder="form.autoGenerateContractNo ? 'èªå¨çæ' : '请è¾å
¥'" |
| | | clearable |
| | | :disabled="form.autoGenerateContractNo" /> |
| | | |
| | | :disabled="form.autoGenerateContractNo || operationType === 'view'" /> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | :reserve-keyword="false" |
| | | placeholder="è¯·éæ©" |
| | | clearable |
| | | :disabled="operationType === 'view'" |
| | | @change="changs"> |
| | | <el-option v-for="item in userList" |
| | | :key="item.userId" |
| | |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable /> |
| | | clearable |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | format="YYYY-MM-DD" |
| | | type="date" |
| | | placeholder="è¯·éæ©" |
| | | clearable /> |
| | | clearable |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | <el-table-column label="ç¨ç(%)" |
| | | prop="taxRate" /> |
| | | <el-table-column label="å«ç¨åä»·(å
)" |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="formattedNumber" /> |
| | | prop="taxInclusiveUnitPrice" |
| | | :formatter="unitPriceFormatter" /> |
| | | <el-table-column label="å«ç¨æ»ä»·(å
)" |
| | | prop="taxInclusiveTotalPrice" |
| | | :formatter="formattedNumber" /> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-row v-if="operationType !== 'view'" |
| | | :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="éä»¶ææï¼" |
| | | prop="salesLedgerFiles"> |
| | | <FileUpload v-model:file-list="fileList" /> |
| | | <FileUpload v-model:file-list="fileList" |
| | | :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | :min="0" |
| | | v-model="productForm.taxInclusiveUnitPrice" |
| | | style="width: 100%" |
| | | :precision="2" |
| | | :precision="6" |
| | | placeholder="请è¾å
¥" |
| | | clearable |
| | | @change="calculateFromUnitPrice" /> |
| | |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24" v-if="deliveryForm.type === '货车'"> |
| | | <el-col :span="24" |
| | | v-if="deliveryForm.type === '货车'"> |
| | | <el-form-item label="å货车çå·ï¼" |
| | | prop="shippingCarNumber"> |
| | | <el-input v-model="deliveryForm.shippingCarNumber" |
| | |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="24" v-else> |
| | | <el-col :span="24" |
| | | v-else> |
| | | <el-form-item label="å¿«éå
¬å¸ï¼" |
| | | prop="expressCompany"> |
| | | <el-input v-model="deliveryForm.expressCompany" |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30" v-if="deliveryForm.type === 'å¿«é'"> |
| | | <el-row :gutter="30" |
| | | v-if="deliveryForm.type === 'å¿«é'"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="å¿«éåå·ï¼" |
| | | prop="expressNumber"> |
| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="åè´§å¾çï¼"> |
| | | <ImageUpload v-model:file-list="deliveryFileList" :limit="9" /> |
| | | <ImageUpload v-model:file-list="deliveryFileList" |
| | | :limit="9" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | shippingCarNumber: [ |
| | | { validator: validateDeliveryShippingCarNumber, trigger: "blur" }, |
| | | ], |
| | | expressCompany: [{ validator: validateDeliveryExpressCompany, trigger: "blur" }], |
| | | expressCompany: [ |
| | | { validator: validateDeliveryExpressCompany, trigger: "blur" }, |
| | | ], |
| | | type: [{ required: true, message: "è¯·éæ©åè´§ç±»å", trigger: "change" }], |
| | | }, |
| | | }); |
| | |
| | | } |
| | | return parseFloat(cellValue).toFixed(2); |
| | | }; |
| | | const unitPriceFormatter = (row, column, cellValue) => { |
| | | if (cellValue === undefined || cellValue === null || cellValue === "") { |
| | | return "0.000000"; |
| | | } |
| | | return parseFloat(cellValue).toFixed(6); |
| | | }; |
| | | const findLedgerRecordByRow = row => { |
| | | if (!row) return null; |
| | | if ( |
| | |
| | | return "*****"; |
| | | } |
| | | return formattedNumber(row, column, cellValue); |
| | | }; |
| | | const sensitiveUnitPriceFormatter = (row, column, cellValue) => { |
| | | if (!isCurrentUserMaintainer(row)) { |
| | | return "*****"; |
| | | } |
| | | return unitPriceFormatter(row, column, cellValue); |
| | | }; |
| | | // è·åtreeåæ°æ® |
| | | const getModels = value => { |
| | |
| | | unit: p.unit || "", |
| | | quantity: quantity, |
| | | taxRate: taxRate, |
| | | taxInclusiveUnitPrice: unitPrice.toFixed(2), |
| | | taxInclusiveUnitPrice: unitPrice.toFixed(6), |
| | | taxInclusiveTotalPrice: taxInclusiveTotalPrice, |
| | | taxExclusiveTotalPrice: taxExclusiveTotalPrice, |
| | | invoiceType: "墿®ç¥¨", |
| | | isProduction: true, |
| | | productId: p.productId, |
| | | productModelId: p.productModelId |
| | | productModelId: p.productModelId, |
| | | }; |
| | | }); |
| | | |
| | |
| | | form.value.storageBlobDTOs = fileList; |
| | | form.value.type = 1; |
| | | if (form.value.autoGenerateContractNo) { |
| | | form.value.salesContractNo = ''; |
| | | form.value.salesContractNo = ""; |
| | | } |
| | | addOrUpdateSalesLedger(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | |
| | | } |
| | | |
| | | if (operationType.value === "add") { |
| | | productSelectedRows.value.forEach(selectedRow => { |
| | | const index = productData.value.findIndex( |
| | | product => product.id === selectedRow.id |
| | | ); |
| | | if (index !== -1) { |
| | | productData.value.splice(index, 1); |
| | | } |
| | | }); |
| | | productData.value = productData.value.filter( |
| | | item => !productSelectedRows.value.includes(item) |
| | | ); |
| | | productSelectedRows.value = []; |
| | | } else { |
| | | let ids = []; |
| | | if (productSelectedRows.value.length > 0) { |
| | |
| | | |
| | | // æå»ºæå°å
容 |
| | | let printContent = ` |
| | | <!DOCTYPE html> |
| | | <html> |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <title>æå°é¢è§</title> |
| | | <style> |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | font-family: "SimSun", serif; |
| | | background: white; |
| | | } |
| | | .print-page { |
| | | width: 200mm; |
| | | height: 75mm; |
| | | padding: 10mm; |
| | | padding-left: 20mm; |
| | | background: white; |
| | | box-sizing: border-box; |
| | | page-break-after: always; |
| | | page-break-inside: avoid; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | .delivery-note { |
| | | width: 100%; |
| | | height: 100%; |
| | | font-size: 12px; |
| | | line-height: 1.2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | color: #000; |
| | | } |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 8px; |
| | | } |
| | | .company-name { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 4px; |
| | | } |
| | | .document-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | .info-section { |
| | | margin-bottom: 8px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | .info-row { |
| | | line-height: 20px; |
| | | } |
| | | .label { |
| | | font-weight: bold; |
| | | width: 60px; |
| | | font-size: 12px; |
| | | } |
| | | .value { |
| | | margin-right: 20px; |
| | | min-width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .table-section { |
| | | margin-bottom: 40px; |
| | | // flex: 0.6; |
| | | } |
| | | .product-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | border: 1px solid #000; |
| | | } |
| | | .product-table th, .product-table td { |
| | | border: 1px solid #000; |
| | | padding: 6px; |
| | | text-align: center; |
| | | font-size: 12px; |
| | | line-height: 1.4; |
| | | } |
| | | .product-table th { |
| | | font-weight: bold; |
| | | } |
| | | .total-value { |
| | | font-weight: bold; |
| | | } |
| | | .footer-section { |
| | | margin-top: auto; |
| | | } |
| | | .footer-row { |
| | | display: flex; |
| | | margin-bottom: 3px; |
| | | line-height: 22px; |
| | | justify-content: space-between; |
| | | } |
| | | .footer-item { |
| | | display: flex; |
| | | margin-right: 20px; |
| | | } |
| | | .footer-item .label { |
| | | font-weight: bold; |
| | | width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .footer-item .value { |
| | | min-width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .address-item .address-value { |
| | | min-width: 200px; |
| | | } |
| | | @media print { |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | .print-page { |
| | | margin: 0; |
| | | padding: 10mm; |
| | | /* padding-left: 20mm; */ |
| | | page-break-inside: avoid; |
| | | page-break-after: always; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | `; |
| | | <!DOCTYPE html> |
| | | <html> |
| | | <head> |
| | | <meta charset="UTF-8"> |
| | | <title>æå°é¢è§</title> |
| | | <style> |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | font-family: "SimSun", serif; |
| | | background: white; |
| | | } |
| | | .print-page { |
| | | width: 200mm; |
| | | height: 75mm; |
| | | padding: 10mm; |
| | | padding-left: 20mm; |
| | | background: white; |
| | | box-sizing: border-box; |
| | | page-break-after: always; |
| | | page-break-inside: avoid; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | .delivery-note { |
| | | width: 100%; |
| | | height: 100%; |
| | | font-size: 12px; |
| | | line-height: 1.2; |
| | | display: flex; |
| | | flex-direction: column; |
| | | color: #000; |
| | | } |
| | | .header { |
| | | text-align: center; |
| | | margin-bottom: 8px; |
| | | } |
| | | .company-name { |
| | | font-size: 18px; |
| | | font-weight: bold; |
| | | margin-bottom: 4px; |
| | | } |
| | | .document-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | } |
| | | .info-section { |
| | | margin-bottom: 8px; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | .info-row { |
| | | line-height: 20px; |
| | | } |
| | | .label { |
| | | font-weight: bold; |
| | | width: 60px; |
| | | font-size: 12px; |
| | | } |
| | | .value { |
| | | margin-right: 20px; |
| | | min-width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .table-section { |
| | | margin-bottom: 40px; |
| | | // flex: 0.6; |
| | | } |
| | | .product-table { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | border: 1px solid #000; |
| | | } |
| | | .product-table th, .product-table td { |
| | | border: 1px solid #000; |
| | | padding: 6px; |
| | | text-align: center; |
| | | font-size: 12px; |
| | | line-height: 1.4; |
| | | } |
| | | .product-table th { |
| | | font-weight: bold; |
| | | } |
| | | .total-value { |
| | | font-weight: bold; |
| | | } |
| | | .footer-section { |
| | | margin-top: auto; |
| | | } |
| | | .footer-row { |
| | | display: flex; |
| | | margin-bottom: 3px; |
| | | line-height: 22px; |
| | | justify-content: space-between; |
| | | } |
| | | .footer-item { |
| | | display: flex; |
| | | margin-right: 20px; |
| | | } |
| | | .footer-item .label { |
| | | font-weight: bold; |
| | | width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .footer-item .value { |
| | | min-width: 80px; |
| | | font-size: 12px; |
| | | } |
| | | .address-item .address-value { |
| | | min-width: 200px; |
| | | } |
| | | @media print { |
| | | body { |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | .print-page { |
| | | margin: 0; |
| | | padding: 10mm; |
| | | /* padding-left: 20mm; */ |
| | | page-break-inside: avoid; |
| | | page-break-after: always; |
| | | } |
| | | .print-page:last-child { |
| | | page-break-after: avoid; |
| | | } |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | `; |
| | | |
| | | // ä¸ºæ¯æ¡æ°æ®çææå°é¡µé¢ |
| | | printData.value.forEach((item, index) => { |
| | | printContent += ` |
| | | <div class="print-page"> |
| | | <div class="delivery-note"> |
| | | <div class="header"> |
| | | <div class="document-title">é¶å®åè´§å</div> |
| | | </div> |
| | | |
| | | <div class="info-section"> |
| | | <div class="info-row"> |
| | | <div> |
| | | <span class="label">åè´§æ¥æï¼</span> |
| | | <span class="value">${formatDate( |
| | | item.createTime |
| | | )}</span> |
| | | </div> |
| | | <div> |
| | | <span class="label">客æ·åç§°ï¼</span> |
| | | <span class="value">${ |
| | | item.customerName |
| | | }</span> |
| | | </div> |
| | | </div> |
| | | <div class="info-row"> |
| | | <span class="label">åå·ï¼</span> |
| | | <span class="value">${ |
| | | item.salesContractNo || |
| | | "" |
| | | }</span> |
| | | </div> |
| | | </div> |
| | | <div class="print-page"> |
| | | <div class="delivery-note"> |
| | | <div class="header"> |
| | | <div class="document-title">é¶å®åè´§å</div> |
| | | </div> |
| | | |
| | | <div class="info-section"> |
| | | <div class="info-row"> |
| | | <div> |
| | | <span class="label">åè´§æ¥æï¼</span> |
| | | <span class="value">${formatDate( |
| | | item.createTime |
| | | )}</span> |
| | | </div> |
| | | <div> |
| | | <span class="label">客æ·åç§°ï¼</span> |
| | | <span class="value">${ |
| | | item.customerName |
| | | }</span> |
| | | </div> |
| | | </div> |
| | | <div class="info-row"> |
| | | <span class="label">åå·ï¼</span> |
| | | <span class="value">${ |
| | | item.salesContractNo || |
| | | "" |
| | | }</span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div class="table-section"> |
| | | <table class="product-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>产ååç§°</th> |
| | | <th>è§æ ¼åå·</th> |
| | | <th>åä½</th> |
| | | <th>åä»·</th> |
| | | <th>é¶å®æ°é</th> |
| | | <th>é¶å®éé¢</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | ${ |
| | | item.products && |
| | | item |
| | | .products |
| | | .length > |
| | | 0 |
| | | ? item.products |
| | | .map( |
| | | product => ` |
| | | <tr> |
| | | <td>${ |
| | | product.productCategory || |
| | | "" |
| | | }</td> |
| | | <td>${ |
| | | product.specificationModel || |
| | | "" |
| | | }</td> |
| | | <td>${ |
| | | product.unit || |
| | | "" |
| | | }</td> |
| | | <td>${ |
| | | product.taxInclusiveUnitPrice || |
| | | "0" |
| | | }</td> |
| | | <td>${ |
| | | product.quantity || |
| | | "0" |
| | | }</td> |
| | | <td>${ |
| | | product.taxInclusiveTotalPrice || |
| | | "0" |
| | | }</td> |
| | | </tr> |
| | | ` |
| | | ) |
| | | .join( |
| | | "" |
| | | ) |
| | | : '<tr><td colspan="6" style="text-align: center; color: #999;">ææ äº§åæ°æ®</td></tr>' |
| | | } |
| | | </tbody> |
| | | <tfoot> |
| | | <tr> |
| | | <td class="label">å计</td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value">${getTotalQuantityForPrint( |
| | | item.products |
| | | )}</td> |
| | | <td class="total-value">${getTotalAmountForPrint( |
| | | item.products |
| | | )}</td> |
| | | </tr> |
| | | </tfoot> |
| | | </table> |
| | | </div> |
| | | <div class="table-section"> |
| | | <table class="product-table"> |
| | | <thead> |
| | | <tr> |
| | | <th>产ååç§°</th> |
| | | <th>è§æ ¼åå·</th> |
| | | <th>åä½</th> |
| | | <th>åä»·</th> |
| | | <th>é¶å®æ°é</th> |
| | | <th>é¶å®éé¢</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | ${ |
| | | item.products && |
| | | item |
| | | .products |
| | | .length > |
| | | 0 |
| | | ? item.products |
| | | .map( |
| | | product => ` |
| | | <tr> |
| | | <td>${ |
| | | product.productCategory || |
| | | "" |
| | | }</td> |
| | | <td>${ |
| | | product.specificationModel || |
| | | "" |
| | | }</td> |
| | | <td>${ |
| | | product.unit || |
| | | "" |
| | | }</td> |
| | | <td>${ |
| | | product.taxInclusiveUnitPrice || |
| | | "0" |
| | | }</td> |
| | | <td>${ |
| | | product.quantity || |
| | | "0" |
| | | }</td> |
| | | <td>${ |
| | | product.taxInclusiveTotalPrice || |
| | | "0" |
| | | }</td> |
| | | </tr> |
| | | ` |
| | | ) |
| | | .join( |
| | | "" |
| | | ) |
| | | : '<tr><td colspan="6" style="text-align: center; color: #999;">ææ äº§åæ°æ®</td></tr>' |
| | | } |
| | | </tbody> |
| | | <tfoot> |
| | | <tr> |
| | | <td class="label">å计</td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value"></td> |
| | | <td class="total-value">${getTotalQuantityForPrint( |
| | | item.products |
| | | )}</td> |
| | | <td class="total-value">${getTotalAmountForPrint( |
| | | item.products |
| | | )}</td> |
| | | </tr> |
| | | </tfoot> |
| | | </table> |
| | | </div> |
| | | |
| | | <div class="footer-section"> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | | <span class="label">æ¶è´§çµè¯ï¼</span> |
| | | <span class="value"></span> |
| | | </div> |
| | | <div class="footer-item"> |
| | | <span class="label">æ¶è´§äººï¼</span> |
| | | <span class="value"></span> |
| | | </div> |
| | | <div class="footer-item address-item"> |
| | | <span class="label">æ¶è´§å°åï¼</span> |
| | | <span class="value address-value"></span> |
| | | </div> |
| | | </div> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | | <span class="label">æä½åï¼</span> |
| | | <span class="value">${ |
| | | userStore.nickName || |
| | | "æå¼å" |
| | | }</span> |
| | | </div> |
| | | <div class="footer-item"> |
| | | <span class="label">æå°æ¥æï¼</span> |
| | | <span class="value">${formatDateTime( |
| | | new Date() |
| | | )}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | `; |
| | | <div class="footer-section"> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | | <span class="label">æ¶è´§çµè¯ï¼</span> |
| | | <span class="value"></span> |
| | | </div> |
| | | <div class="footer-item"> |
| | | <span class="label">æ¶è´§äººï¼</span> |
| | | <span class="value"></span> |
| | | </div> |
| | | <div class="footer-item address-item"> |
| | | <span class="label">æ¶è´§å°åï¼</span> |
| | | <span class="value address-value"></span> |
| | | </div> |
| | | </div> |
| | | <div class="footer-row"> |
| | | <div class="footer-item"> |
| | | <span class="label">æä½åï¼</span> |
| | | <span class="value">${ |
| | | userStore.nickName || |
| | | "æå¼å" |
| | | }</span> |
| | | </div> |
| | | <div class="footer-item"> |
| | | <span class="label">æå°æ¥æï¼</span> |
| | | <span class="value">${formatDateTime( |
| | | new Date() |
| | | )}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | `; |
| | | }); |
| | | |
| | | printContent += ` |
| | | </body> |
| | | </html> |
| | | `; |
| | | </body> |
| | | </html> |
| | | `; |
| | | |
| | | // åå
¥å
容尿°çªå£ |
| | | printWindow.document.write(printContent); |
| | |
| | | isCalculating.value = true; |
| | | |
| | | // 计ç®å«ç¨åä»· = å«ç¨æ»ä»· / æ°é |
| | | productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(2); |
| | | productForm.value.taxInclusiveUnitPrice = (totalPrice / quantity).toFixed(6); |
| | | |
| | | // 妿æç¨çï¼è®¡ç®ä¸å«ç¨æ»ä»· |
| | | if (productForm.value.taxRate) { |
| | |
| | | // 计ç®å«ç¨åä»· = å«ç¨æ»ä»· / æ°é |
| | | productForm.value.taxInclusiveUnitPrice = ( |
| | | inclusiveTotalPrice / quantity |
| | | ).toFixed(2); |
| | | ).toFixed(6); |
| | | |
| | | isCalculating.value = false; |
| | | }; |
| | |
| | | |
| | | // åè´§ç¶æå¿
é¡»æ¯"å¾
åè´§"æ"å®¡æ ¸æç»" |
| | | const statusStr = shippingStatus ? String(shippingStatus).trim() : ""; |
| | | return statusStr === "å¾
åè´§" || statusStr === "å®¡æ ¸æç»" || statusStr === "é¨ååè´§"; |
| | | return ( |
| | | statusStr === "å¾
åè´§" || |
| | | statusStr === "å®¡æ ¸æç»" || |
| | | statusStr === "é¨ååè´§" |
| | | ); |
| | | }; |
| | | |
| | | // æå¼éä»¶å¼¹çª |
| | |
| | | </el-table-column> |
| | | <el-table-column prop="totalAmount" label="æ¥ä»·éé¢" width="120"> |
| | | <template #default="scope"> |
| | | ¥{{ scope.row.totalAmount.toFixed(2) }} |
| | | ¥{{ scope.row.totalAmount.toFixed(6) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="200" fixed="right" align="center"> |
| | |
| | | <el-table-column prop="unitPrice" label="åä»·"> |
| | | <template #default="scope"> |
| | | <el-form-item :prop="`products.${scope.$index}.unitPrice`" class="product-table-form-item"> |
| | | <el-input-number v-model="scope.row.unitPrice" :min="0" :precision="2" style="width: 100%" /> |
| | | <el-input-number v-model="scope.row.unitPrice" :min="0" :precision="6" style="width: 100%" /> |
| | | </el-form-item> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | <!-- <el-tag :type="getStatusType(currentQuotation.status)">{{ currentQuotation.status }}</el-tag>--> |
| | | <!-- </el-descriptions-item>--> |
| | | <el-descriptions-item label="æ¥ä»·æ»é¢" :span="2"> |
| | | <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">Â¥{{ currentQuotation.totalAmount?.toFixed(2) }}</span> |
| | | <span style="font-size: 18px; color: #e6a23c; font-weight: bold;">Â¥{{ currentQuotation.totalAmount?.toFixed(6) }}</span> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | |
| | |
| | | <el-table-column prop="unit" label="åä½" /> |
| | | <el-table-column prop="unitPrice" label="åä»·"> |
| | | <template #default="scope"> |
| | | ¥{{ scope.row.unitPrice.toFixed(2) }} |
| | | ¥{{ scope.row.unitPrice.toFixed(6) }} |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | } |
| | | |
| | | const handleEdit = async (row) => { |
| | | console.log("1111111111111111111", row) |
| | | dialogTitle.value = 'ç¼è¾æ¥ä»·' |
| | | isEdit.value = true |
| | | editId.value = row.id |
| | |
| | | : env.VITE_BASE_API; |
| | | const javaUrl = |
| | | env.VITE_APP_ENV === "development" |
| | | ? "http://1.15.17.182:9049" |
| | | ? "http://1.15.17.182:9048" |
| | | : env.VITE_JAVA_API; |
| | | return { |
| | | define:{ |