| | |
| | | @keyup.enter="handleSearch" |
| | | > |
| | | <template #prefix> |
| | | <el-icon><Search /></el-icon> |
| | | <el-icon> |
| | | <Search/> |
| | | </el-icon> |
| | | </template> |
| | | </el-input> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-select v-model="searchForm.customer" placeholder="è¯·éæ©å®¢æ·" clearable> |
| | | <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.customerName"> |
| | | <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" |
| | | :value="item.customerName"> |
| | | {{ |
| | | item.customerName + "ââ" + item.taxpayerIdentificationNumber |
| | | }} |
| | |
| | | ¥{{ scope.row.totalAmount.toFixed(2) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="200" fixed="right" align="center"> |
| | | <el-table-column label="æä½" width="250" fixed="right" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" @click="handleEdit(scope.row)" :disabled="!['å¾
审æ¹','æç»'].includes(scope.row.status)">ç¼è¾</el-button> |
| | | <el-button link type="primary" @click="handleEdit(scope.row)" |
| | | :disabled="!['å¾
审æ¹','æç»'].includes(scope.row.status)">ç¼è¾ |
| | | </el-button> |
| | | <el-button link type="primary" @click="handleView(scope.row)" style="color: #67C23A">æ¥ç</el-button> |
| | | <el-button link type="danger" @click="handleDelete(scope.row)">å é¤</el-button> |
| | | <el-button link type="primary" @click="handleImportDetail(scope.row)">导å
¥è¯¦æ
</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </el-card> |
| | | |
| | | <!-- æ°å¢/ç¼è¾å¯¹è¯æ¡ --> |
| | | <FormDialog v-model="dialogVisible" :title="dialogTitle" width="85%" :close-on-click-modal="false" @close="dialogVisible = false" @confirm="handleSubmit" @cancel="dialogVisible = false"> |
| | | <FormDialog v-model="dialogVisible" :title="dialogTitle" width="85%" :close-on-click-modal="false" |
| | | @close="dialogVisible = false" @confirm="handleSubmit" @cancel="dialogVisible = false"> |
| | | <div class="quotation-form-container"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px" class="quotation-form"> |
| | | <!-- åºæ¬ä¿¡æ¯ --> |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header-wrapper"> |
| | | <el-icon class="card-icon"><Document /></el-icon> |
| | | <el-icon class="card-icon"> |
| | | <Document/> |
| | | </el-icon> |
| | | <span class="card-title">åºæ¬ä¿¡æ¯</span> |
| | | </div> |
| | | </template> |
| | |
| | | <el-row :gutter="24"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="客æ·åç§°" prop="customer"> |
| | | <el-select v-model="form.customer" placeholder="è¯·éæ©å®¢æ·" style="width: 100%" @change="handleCustomerChange" clearable> |
| | | <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" :value="item.customerName"> |
| | | <el-select v-model="form.customer" placeholder="è¯·éæ©å®¢æ·" style="width: 100%" |
| | | @change="handleCustomerChange" clearable> |
| | | <el-option v-for="item in customerOption" :key="item.id" :label="item.customerName" |
| | | :value="item.customerName"> |
| | | {{ |
| | | item.customerName + "ââ" + item.taxpayerIdentificationNumber |
| | | }} |
| | |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header-wrapper"> |
| | | <el-icon class="card-icon"><UserFilled /></el-icon> |
| | | <el-icon class="card-icon"> |
| | | <UserFilled/> |
| | | </el-icon> |
| | | <span class="card-title">审æ¹äººéæ©</span> |
| | | <el-button type="primary" size="small" @click="addApproverNode" class="header-btn"> |
| | | <el-icon><Plus /></el-icon> |
| | | <el-icon> |
| | | <Plus/> |
| | | </el-icon> |
| | | æ°å¢èç¹ |
| | | </el-button> |
| | | </div> |
| | |
| | | <div class="approver-node-label"> |
| | | <span class="node-step">{{ index + 1 }}</span> |
| | | <span class="node-text">审æ¹äºº</span> |
| | | <el-icon class="arrow-icon"><ArrowRight /></el-icon> |
| | | <el-icon class="arrow-icon"> |
| | | <ArrowRight/> |
| | | </el-icon> |
| | | </div> |
| | | <el-select |
| | | v-model="node.userId" |
| | |
| | | @click="removeApproverNode(index)" |
| | | v-if="approverNodes.length > 1" |
| | | class="remove-btn" |
| | | >å é¤</el-button> |
| | | >å é¤ |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header-wrapper"> |
| | | <el-icon class="card-icon"><Box /></el-icon> |
| | | <el-icon class="card-icon"> |
| | | <Box/> |
| | | </el-icon> |
| | | <span class="card-title">产åä¿¡æ¯</span> |
| | | <el-button type="primary" size="small" @click="addProduct" class="header-btn"> |
| | | <el-icon><Plus /></el-icon> |
| | | <el-icon> |
| | | <Plus/> |
| | | </el-icon> |
| | | æ·»å 产å |
| | | </el-button> |
| | | </div> |
| | | </template> |
| | | <div class="form-content"> |
| | | <el-table :data="form.products" border style="width: 100%" class="product-table" v-if="form.products.length > 0"> |
| | | <el-table :data="form.products" border style="width: 100%" class="product-table" |
| | | v-if="form.products.length > 0"> |
| | | <el-table-column prop="product" label="产ååç§°" width="200"> |
| | | <template #default="scope"> |
| | | <el-form-item :prop="`products.${scope.$index}.productId`" class="product-table-form-item"> |
| | |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header-wrapper"> |
| | | <el-icon class="card-icon"><EditPen /></el-icon> |
| | | <el-icon class="card-icon"> |
| | | <EditPen/> |
| | | </el-icon> |
| | | <span class="card-title">夿³¨ä¿¡æ¯</span> |
| | | </div> |
| | | </template> |
| | |
| | | </div> |
| | | </FormDialog> |
| | | |
| | | <FormDialog v-model="importDialogVisible" title="导å
¥æ¥ä»·å" width="85%" :close-on-click-modal="false" @close="importDialogVisible = false" @confirm="handleImportSubmit" @cancel="importDialogVisible = false"> |
| | | <FormDialog v-model="importDialogVisible" title="导å
¥æ¥ä»·å" width="85%" :close-on-click-modal="false" |
| | | @close="importDialogVisible = false" @confirm="handleImportSubmit" |
| | | @cancel="importDialogVisible = false"> |
| | | <!-- 审æ¹äººä¿¡æ¯ --> |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header-wrapper"> |
| | | <el-icon class="card-icon"><UserFilled /></el-icon> |
| | | <el-icon class="card-icon"> |
| | | <UserFilled/> |
| | | </el-icon> |
| | | <span class="card-title">审æ¹äººéæ©</span> |
| | | <el-button type="primary" size="small" @click="addImportApproverNode" class="header-btn"> |
| | | <el-icon><Plus /></el-icon> |
| | | <el-icon> |
| | | <Plus/> |
| | | </el-icon> |
| | | æ°å¢èç¹ |
| | | </el-button> |
| | | </div> |
| | |
| | | <div class="approver-node-label"> |
| | | <span class="node-step">{{ index + 1 }}</span> |
| | | <span class="node-text">审æ¹äºº</span> |
| | | <el-icon class="arrow-icon"><ArrowRight /></el-icon> |
| | | <el-icon class="arrow-icon"> |
| | | <ArrowRight/> |
| | | </el-icon> |
| | | </div> |
| | | <el-select |
| | | v-model="node.userId" |
| | |
| | | @click="removeImportApproverNode(index)" |
| | | v-if="importApproverNodes.length > 1" |
| | | class="remove-btn" |
| | | >å é¤</el-button> |
| | | >å é¤ |
| | | </el-button> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header-wrapper"> |
| | | <el-icon class="card-icon"><Paperclip /></el-icon> |
| | | <el-icon class="card-icon"> |
| | | <Paperclip/> |
| | | </el-icon> |
| | | <span class="card-title">éä»¶ææ</span> |
| | | </div> |
| | | </template> |
| | | <div class="form-content"> |
| | | <el-button type="primary" @click="downloadImportTemplate" style="margin-bottom: 20px">ä¸è½½æ¨¡æ¿æä»¶</el-button> |
| | | <el-form-item label="éä»¶ææ" prop="files"> |
| | | <el-upload |
| | | v-model:file-list="importFileList" |
| | |
| | | <span style="flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"> |
| | | {{ file.name }} |
| | | </span> |
| | | <!-- <div style="display:flex; align-items:center; gap: 6px;">--> |
| | | <div style="display:flex; align-items:center; gap: 6px;"> |
| | | <!-- <el-button link type="success" :icon="Download" @click="handleDownload(file)" />--> |
| | | <!-- <el-button link type="primary" :icon="View" @click="handlePreview(file)" />--> |
| | | <!-- <el-button link type="danger" :icon="Delete" @click="triggerRemoveFile(file)" />--> |
| | | <!-- </div>--> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <template #tip> |
| | |
| | | <!-- <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(2) |
| | | }}</span> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | |
| | |
| | | <p>{{ currentQuotation.remark }}</p> |
| | | </div> |
| | | </el-dialog> |
| | | <ImportQuotationDetail v-if="showDetail" v-model:showModal="showDetail" :quotationId="currentQuotation.id" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, computed, onMounted, markRaw, shallowRef, getCurrentInstance } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { Search, Document, UserFilled, Box, EditPen, Plus, ArrowRight, Delete, Download, View } from '@element-plus/icons-vue' |
| | | import { |
| | | Search, |
| | | Document, |
| | | UserFilled, |
| | | Box, |
| | | EditPen, |
| | | Plus, |
| | | ArrowRight, |
| | | Delete, |
| | | } from '@element-plus/icons-vue' |
| | | import Pagination from '@/components/PIMTable/Pagination.vue' |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue' |
| | | import {getQuotationList,addQuotation,updateQuotation,deleteQuotation, importQuotation} from '@/api/salesManagement/salesQuotation.js' |
| | | import ImportQuotationDetail from '@/views/salesManagement/salesQuotation/ImportQuotationDetail.vue' |
| | | import { |
| | | getQuotationList, |
| | | addQuotation, |
| | | updateQuotation, |
| | | deleteQuotation, |
| | | importQuotation |
| | | } from '@/api/salesManagement/salesQuotation.js' |
| | | import {userListNoPage} from "@/api/system/user.js"; |
| | | import {customerList} from "@/api/salesManagement/salesLedger.js"; |
| | | import {modelList, productTreeList} from "@/api/basicData/product.js"; |
| | |
| | | let nextApproverId = 2 |
| | | |
| | | const isEdit = ref(false) |
| | | const showDetail = ref(false) |
| | | const editId = ref(null) |
| | | const currentQuotation = ref({}) |
| | | const formRef = ref() |
| | |
| | | return productOptions.value |
| | | }); |
| | | }; |
| | | |
| | | function convertIdToValue(data) { |
| | | return data.map((item) => { |
| | | const { id, children, ...rest } = item; |
| | |
| | | return newItem; |
| | | }); |
| | | } |
| | | |
| | | // æ ¹æ®åç§°åæ¥èç¹ idï¼ä¾¿äºä»
ååç§°æ¶çåæ¾ |
| | | function findNodeIdByLabel(nodes, label) { |
| | | if (!label) return null; |
| | |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | const getModels = (value, row) => { |
| | | if (!row) return; |
| | | // 妿æ¸
ç©ºéæ©ï¼åæ¸
空ç¸å
³å段 |
| | |
| | | }) |
| | | } |
| | | |
| | | const downloadImportTemplate = () => { |
| | | proxy.download("/sales/quotation/downloadTemplate", {}, "æ¥ä»·å导å
¥æ¨¡æ¿.xlsx"); |
| | | } |
| | | |
| | | const handleCurrentChange = (val) => { |
| | | pagination.currentPage = val.page |
| | | pagination.pageSize = val.limit |
| | |
| | | })) |
| | | }); |
| | | } |
| | | |
| | | const handleImportDetail = (row) => { |
| | | showDetail.value = true |
| | | currentQuotation.value = row |
| | | } |
| | | |
| | | |
| | | onMounted(()=>{ |
| | | handleSearch() |
| | |
| | | |
| | | .product-table-form-item { |
| | | margin-bottom: 0; |
| | | |
| | | :deep(.el-form-item__content) { |
| | | margin-left: 0 !important; |
| | | } |
| | | |
| | | :deep(.el-form-item__label) { |
| | | width: auto; |
| | | min-width: auto; |