Merge remote-tracking branch 'origin/dev_NEW_pro' into dev_NEW_pro
| | |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // çäº§è®¢åæº¯æºè¯¦æ
|
| | | export function getOrderDetail(npsNo) { |
| | | return request({ |
| | | url: "/productionOrder/ordeDetail", |
| | | method: "get", |
| | | params: { npsNo }, |
| | | }); |
| | | } |
| | | // ç产订å-é¢æè¯¦æ
å表 |
| | | // export function listMaterialPickingDetail(query) { |
| | | // return request({ |
| | |
| | | data, |
| | | }); |
| | | } |
| | | |
| | | // è·åå·¥åºç»è®¡æ°æ® |
| | | export function getOperationStatistics(query) { |
| | | return request({ |
| | | url: "/productionOperationTask/getOperation", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | |
| | | }
|
| | | }
|
| | | .table_list {
|
| | | margin-top: 20px;
|
| | | background: rgba(255, 255, 255, 0.88);
|
| | | border: 1px solid var(--surface-border);
|
| | | border-radius: var(--radius-md);
|
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form" style="margin-bottom: 20px;"> |
| | | <div> |
| | | <span class="search_title">客æ·åç§°ï¼</span> |
| | | <el-input v-model="searchForm.customerName" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form" style="margin-bottom: 20px;"> |
| | | <div> |
| | | <span class="search_title">客æ·åç§°ï¼</span> |
| | | <el-input v-model="searchForm.customerName" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div> |
| | | <div class="search_form"> |
| | | <div> |
| | | <div style="margin-bottom: 10px;"> |
| | | <span class="search_title">ä¾åºåæ¡£æ¡ï¼</span> |
| | | <el-input |
| | | v-model="searchForm.supplierName" |
| | |
| | | >æç´¢</el-button |
| | | > |
| | | </div> |
| | | <div> |
| | | <div style="margin-bottom: 10px;"> |
| | | <el-button type="primary" @click="openForm('add')" |
| | | >æ°å¢ä¾åºå</el-button |
| | | > |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form" style="margin-bottom: 20px;"> |
| | | <div> |
| | | <span class="search_title">ç¥è¯æ é¢ï¼</span> |
| | | <el-input |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search-wrapper"> |
| | | <div class="search-wrapper mb20"> |
| | | <el-form |
| | | :model="searchForm" |
| | | class="demo-form-inline" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">ä¸´ææ¥æï¼</span> |
| | | <el-date-picker |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">æ£å®æ¥æï¼</span> |
| | | <el-date-picker |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">å½å
¥æ¥æï¼</span> |
| | | <el-date-picker |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "åºå®èµäº§", |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "æ å½¢èµäº§", |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="600px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="600px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="100px"> |
| | | <el-form-item label="ç§ç®ç¼ç " prop="subjectCode"> |
| | | <el-input v-model="form.subjectCode" placeholder="请è¾å
¥ç§ç®ç¼ç " /> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "æ»å¸ç§ç®", |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "è¿é¡¹å票", |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "仿¬¾å", |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "仿¬¾ç³è¯·", |
| | |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button type="primary" @click="add" icon="Plus">æ°å¢å
¥åº</el-button> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="100px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "éè´å
¥åº", |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog title="对账æç»" v-model="detailDialogVisible" width="900px" append-to-body> |
| | | <FormDialog title="对账æç»" v-model="detailDialogVisible" width="900px" @confirm="printDetail" @cancel="detailDialogVisible = false" operationType="detail"> |
| | | <div class="statement-header"> |
| | | <h3>{{ currentSupplier }} åºä»å¯¹è´¦å</h3> |
| | | <p>对账æé´: {{ currentPeriod }}</p> |
| | |
| | | <el-table-column prop="remark" label="夿³¨" show-overflow-tooltip /> |
| | | </el-table> |
| | | <template #footer> |
| | | <el-button @click="detailDialogVisible = false">å
³é</el-button> |
| | | <el-button type="primary" @click="printDetail">æå°</el-button> |
| | | <el-button @click="detailDialogVisible = false">å
³é</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | |
| | | <FormDialog title="çæå¯¹è´¦å" v-model="generateDialogVisible" width="1000px" @confirm="confirmGenerate" @cancel="generateDialogVisible = false"> |
| | | <el-form :model="generateForm" label-width="100px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éæ©ä¾åºå" prop="supplierId"> |
| | | <el-select v-model="generateForm.supplierId" placeholder="è¯·éæ©ä¾åºå" style="width: 100%;" @change="onSupplierChange"> |
| | | <el-option v-for="item in supplierList" :key="item.id" :label="item.name" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="对账æä»½" prop="period"> |
| | | <el-date-picker v-model="generateForm.period" type="month" placeholder="éæ©æä»½" value-format="YYYY-MM" style="width: 100%;" @change="onPeriodChange" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | |
| | | <div v-if="purchaseData.length > 0" class="purchase-section"> |
| | | <div class="section-title">æ¬æéè´æ°æ®</div> |
| | | <el-table :data="purchaseData" border style="width: 100%; margin-bottom: 15px;" v-loading="purchaseLoading" @selection-change="handlePurchaseSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column prop="date" label="æ¥æ" width="120" /> |
| | | <el-table-column prop="code" label="åæ®ç¼å·" width="150" /> |
| | | <el-table-column prop="type" label="ç±»å" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.type === 'å
¥åº' ? 'success' : 'danger'">{{ row.type }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="amount" label="éé¢" width="120"> |
| | | <template #default="{ row }"> |
| | | <span :class="row.type === 'å
¥åº' ? 'text-danger' : 'text-success'">Â¥{{ formatMoney(row.amount) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="remark" label="夿³¨" /> |
| | | </el-table> |
| | | |
| | | <div class="summary-row"> |
| | | <span>æåä½é¢: <strong class="text-primary">Â¥{{ formatMoney(generateForm.beginBalance) }}</strong></span> |
| | | <span>æ¬æåºä»: <strong class="text-danger">Â¥{{ formatMoney(generateForm.currentPayable) }}</strong></span> |
| | | <span>æ¬æä»æ¬¾: <strong class="text-success">Â¥{{ formatMoney(generateForm.currentPayment) }}</strong></span> |
| | | <span>ææ«ä½é¢: <strong class="text-primary">Â¥{{ formatMoney(calculateEndBalance(generateForm.beginBalance, generateForm.currentPayable, generateForm.currentPayment)) }}</strong></span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-else-if="generateForm.supplierId && !purchaseLoading" class="empty-tip"> |
| | | <el-empty description="该ä¾åºåæ¬æææ éè´æ°æ®" /> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <el-button type="primary" @click="confirmGenerate" :disabled="!canGenerate">确认çæ</el-button> |
| | | <el-button @click="generateDialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "åºä»å¯¹è´¦", |
| | |
| | | const currentPeriod = ref(""); |
| | | const detailData = ref([]); |
| | | |
| | | const generateDialogVisible = ref(false); |
| | | const purchaseLoading = ref(false); |
| | | const purchaseData = ref([]); |
| | | const selectedPurchases = ref([]); |
| | | |
| | | const generateForm = reactive({ |
| | | supplierId: "", |
| | | supplierName: "", |
| | | period: "", |
| | | beginBalance: 0, |
| | | currentPayable: 0, |
| | | currentPayment: 0, |
| | | }); |
| | | |
| | | const canGenerate = computed(() => { |
| | | return generateForm.supplierId && generateForm.period && selectedPurchases.value.length > 0; |
| | | }); |
| | | |
| | | const supplierList = [ |
| | | { id: 1, name: "åäº¬åææä¾åºå" }, |
| | | { id: 2, name: "䏿µ·çµåå
å¨ä»¶å
¬å¸" }, |
| | |
| | | { id: 2, statementCode: "DZ202401002", supplierId: 2, supplierName: "䏿µ·çµåå
å¨ä»¶å
¬å¸", period: "2024-01", beginBalance: 10000, currentPayable: 20000, currentPayment: 15000, endBalance: 15000 }, |
| | | { id: 3, statementCode: "DZ202402001", supplierId: 1, supplierName: "åäº¬åææä¾åºå", period: "2024-02", beginBalance: 25000, currentPayable: 18000, currentPayment: 20000, endBalance: 23000 }, |
| | | ]; |
| | | |
| | | const calculateEndBalance = (beginBalance, currentPayable, currentPayment) => { |
| | | return beginBalance + currentPayable - currentPayment; |
| | | }; |
| | | |
| | | const formatMoney = (value) => { |
| | | if (value === undefined || value === null) return "0.00"; |
| | |
| | | }; |
| | | |
| | | const generateStatement = () => { |
| | | ElMessage.success("对账åçææå"); |
| | | generateForm.supplierId = ""; |
| | | generateForm.supplierName = ""; |
| | | generateForm.period = ""; |
| | | generateForm.beginBalance = 0; |
| | | generateForm.currentPayable = 0; |
| | | generateForm.currentPayment = 0; |
| | | purchaseData.value = []; |
| | | selectedPurchases.value = []; |
| | | generateDialogVisible.value = true; |
| | | }; |
| | | |
| | | const onSupplierChange = (supplierId) => { |
| | | const supplier = supplierList.find(item => item.id === supplierId); |
| | | if (supplier) { |
| | | generateForm.supplierName = supplier.name; |
| | | } |
| | | loadPurchaseData(); |
| | | }; |
| | | |
| | | const onPeriodChange = () => { |
| | | loadPurchaseData(); |
| | | }; |
| | | |
| | | const loadPurchaseData = () => { |
| | | if (!generateForm.supplierId || !generateForm.period) { |
| | | purchaseData.value = []; |
| | | return; |
| | | } |
| | | |
| | | purchaseLoading.value = true; |
| | | |
| | | setTimeout(() => { |
| | | const mockPurchaseData = [ |
| | | { id: 1, date: generateForm.period + "-05", code: "RK2024001", type: "å
¥åº", amount: 8000, remark: "åææéè´" }, |
| | | { id: 2, date: generateForm.period + "-10", code: "FK2024001", type: "仿¬¾", amount: 5000, remark: "æ¯ä»è´§æ¬¾" }, |
| | | { id: 3, date: generateForm.period + "-15", code: "RK2024002", type: "å
¥åº", amount: 12000, remark: "çµåå
å¨ä»¶" }, |
| | | { id: 4, date: generateForm.period + "-18", code: "TH2024001", type: "éè´§", amount: 2000, remark: "è´¨éé®é¢éè´§" }, |
| | | { id: 5, date: generateForm.period + "-22", code: "RK2024003", type: "å
¥åº", amount: 6000, remark: "å
è£
ææ" }, |
| | | { id: 6, date: generateForm.period + "-25", code: "FK2024002", type: "仿¬¾", amount: 8000, remark: "æ¯ä»è´§æ¬¾" }, |
| | | ]; |
| | | |
| | | purchaseData.value = mockPurchaseData; |
| | | |
| | | const lastPeriod = getLastPeriod(generateForm.period); |
| | | const lastStatement = mockData.find(item => |
| | | item.supplierId === generateForm.supplierId && item.period === lastPeriod |
| | | ); |
| | | generateForm.beginBalance = lastStatement ? lastStatement.endBalance : 0; |
| | | |
| | | calculateSummary(); |
| | | |
| | | purchaseLoading.value = false; |
| | | }, 500); |
| | | }; |
| | | |
| | | const getLastPeriod = (period) => { |
| | | const [year, month] = period.split("-").map(Number); |
| | | if (month === 1) { |
| | | return `${year - 1}-12`; |
| | | } |
| | | return `${year}-${String(month - 1).padStart(2, "0")}`; |
| | | }; |
| | | |
| | | const calculateSummary = () => { |
| | | let payable = 0; |
| | | let payment = 0; |
| | | |
| | | selectedPurchases.value.forEach(item => { |
| | | if (item.type === "å
¥åº") { |
| | | payable += item.amount; |
| | | } else if (item.type === "éè´§") { |
| | | payable -= item.amount; |
| | | } else if (item.type === "仿¬¾") { |
| | | payment += item.amount; |
| | | } |
| | | }); |
| | | |
| | | generateForm.currentPayable = payable; |
| | | generateForm.currentPayment = payment; |
| | | }; |
| | | |
| | | const handlePurchaseSelectionChange = (selection) => { |
| | | selectedPurchases.value = selection; |
| | | calculateSummary(); |
| | | }; |
| | | |
| | | const confirmGenerate = () => { |
| | | const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1; |
| | | const supplier = supplierList[Math.floor(Math.random() * supplierList.length)]; |
| | | const endBalance = calculateEndBalance(generateForm.beginBalance, generateForm.currentPayable, generateForm.currentPayment); |
| | | |
| | | mockData.unshift({ |
| | | id: newId, |
| | | statementCode: "DZ" + Date.now(), |
| | | supplierId: supplier.id, |
| | | supplierName: supplier.name, |
| | | period: "2024-03", |
| | | beginBalance: Math.floor(Math.random() * 20000), |
| | | currentPayable: Math.floor(Math.random() * 25000), |
| | | currentPayment: Math.floor(Math.random() * 20000), |
| | | endBalance: Math.floor(Math.random() * 25000), |
| | | supplierId: generateForm.supplierId, |
| | | supplierName: generateForm.supplierName, |
| | | period: generateForm.period, |
| | | beginBalance: generateForm.beginBalance, |
| | | currentPayable: generateForm.currentPayable, |
| | | currentPayment: generateForm.currentPayment, |
| | | endBalance, |
| | | }); |
| | | |
| | | generateDialogVisible.value = false; |
| | | ElMessage.success("对账åçææå"); |
| | | getTableData(); |
| | | }; |
| | | |
| | | const viewDetail = (row) => { |
| | | currentSupplier.value = row.supplierName; |
| | | currentPeriod.value = row.period; |
| | | |
| | | const purchaseInAmount = Math.floor(row.currentPayable * 0.7); |
| | | const returnAmount = Math.floor(row.currentPayable * 0.1); |
| | | const firstPayment = Math.floor(row.currentPayment * 0.5); |
| | | const secondPayment = row.currentPayment - firstPayment; |
| | | |
| | | let runningBalance = row.beginBalance; |
| | | |
| | | detailData.value = [ |
| | | { date: row.period + "-01", type: "æå", code: "-", debit: 0, credit: 0, balance: row.beginBalance, remark: "æåä½é¢" }, |
| | | { date: row.period + "-05", type: "å
¥åº", code: "RK2024001", debit: 0, credit: 8000, balance: row.beginBalance + 8000, remark: "" }, |
| | | { date: row.period + "-10", type: "仿¬¾", code: "FK2024001", debit: 5000, credit: 0, balance: row.beginBalance + 3000, remark: "" }, |
| | | { date: row.period + "-15", type: "å
¥åº", code: "RK2024002", credit: 12000, balance: row.beginBalance + 15000, remark: "" }, |
| | | { date: row.period + "-20", type: "éè´§", code: "TH2024001", debit: 2000, credit: 0, balance: row.beginBalance + 13000, remark: "" }, |
| | | { date: row.period + "-25", type: "仿¬¾", code: "FK2024002", debit: row.currentPayment - 5000, balance: row.endBalance, remark: "" }, |
| | | { date: row.period + "-01", type: "æå", code: "-", debit: 0, credit: 0, balance: runningBalance, remark: "æåä½é¢" }, |
| | | { date: row.period + "-05", type: "å
¥åº", code: "RK2024001", debit: 0, credit: purchaseInAmount, balance: runningBalance += purchaseInAmount, remark: "éè´å
¥åº" }, |
| | | { date: row.period + "-10", type: "仿¬¾", code: "FK2024001", debit: firstPayment, credit: 0, balance: runningBalance -= firstPayment, remark: "æ¯ä»è´§æ¬¾" }, |
| | | { date: row.period + "-15", type: "å
¥åº", code: "RK2024002", debit: 0, credit: row.currentPayable - purchaseInAmount - returnAmount, balance: runningBalance += (row.currentPayable - purchaseInAmount - returnAmount), remark: "éè´å
¥åº" }, |
| | | { date: row.period + "-20", type: "éè´§", code: "TH2024001", debit: 0, credit: -returnAmount, balance: runningBalance -= returnAmount, remark: "éè´éè´§" }, |
| | | { date: row.period + "-25", type: "仿¬¾", code: "FK2024002", debit: secondPayment, credit: 0, balance: runningBalance -= secondPayment, remark: "æ¯ä»è´§æ¬¾" }, |
| | | ]; |
| | | |
| | | detailDialogVisible.value = true; |
| | | }; |
| | | |
| | |
| | | margin: 0; |
| | | } |
| | | } |
| | | |
| | | .purchase-section { |
| | | margin-top: 20px; |
| | | |
| | | .section-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | margin-bottom: 15px; |
| | | padding-left: 10px; |
| | | border-left: 4px solid #409eff; |
| | | } |
| | | } |
| | | |
| | | .summary-row { |
| | | display: flex; |
| | | justify-content: space-around; |
| | | padding: 15px; |
| | | background-color: #f5f7fa; |
| | | border-radius: 4px; |
| | | margin-top: 15px; |
| | | |
| | | span { |
| | | font-size: 14px; |
| | | |
| | | strong { |
| | | font-size: 16px; |
| | | margin-left: 5px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .empty-tip { |
| | | margin-top: 30px; |
| | | } |
| | | |
| | | .text-primary { |
| | | color: #409eff; |
| | | } |
| | | </style> |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "å¼ç¥¨ç³è¯·", |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "é项å票", |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "æ¶æ¬¾å", |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog title="对账æç»" v-model="detailDialogVisible" width="900px" append-to-body> |
| | | <FormDialog title="对账æç»" v-model="detailDialogVisible" width="900px" @confirm="printDetail" @cancel="detailDialogVisible = false" operationType="detail"> |
| | | <div class="statement-header"> |
| | | <h3>{{ currentCustomer }} åºæ¶å¯¹è´¦å</h3> |
| | | <p>对账æé´: {{ currentPeriod }}</p> |
| | |
| | | <el-table-column prop="remark" label="夿³¨" show-overflow-tooltip /> |
| | | </el-table> |
| | | <template #footer> |
| | | <el-button @click="detailDialogVisible = false">å
³é</el-button> |
| | | <el-button type="primary" @click="printDetail">æå°</el-button> |
| | | <el-button @click="detailDialogVisible = false">å
³é</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | |
| | | <FormDialog title="çæå¯¹è´¦å" v-model="generateDialogVisible" width="1000px" @confirm="confirmGenerate" @cancel="generateDialogVisible = false"> |
| | | <el-form :model="generateForm" label-width="100px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="鿩客æ·" prop="customerId"> |
| | | <el-select v-model="generateForm.customerId" placeholder="è¯·éæ©å®¢æ·" style="width: 100%;" @change="onCustomerChange"> |
| | | <el-option v-for="item in customerList" :key="item.id" :label="item.name" :value="item.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="对账æä»½" prop="period"> |
| | | <el-date-picker v-model="generateForm.period" type="month" placeholder="éæ©æä»½" value-format="YYYY-MM" style="width: 100%;" @change="onPeriodChange" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | |
| | | <div v-if="salesData.length > 0" class="sales-section"> |
| | | <div class="section-title">æ¬æé宿°æ®</div> |
| | | <el-table :data="salesData" border style="width: 100%; margin-bottom: 15px;" v-loading="salesLoading" @selection-change="handleSalesSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column prop="date" label="æ¥æ" width="120" /> |
| | | <el-table-column prop="code" label="åæ®ç¼å·" width="150" /> |
| | | <el-table-column prop="type" label="ç±»å" width="100"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="row.type === 'åºåº' ? 'success' : row.type === 'æ¶æ¬¾' ? 'primary' : 'danger'">{{ row.type }}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="amount" label="éé¢" width="120"> |
| | | <template #default="{ row }"> |
| | | <span :class="row.type === 'åºåº' ? 'text-primary' : row.type === 'æ¶æ¬¾' ? 'text-success' : 'text-danger'">Â¥{{ formatMoney(row.amount) }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="remark" label="夿³¨" /> |
| | | </el-table> |
| | | |
| | | <div class="summary-row"> |
| | | <span>æåä½é¢: <strong class="text-primary">Â¥{{ formatMoney(generateForm.beginBalance) }}</strong></span> |
| | | <span>æ¬æåºæ¶: <strong class="text-primary">Â¥{{ formatMoney(generateForm.currentReceivable) }}</strong></span> |
| | | <span>æ¬ææ¶æ¬¾: <strong class="text-success">Â¥{{ formatMoney(generateForm.currentReceipt) }}</strong></span> |
| | | <span>ææ«ä½é¢: <strong :class="calculateEndBalance(generateForm.beginBalance, generateForm.currentReceivable, generateForm.currentReceipt) >= 0 ? 'text-success' : 'text-danger'">Â¥{{ formatMoney(calculateEndBalance(generateForm.beginBalance, generateForm.currentReceivable, generateForm.currentReceipt)) }}</strong></span> |
| | | </div> |
| | | </div> |
| | | |
| | | <div v-else-if="generateForm.customerId && !salesLoading" class="empty-tip"> |
| | | <el-empty description="è¯¥å®¢æ·æ¬æææ é宿°æ®" /> |
| | | </div> |
| | | |
| | | <template #footer> |
| | | <el-button type="primary" @click="confirmGenerate" :disabled="!canGenerate">确认çæ</el-button> |
| | | <el-button @click="generateDialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ElMessage } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "åºæ¶å¯¹è´¦", |
| | |
| | | const currentPeriod = ref(""); |
| | | const detailData = ref([]); |
| | | |
| | | const generateDialogVisible = ref(false); |
| | | const salesLoading = ref(false); |
| | | const salesData = ref([]); |
| | | const selectedSales = ref([]); |
| | | |
| | | const generateForm = reactive({ |
| | | customerId: "", |
| | | customerName: "", |
| | | period: "", |
| | | beginBalance: 0, |
| | | currentReceivable: 0, |
| | | currentReceipt: 0, |
| | | }); |
| | | |
| | | const canGenerate = computed(() => { |
| | | return generateForm.customerId && generateForm.period && selectedSales.value.length > 0; |
| | | }); |
| | | |
| | | const customerList = [ |
| | | { id: 1, name: "åäº¬ç§ææéå
¬å¸" }, |
| | | { id: 2, name: "䏿µ·è´¸æå
¬å¸" }, |
| | |
| | | { id: 2, statementCode: "DZ202401002", customerId: 2, customerName: "䏿µ·è´¸æå
¬å¸", period: "2024-01", beginBalance: 5000, currentReceivable: 12000, currentReceipt: 10000, endBalance: 7000 }, |
| | | { id: 3, statementCode: "DZ202402001", customerId: 1, customerName: "åäº¬ç§ææéå
¬å¸", period: "2024-02", beginBalance: 17000, currentReceivable: 20000, currentReceipt: 15000, endBalance: 22000 }, |
| | | ]; |
| | | |
| | | const calculateEndBalance = (beginBalance, currentReceivable, currentReceipt) => { |
| | | return beginBalance + currentReceivable - currentReceipt; |
| | | }; |
| | | |
| | | const formatMoney = (value) => { |
| | | if (value === undefined || value === null) return "0.00"; |
| | |
| | | }; |
| | | |
| | | const generateStatement = () => { |
| | | ElMessage.success("对账åçææå"); |
| | | generateForm.customerId = ""; |
| | | generateForm.customerName = ""; |
| | | generateForm.period = ""; |
| | | generateForm.beginBalance = 0; |
| | | generateForm.currentReceivable = 0; |
| | | generateForm.currentReceipt = 0; |
| | | salesData.value = []; |
| | | selectedSales.value = []; |
| | | generateDialogVisible.value = true; |
| | | }; |
| | | |
| | | const onCustomerChange = (customerId) => { |
| | | const customer = customerList.find(item => item.id === customerId); |
| | | if (customer) { |
| | | generateForm.customerName = customer.name; |
| | | } |
| | | loadSalesData(); |
| | | }; |
| | | |
| | | const onPeriodChange = () => { |
| | | loadSalesData(); |
| | | }; |
| | | |
| | | const loadSalesData = () => { |
| | | if (!generateForm.customerId || !generateForm.period) { |
| | | salesData.value = []; |
| | | return; |
| | | } |
| | | |
| | | salesLoading.value = true; |
| | | |
| | | setTimeout(() => { |
| | | const mockSalesData = [ |
| | | { id: 1, date: generateForm.period + "-03", code: "CK2024001", type: "åºåº", amount: 8000, remark: "产åAéå®" }, |
| | | { id: 2, date: generateForm.period + "-08", code: "SK2024001", type: "æ¶æ¬¾", amount: 5000, remark: "客æ·å款" }, |
| | | { id: 3, date: generateForm.period + "-12", code: "CK2024002", type: "åºåº", amount: 12000, remark: "产åBéå®" }, |
| | | { id: 4, date: generateForm.period + "-15", code: "TH2024001", type: "éè´§", amount: 2000, remark: "è´¨éé®é¢éè´§" }, |
| | | { id: 5, date: generateForm.period + "-20", code: "CK2024003", type: "åºåº", amount: 5000, remark: "产åCéå®" }, |
| | | { id: 6, date: generateForm.period + "-25", code: "SK2024002", type: "æ¶æ¬¾", amount: 8000, remark: "客æ·å款" }, |
| | | ]; |
| | | |
| | | salesData.value = mockSalesData; |
| | | |
| | | const lastPeriod = getLastPeriod(generateForm.period); |
| | | const lastStatement = mockData.find(item => |
| | | item.customerId === generateForm.customerId && item.period === lastPeriod |
| | | ); |
| | | generateForm.beginBalance = lastStatement ? lastStatement.endBalance : 0; |
| | | |
| | | calculateSummary(); |
| | | |
| | | salesLoading.value = false; |
| | | }, 500); |
| | | }; |
| | | |
| | | const getLastPeriod = (period) => { |
| | | const [year, month] = period.split("-").map(Number); |
| | | if (month === 1) { |
| | | return `${year - 1}-12`; |
| | | } |
| | | return `${year}-${String(month - 1).padStart(2, "0")}`; |
| | | }; |
| | | |
| | | const calculateSummary = () => { |
| | | let receivable = 0; |
| | | let receipt = 0; |
| | | |
| | | selectedSales.value.forEach(item => { |
| | | if (item.type === "åºåº") { |
| | | receivable += item.amount; |
| | | } else if (item.type === "éè´§") { |
| | | receivable -= item.amount; |
| | | } else if (item.type === "æ¶æ¬¾") { |
| | | receipt += item.amount; |
| | | } |
| | | }); |
| | | |
| | | generateForm.currentReceivable = receivable; |
| | | generateForm.currentReceipt = receipt; |
| | | }; |
| | | |
| | | const handleSalesSelectionChange = (selection) => { |
| | | selectedSales.value = selection; |
| | | calculateSummary(); |
| | | }; |
| | | |
| | | const confirmGenerate = () => { |
| | | const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1; |
| | | const customer = customerList[Math.floor(Math.random() * customerList.length)]; |
| | | const endBalance = calculateEndBalance(generateForm.beginBalance, generateForm.currentReceivable, generateForm.currentReceipt); |
| | | |
| | | mockData.unshift({ |
| | | id: newId, |
| | | statementCode: "DZ" + Date.now(), |
| | | customerId: customer.id, |
| | | customerName: customer.name, |
| | | period: "2024-03", |
| | | beginBalance: Math.floor(Math.random() * 10000), |
| | | currentReceivable: Math.floor(Math.random() * 20000), |
| | | currentReceipt: Math.floor(Math.random() * 15000), |
| | | endBalance: Math.floor(Math.random() * 20000), |
| | | customerId: generateForm.customerId, |
| | | customerName: generateForm.customerName, |
| | | period: generateForm.period, |
| | | beginBalance: generateForm.beginBalance, |
| | | currentReceivable: generateForm.currentReceivable, |
| | | currentReceipt: generateForm.currentReceipt, |
| | | endBalance, |
| | | }); |
| | | |
| | | generateDialogVisible.value = false; |
| | | ElMessage.success("对账åçææå"); |
| | | getTableData(); |
| | | }; |
| | | |
| | | const viewDetail = (row) => { |
| | | currentCustomer.value = row.customerName; |
| | | currentPeriod.value = row.period; |
| | | |
| | | const saleOutAmount = Math.floor(row.currentReceivable * 0.6); |
| | | const returnAmount = Math.floor(row.currentReceivable * 0.1); |
| | | const firstReceipt = Math.floor(row.currentReceipt * 0.4); |
| | | const secondReceipt = row.currentReceipt - firstReceipt; |
| | | |
| | | let runningBalance = row.beginBalance; |
| | | |
| | | detailData.value = [ |
| | | { date: row.period + "-01", type: "æå", code: "-", debit: 0, credit: 0, balance: row.beginBalance, remark: "æåä½é¢" }, |
| | | { date: row.period + "-05", type: "åºåº", code: "CK2024001", debit: 5000, credit: 0, balance: row.beginBalance + 5000, remark: "" }, |
| | | { date: row.period + "-10", type: "æ¶æ¬¾", code: "SK2024001", debit: 0, credit: 3000, balance: row.beginBalance + 2000, remark: "" }, |
| | | { date: row.period + "-15", type: "åºåº", code: "CK2024002", debit: 8000, credit: 0, balance: row.beginBalance + 10000, remark: "" }, |
| | | { date: row.period + "-20", type: "éè´§", code: "TH2024001", debit: 0, credit: 2000, balance: row.beginBalance + 8000, remark: "" }, |
| | | { date: row.period + "-25", type: "æ¶æ¬¾", code: "SK2024002", credit: row.currentReceipt - 3000, balance: row.endBalance, remark: "" }, |
| | | { date: row.period + "-01", type: "æå", code: "-", debit: 0, credit: 0, balance: runningBalance, remark: "æåä½é¢" }, |
| | | { date: row.period + "-05", type: "åºåº", code: "CK2024001", debit: saleOutAmount, credit: 0, balance: runningBalance += saleOutAmount, remark: "éå®åºåº" }, |
| | | { date: row.period + "-10", type: "æ¶æ¬¾", code: "SK2024001", debit: 0, credit: firstReceipt, balance: runningBalance -= firstReceipt, remark: "客æ·å款" }, |
| | | { date: row.period + "-15", type: "åºåº", code: "CK2024002", debit: row.currentReceivable - saleOutAmount - returnAmount, credit: 0, balance: runningBalance += (row.currentReceivable - saleOutAmount - returnAmount), remark: "éå®åºåº" }, |
| | | { date: row.period + "-20", type: "éè´§", code: "TH2024001", debit: 0, credit: returnAmount, balance: runningBalance -= returnAmount, remark: "éå®éè´§" }, |
| | | { date: row.period + "-25", type: "æ¶æ¬¾", code: "SK2024002", debit: 0, credit: secondReceipt, balance: runningBalance -= secondReceipt, remark: "客æ·å款" }, |
| | | ]; |
| | | |
| | | detailDialogVisible.value = true; |
| | | }; |
| | | |
| | |
| | | margin: 0; |
| | | } |
| | | } |
| | | |
| | | .sales-section { |
| | | margin-top: 20px; |
| | | |
| | | .section-title { |
| | | font-size: 16px; |
| | | font-weight: bold; |
| | | margin-bottom: 15px; |
| | | padding-left: 10px; |
| | | border-left: 4px solid #409eff; |
| | | } |
| | | } |
| | | |
| | | .summary-row { |
| | | display: flex; |
| | | justify-content: space-around; |
| | | padding: 15px; |
| | | background-color: #f5f7fa; |
| | | border-radius: 4px; |
| | | margin-top: 15px; |
| | | |
| | | span { |
| | | font-size: 14px; |
| | | |
| | | strong { |
| | | font-size: 16px; |
| | | margin-left: 5px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .empty-tip { |
| | | margin-top: 30px; |
| | | } |
| | | </style> |
| | |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button type="primary" @click="add" icon="Plus">æ°å¢åºåº</el-button> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="100px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "éå®åºåº", |
| | |
| | | <div class="actions"> |
| | | <div></div> |
| | | <div> |
| | | <el-button type="primary" @click="add" icon="Plus">æ°å¢éè´§</el-button> |
| | | <el-button @click="handleOut" icon="Download">导åº</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="800px" append-to-body> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="800px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-form> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm">ç¡®å®</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "éå®éè´§", |
| | |
| | | <template> |
| | | <el-dialog v-model="visible" title="æ¶æ¬¾/鿬¾" width="90%" append-to-body> |
| | | <FormDialog v-model="visible" title="æ¶æ¬¾/鿬¾" width="90%" @confirm="submit" @cancel="visible=false"> |
| | | <div class="section"> |
| | | <div class="section-title descriptions">åºç¡èµæ</div> |
| | | <el-form :model="form" label-width="100px"> |
| | |
| | | <el-button type="primary" @click="submit">确认</el-button> |
| | | <el-button @click="visible=false">åæ¶</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue'; |
| | | import { getToken } from '@/utils/auth'; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | const visible = ref(false); |
| | | const form = ref({ |
| | |
| | | </PIMTable> |
| | | </div> |
| | | |
| | | <el-dialog :title="dialogTitle" v-model="dialogVisible" width="900px" append-to-body> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="100px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="8"> |
| | | <el-form-item label="åè¯åå·" prop="voucherNo"> |
| | | <el-input v-model="form.voucherNo" placeholder="ç³»ç»èªå¨çæ" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="åè¯æ¥æ" prop="voucherDate"> |
| | | <el-date-picker v-model="form.voucherDate" type="date" placeholder="éæ©æ¥æ" value-format="YYYY-MM-DD" style="width: 100%;" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="éä»¶å¼ æ°" prop="attachmentCount"> |
| | | <el-input-number v-model="form.attachmentCount" :min="0" style="width: 100%;" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-form-item label="åè¯åå½" prop="entries"> |
| | | <el-table :data="form.entries" border style="width: 100%"> |
| | | <el-table-column type="index" label="åºå·" width="60" /> |
| | | <el-table-column prop="subjectCode" label="ç§ç®ç¼ç " width="120"> |
| | | <template #default="{ $index }"> |
| | | <el-select v-model="form.entries[$index].subjectCode" placeholder="éæ©ç§ç®" filterable style="width: 100%;" @change="(val) => handleSubjectChange(val, $index)"> |
| | | <el-option v-for="item in subjectList" :key="item.code" :label="item.code" :value="item.code" /> |
| | | </el-select> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="subjectName" label="ç§ç®åç§°" width="150"> |
| | | <template #default="{ $index }"> |
| | | <el-input v-model="form.entries[$index].subjectName" disabled /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="summary" label="æè¦"> |
| | | <template #default="{ $index }"> |
| | | <el-input v-model="form.entries[$index].summary" placeholder="请è¾å
¥æè¦" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="debit" label="åæ¹éé¢" width="130"> |
| | | <template #default="{ $index }"> |
| | | <el-input-number v-model="form.entries[$index].debit" :min="0" :precision="2" style="width: 100%;" @change="calculateTotal" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="credit" label="è´·æ¹éé¢" width="130"> |
| | | <template #default="{ $index }"> |
| | | <el-input-number v-model="form.entries[$index].credit" :min="0" :precision="2" style="width: 100%;" @change="calculateTotal" /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" width="80"> |
| | | <template #default="{ $index }"> |
| | | <el-button type="danger" link @click="removeEntry($index)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <div style="display: flex; justify-content: space-between; margin-top: 10px;"> |
| | | <el-button type="primary" link @click="addEntry">+ æ·»å åå½</el-button> |
| | | <div> |
| | | <span style="margin-right: 20px;">å计: åæ¹ <span :class="totalDebitEntry === totalCreditEntry ? 'text-success' : 'text-danger'">Â¥{{ formatMoney(totalDebitEntry) }}</span></span> |
| | | <span>è´·æ¹ <span :class="totalDebitEntry === totalCreditEntry ? 'text-success' : 'text-danger'">Â¥{{ formatMoney(totalCreditEntry) }}</span></span> |
| | | <FormDialog :title="dialogTitle" v-model="dialogVisible" width="1200px" @confirm="submitForm" @cancel="dialogVisible = false"> |
| | | <div class="voucher-container"> |
| | | <div class="voucher-header"> |
| | | <h2 class="voucher-title">è®°è´¦åè¯</h2> |
| | | <div class="voucher-period">{{ form.voucherDate ? form.voucherDate.substring(0, 7) + 'æ' : '' }}</div> |
| | | </div> |
| | | <el-form :model="form" :rules="rules" ref="formRef" label-width="0"> |
| | | <div class="voucher-info"> |
| | | <div class="voucher-no-section"> |
| | | <span class="label">åè¯åï¼</span> |
| | | <el-select v-model="form.voucherPrefix" style="width: 70px;"> |
| | | <el-option label="è®°" value="è®°" /> |
| | | </el-select> |
| | | <el-input v-model="form.voucherNum" style="width: 60px;" /> |
| | | <span class="label" style="margin-left: 5px;">å·</span> |
| | | </div> |
| | | <div class="voucher-date-section"> |
| | | <span class="label">æ¥æï¼</span> |
| | | <el-date-picker v-model="form.voucherDate" type="date" placeholder="éæ©æ¥æ" value-format="YYYY-MM-DD" style="width: 140px;" /> |
| | | </div> |
| | | <div class="voucher-attachment-section"> |
| | | <span class="label">éä»¶ï¼</span> |
| | | <el-input-number v-model="form.attachmentCount" :min="0" :controls="false" style="width: 60px;" /> |
| | | <span class="label" style="margin-left: 5px;">å¼ </span> |
| | | <el-button type="primary" link style="margin-left: 10px;">ä¸ä¼ æä»¶</el-button> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | <el-form-item label="å¶å人" prop="creator"> |
| | | <el-input v-model="form.creator" disabled /> |
| | | </el-form-item> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请è¾å
¥å¤æ³¨" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | <div class="voucher-table"> |
| | | <table class="accounting-voucher"> |
| | | <thead> |
| | | <tr> |
| | | <th class="col-summary" rowspan="2">æè¦</th> |
| | | <th class="col-subject" rowspan="2">ä¼è®¡ç§ç®</th> |
| | | <th class="col-debit-header" colspan="11">åæ¹</th> |
| | | <th class="col-credit-header" colspan="11">è´·æ¹</th> |
| | | <th class="col-action" rowspan="2">æä½</th> |
| | | </tr> |
| | | <tr class="amount-header"> |
| | | <th>亿</th> |
| | | <th>å</th> |
| | | <th>ç¾</th> |
| | | <th>å</th> |
| | | <th>ä¸</th> |
| | | <th>å</th> |
| | | <th>ç¾</th> |
| | | <th>å</th> |
| | | <th>å
</th> |
| | | <th>è§</th> |
| | | <th>å</th> |
| | | <th>亿</th> |
| | | <th>å</th> |
| | | <th>ç¾</th> |
| | | <th>å</th> |
| | | <th>ä¸</th> |
| | | <th>å</th> |
| | | <th>ç¾</th> |
| | | <th>å</th> |
| | | <th>å
</th> |
| | | <th>è§</th> |
| | | <th>å</th> |
| | | </tr> |
| | | </thead> |
| | | <tbody> |
| | | <tr v-for="(entry, rowIndex) in form.entries" :key="rowIndex" @click="selectRow(rowIndex)" :class="{ 'selected-row': selectedRowIndex === rowIndex }"> |
| | | <td class="col-summary"> |
| | | <el-input v-model="entry.summary" placeholder="请è¾å
¥æè¦" @focus="selectRow(rowIndex)" /> |
| | | </td> |
| | | <td class="col-subject"> |
| | | <el-select v-model="entry.subjectCode" placeholder="éæ©ç§ç®" filterable @change="(val) => handleSubjectChange(val, rowIndex)" @focus="selectRow(rowIndex)"> |
| | | <el-option v-for="item in subjectList" :key="item.code" :label="item.code + item.name" :value="item.code" /> |
| | | </el-select> |
| | | <div class="subject-name">{{ entry.subjectName }}</div> |
| | | </td> |
| | | <!-- åæ¹11å --> |
| | | <template v-if="editingCell.row === rowIndex && editingCell.type === 'debit'"> |
| | | <td colspan="11" class="debit-input-cell"> |
| | | <el-input-number ref="amountInputRef" v-model="entry.debit" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" /> |
| | | </td> |
| | | </template> |
| | | <template v-else> |
| | | <td v-for="(digit, dIndex) in getAmountDigits(entry.debit, 11)" :key="'debit-'+dIndex" class="amount-cell debit-cell" @click="openAmountInput(rowIndex, 'debit')"> |
| | | <span :class="{ 'text-primary': digit !== '', 'zero': digit === '' }">{{ digit || '' }}</span> |
| | | </td> |
| | | </template> |
| | | <!-- è´·æ¹11å --> |
| | | <template v-if="editingCell.row === rowIndex && editingCell.type === 'credit'"> |
| | | <td colspan="11" class="credit-input-cell"> |
| | | <el-input-number ref="amountInputRef" v-model="entry.credit" :min="0" :precision="2" :controls="false" size="small" @blur="finishEdit" class="full-width-input" /> |
| | | </td> |
| | | </template> |
| | | <template v-else> |
| | | <td v-for="(digit, dIndex) in getAmountDigits(entry.credit, 11)" :key="'credit-'+dIndex" class="amount-cell credit-cell" @click="openAmountInput(rowIndex, 'credit')"> |
| | | <span :class="{ 'text-danger': digit !== '', 'zero': digit === '' }">{{ digit || '' }}</span> |
| | | </td> |
| | | </template> |
| | | <td class="col-action"> |
| | | <el-button type="danger" link size="small" @click="removeEntry(rowIndex)" icon="Delete" :disabled="form.entries.length <= 2">å é¤</el-button> |
| | | </td> |
| | | </tr> |
| | | <tr class="total-row"> |
| | | <td class="col-summary" colspan="2" style="text-align: center; font-weight: bold;">å计ï¼</td> |
| | | <td v-for="(digit, index) in getAmountDigits(totalDebitEntry, 11)" :key="'total-debit-'+index" class="amount-cell total-debit-cell"> |
| | | <span :class="{ 'text-primary': digit !== '' }">{{ digit }}</span> |
| | | </td> |
| | | <td v-for="(digit, index) in getAmountDigits(totalCreditEntry, 11)" :key="'total-credit-'+index" class="amount-cell total-credit-cell"> |
| | | <span :class="{ 'text-danger': digit !== '' }">{{ digit }}</span> |
| | | </td> |
| | | <td class="col-action"></td> |
| | | </tr> |
| | | </tbody> |
| | | </table> |
| | | </div> |
| | | <div class="voucher-toolbar"> |
| | | <el-button type="primary" link @click="addEntry" icon="Plus">æ°å¢è¡</el-button> |
| | | </div> |
| | | <div class="voucher-footer"> |
| | | <div class="creator-section"> |
| | | <span class="label">å¶å人ï¼{{ form.creator }}</span> |
| | | </div> |
| | | </div> |
| | | </el-form> |
| | | </div> |
| | | <template #footer> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | <el-button type="primary" @click="submitForm" :disabled="totalDebitEntry !== totalCreditEntry">ç¡®å®</el-button> |
| | | <div> |
| | | <el-button type="primary" @click="submitForm" :disabled="!isBalanced">ä¿å</el-button> |
| | | <el-button @click="dialogVisible = false">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </FormDialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted, computed } from "vue"; |
| | | import { ref, reactive, onMounted, computed, nextTick } from "vue"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | |
| | | defineOptions({ |
| | | name: "åè¯ç®¡ç", |
| | |
| | | |
| | | const form = reactive({ |
| | | voucherNo: "", |
| | | voucherPrefix: "è®°", |
| | | voucherNum: "", |
| | | voucherDate: "", |
| | | attachmentCount: 0, |
| | | entries: [], |
| | | creator: "å¼ ä¸", |
| | | remark: "", |
| | | }); |
| | | |
| | | const selectedRowIndex = ref(-1); |
| | | const editingCell = reactive({ |
| | | row: -1, |
| | | type: "", |
| | | }); |
| | | const amountInputRef = ref(null); |
| | | |
| | | const isBalanced = computed(() => { |
| | | return totalDebitEntry.value === totalCreditEntry.value && totalDebitEntry.value > 0; |
| | | }); |
| | | |
| | | const rules = { |
| | |
| | | form.entries.push({ subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }); |
| | | }; |
| | | |
| | | const selectRow = (index) => { |
| | | selectedRowIndex.value = index; |
| | | }; |
| | | |
| | | const openAmountInput = (index, type) => { |
| | | editingCell.row = index; |
| | | editingCell.type = type; |
| | | nextTick(() => { |
| | | if (amountInputRef.value) { |
| | | amountInputRef.value.focus(); |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | const finishEdit = () => { |
| | | editingCell.row = -1; |
| | | editingCell.type = ""; |
| | | }; |
| | | |
| | | const getAmountDigits = (amount, length) => { |
| | | if (!amount || amount === 0) { |
| | | return new Array(length).fill(''); |
| | | } |
| | | |
| | | const amountStr = Number(amount).toFixed(2); |
| | | const [intPart, decPart] = amountStr.split('.'); |
| | | const fullAmount = intPart + decPart; |
| | | |
| | | // 左填å
0å°æå®é¿åº¦ |
| | | const paddedAmount = fullAmount.padStart(length, '0'); |
| | | const digits = paddedAmount.split(''); |
| | | |
| | | // æ¾å°ç¬¬ä¸ä¸ªéé¶æ°åçä½ç½® |
| | | let firstNonZeroIndex = 0; |
| | | for (let i = 0; i < digits.length; i++) { |
| | | if (digits[i] !== '0') { |
| | | firstNonZeroIndex = i; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | // åªéèå导é¶ï¼ç¬¬ä¸ä¸ªéé¶æ°åä¹åçé¶ï¼ |
| | | return digits.map((d, index) => { |
| | | if (index < firstNonZeroIndex) { |
| | | return ''; // å坼鶿¾ç¤ºä¸ºç©º |
| | | } |
| | | return d; // ä¿çéé¢ä¸çé¶ |
| | | }); |
| | | }; |
| | | |
| | | const removeEntry = (index) => { |
| | | form.entries.splice(index, 1); |
| | | calculateTotal(); |
| | |
| | | const add = () => { |
| | | isEdit.value = false; |
| | | dialogTitle.value = "æ°å¢åè¯"; |
| | | const nextNum = String(mockData.length + 1).padStart(2, "0"); |
| | | Object.assign(form, { |
| | | voucherNo: "è®°-" + String(mockData.length + 1).padStart(4, "0"), |
| | | voucherNo: "è®°-" + nextNum, |
| | | voucherPrefix: "è®°", |
| | | voucherNum: nextNum, |
| | | voucherDate: new Date().toISOString().split('T')[0], |
| | | attachmentCount: 0, |
| | | entries: [{ subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }], |
| | | entries: [ |
| | | { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }, |
| | | { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }, |
| | | { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }, |
| | | { subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }, |
| | | ], |
| | | creator: "å¼ ä¸", |
| | | remark: "", |
| | | }); |
| | | selectedRowIndex.value = 0; |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | |
| | | isEdit.value = true; |
| | | currentId.value = row.id; |
| | | dialogTitle.value = "ç¼è¾åè¯"; |
| | | Object.assign(form, row); |
| | | const parts = row.voucherNo.split('-'); |
| | | Object.assign(form, { |
| | | ...row, |
| | | voucherPrefix: parts[0] || 'è®°', |
| | | voucherNum: parts[1] || '', |
| | | }); |
| | | if (form.entries.length < 4) { |
| | | while (form.entries.length < 4) { |
| | | form.entries.push({ subjectCode: "", subjectName: "", summary: "", debit: 0, credit: 0 }); |
| | | } |
| | | } |
| | | selectedRowIndex.value = 0; |
| | | dialogVisible.value = true; |
| | | }; |
| | | |
| | |
| | | const submitForm = () => { |
| | | formRef.value.validate((valid) => { |
| | | if (valid) { |
| | | if (totalDebitEntry.value !== totalCreditEntry.value) { |
| | | if (!isBalanced.value) { |
| | | ElMessage.error("åè´·ä¸å¹³è¡¡ï¼è¯·æ£æ¥åå½"); |
| | | return; |
| | | } |
| | | const summary = form.entries.find(e => e.debit > 0)?.summary || ""; |
| | | |
| | | const validEntries = form.entries.filter(e => e.subjectCode && (e.debit > 0 || e.credit > 0)); |
| | | const summary = validEntries.find(e => e.debit > 0)?.summary || ""; |
| | | |
| | | const voucherNo = `${form.voucherPrefix}-${form.voucherNum}`; |
| | | const dataToSave = { |
| | | ...form, |
| | | voucherNo, |
| | | summary, |
| | | debit: totalDebitEntry.value, |
| | | credit: totalCreditEntry.value, |
| | | entries: validEntries, |
| | | }; |
| | | |
| | | if (isEdit.value) { |
| | | const index = mockData.findIndex(item => item.id === currentId.value); |
| | | if (index !== -1) { |
| | | mockData[index] = { ...mockData[index], ...form, summary, debit: totalDebitEntry.value, credit: totalCreditEntry.value }; |
| | | mockData[index] = { ...mockData[index], ...dataToSave }; |
| | | } |
| | | ElMessage.success("ç¼è¾æå"); |
| | | } else { |
| | | const newId = mockData.length > 0 ? Math.max(...mockData.map(item => item.id)) + 1 : 1; |
| | | mockData.push({ id: newId, ...form, summary, debit: totalDebitEntry.value, credit: totalCreditEntry.value, status: "unposted" }); |
| | | mockData.push({ id: newId, ...dataToSave, status: "unposted" }); |
| | | ElMessage.success("æ°å¢æå"); |
| | | } |
| | | dialogVisible.value = false; |
| | |
| | | color: #f56c6c; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .text-primary { |
| | | color: #409eff; |
| | | } |
| | | |
| | | .voucher-container { |
| | | background: #fff; |
| | | padding: 20px; |
| | | } |
| | | |
| | | .voucher-header { |
| | | text-align: center; |
| | | margin-bottom: 15px; |
| | | |
| | | .voucher-title { |
| | | font-size: 22px; |
| | | font-weight: bold; |
| | | margin: 0 0 5px 0; |
| | | color: #303133; |
| | | } |
| | | |
| | | .voucher-period { |
| | | font-size: 14px; |
| | | color: #909399; |
| | | } |
| | | } |
| | | |
| | | .voucher-info { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 15px; |
| | | padding: 0 10px; |
| | | |
| | | .label { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | |
| | | .voucher-no-section, |
| | | .voucher-date-section, |
| | | .voucher-attachment-section { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | } |
| | | |
| | | .voucher-table { |
| | | border: 1px solid #dcdfe6; |
| | | border-right: none; |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .accounting-voucher { |
| | | width: 100%; |
| | | border-collapse: collapse; |
| | | font-size: 13px; |
| | | |
| | | th, |
| | | td { |
| | | border: 1px solid #dcdfe6; |
| | | text-align: center; |
| | | padding: 0; |
| | | height: 36px; |
| | | } |
| | | |
| | | & th:last-child, |
| | | & td:last-child { |
| | | border-right: none !important; |
| | | } |
| | | |
| | | thead { |
| | | background-color: #f5f7fa; |
| | | |
| | | th { |
| | | font-weight: normal; |
| | | color: #606266; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .col-summary, |
| | | .col-subject { |
| | | font-weight: bold; |
| | | font-size: 13px; |
| | | } |
| | | |
| | | .col-debit-header, |
| | | .col-credit-header { |
| | | background-color: #ecf5ff; |
| | | color: #409eff; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | |
| | | .amount-header { |
| | | th { |
| | | font-size: 11px; |
| | | padding: 2px 0; |
| | | background-color: #f5f7fa; |
| | | } |
| | | } |
| | | |
| | | .col-summary { |
| | | width: 160px; |
| | | min-width: 160px; |
| | | } |
| | | |
| | | .col-subject { |
| | | width: 180px; |
| | | min-width: 180px; |
| | | } |
| | | |
| | | .col-action { |
| | | width: 60px; |
| | | min-width: 60px; |
| | | text-align: center; |
| | | } |
| | | |
| | | .amount-cell { |
| | | width: 24px; |
| | | min-width: 24px; |
| | | max-width: 24px; |
| | | padding: 0; |
| | | font-size: 13px; |
| | | font-family: 'Courier New', monospace; |
| | | cursor: pointer; |
| | | text-align: center; |
| | | |
| | | &:hover { |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | span { |
| | | display: block; |
| | | width: 100%; |
| | | height: 100%; |
| | | line-height: 36px; |
| | | |
| | | &.zero { |
| | | color: #c0c4cc; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .debit-input-cell, |
| | | .credit-input-cell { |
| | | padding: 0; |
| | | background-color: #ecf5ff; |
| | | |
| | | .full-width-input { |
| | | width: 100%; |
| | | |
| | | :deep(.el-input__wrapper) { |
| | | padding: 0 10px; |
| | | box-shadow: none; |
| | | background-color: transparent; |
| | | } |
| | | |
| | | input { |
| | | text-align: right; |
| | | font-size: 14px; |
| | | height: 34px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | tbody { |
| | | tr { |
| | | &:hover { |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | &.selected-row { |
| | | background-color: #ecf5ff; |
| | | } |
| | | } |
| | | |
| | | td { |
| | | .el-input { |
| | | .el-input__wrapper { |
| | | box-shadow: none; |
| | | padding: 0 5px; |
| | | } |
| | | |
| | | input { |
| | | text-align: center; |
| | | height: 34px; |
| | | } |
| | | } |
| | | |
| | | .el-select { |
| | | width: 100%; |
| | | |
| | | .el-input__wrapper { |
| | | box-shadow: none; |
| | | } |
| | | |
| | | input { |
| | | text-align: center; |
| | | height: 34px; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .col-summary { |
| | | .el-input input { |
| | | text-align: left; |
| | | padding-left: 10px; |
| | | } |
| | | } |
| | | |
| | | .col-subject { |
| | | position: relative; |
| | | |
| | | .el-select { |
| | | .el-input input { |
| | | font-size: 12px; |
| | | } |
| | | } |
| | | |
| | | .subject-name { |
| | | font-size: 11px; |
| | | color: #909399; |
| | | margin-top: 2px; |
| | | line-height: 1.2; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .total-row { |
| | | background-color: #fdf6ec; |
| | | |
| | | td { |
| | | font-weight: bold; |
| | | } |
| | | |
| | | .total-cell { |
| | | background-color: #fdf6ec; |
| | | font-weight: bold; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .voucher-toolbar { |
| | | display: flex; |
| | | justify-content: flex-start; |
| | | padding: 10px 0; |
| | | margin-top: 5px; |
| | | } |
| | | |
| | | .voucher-footer { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | padding: 0 10px; |
| | | margin-top: 10px; |
| | | |
| | | .creator-section { |
| | | .label { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | } |
| | | } |
| | | } |
| | | |
| | | :deep(.el-dialog__body) { |
| | | padding: 10px 20px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <div class="search_form" style="margin-bottom: 10px;"> |
| | | <div> |
| | | <span class="search_title ml10">åºåºæ¥æï¼</span> |
| | | <el-date-picker |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <div class="search_form" style="margin-bottom: 10px;"> |
| | | <div> |
| | | <span class="search_title ml10">å
¥åºæ¥æï¼</span> |
| | | <el-date-picker v-model="searchForm.timeStr" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <div class="search_form mb10"> |
| | | <div> |
| | | <span class="search_title ml10">产å大类ï¼</span> |
| | | <el-input v-model="searchForm.productName" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">åæ¾å£åº¦ï¼</span> |
| | | <el-select |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">å§åï¼</span> |
| | | <el-input v-model="searchForm.staffName" style="width: 240px" placeholder="请è¾å
¥å§åæç´¢" @change="handleQuery" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">å§åï¼</span> |
| | | <el-input |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">å§åï¼</span> |
| | | <el-input |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">主é¢ï¼</span> |
| | | <el-input |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form" style="margin-bottom: 20px;"> |
| | | <div> |
| | | <span class="search_title">ä¾åºååç§°:</span> |
| | | <el-input |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {Search, Delete} from "@element-plus/icons-vue"; |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue'; |
| | | import FileListDialog from '@/components/Dialog/FileListDialog.vue'; |
| | | import { getToken } from "@/utils/auth"; |
| | |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .app-container { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .page-header { |
| | | text-align: center; |
| | | margin-bottom: 20px; |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search-bar"> |
| | | <el-form :model="searchForm" |
| | | inline> |
| | | <el-form-item label="æ¥æåºé´:"> |
| | | <el-date-picker v-model="searchForm.dateRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | value-format="YYYY-MM-DD" |
| | | style="width: 240px" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | icon="Search" |
| | | @click="handleQuery">æç´¢</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <div class="stats-grid" |
| | | v-loading="loading"> |
| | | <el-row :gutter="16" |
| | | v-if="statsData.length > 0"> |
| | | <el-col v-for="(item, index) in statsData" |
| | | :key="index" |
| | | :xs="24" |
| | | :sm="12" |
| | | :md="8" |
| | | :lg="4.8" |
| | | :xl="4.8" |
| | | class="mb-16"> |
| | | <div class="stats-card"> |
| | | <div class="card-header"> |
| | | <span class="process-name">{{ item.name }}</span> |
| | | <div class="header-stats"> |
| | | <div class="stat-row"> |
| | | <span class="label">è®¡åæ°</span> |
| | | <span class="value">{{ item.planned }}</span> |
| | | </div> |
| | | <div class="stat-row"> |
| | | <span class="label">è¯åæ°</span> |
| | | <span class="value">{{ item.good }}</span> |
| | | </div> |
| | | <div class="stat-row"> |
| | | <span class="label">ä¸è¯åæ°</span> |
| | | <span class="value">{{ item.bad }}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="card-body"> |
| | | <div class="main-stat"> |
| | | <div class="big-number">{{ item.total }}</div> |
| | | <div class="sub-label">çäº§ä»»å¡æ°</div> |
| | | </div> |
| | | </div> |
| | | <div class="card-footer"> |
| | | <div class="progress-info"> |
| | | <span class="progress-label">è¿åº¦:</span> |
| | | <el-progress :percentage="Math.min(item.percentage, 100)" |
| | | :color="getProgressColor(item.percentage)" |
| | | :stroke-width="10" |
| | | :show-text="false" |
| | | class="flex-1" /> |
| | | <span class="percentage-text">{{ item.percentage }}%</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </el-col> |
| | | </el-row> |
| | | <el-empty v-else |
| | | description="ææ æ°æ®" /> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { reactive, ref, onMounted } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import { getOperationStatistics } from "@/api/productionManagement/workOrder.js"; |
| | | |
| | | const loading = ref(false); |
| | | const searchForm = reactive({ |
| | | dateRange: [], |
| | | }); |
| | | |
| | | const statsData = ref([]); |
| | | |
| | | const getProgressColor = percentage => { |
| | | if (percentage >= 100) return "#67c23a"; |
| | | if (percentage >= 50) return "#409eff"; |
| | | if (percentage >= 25) return "#e6a23c"; |
| | | return "red"; |
| | | }; |
| | | |
| | | const getList = () => { |
| | | loading.value = true; |
| | | const params = { |
| | | startDate: searchForm.dateRange?.[0] || "", |
| | | endDate: searchForm.dateRange?.[1] || "", |
| | | }; |
| | | getOperationStatistics(params) |
| | | .then(res => { |
| | | // æ ¹æ®å®é
æ¥å£è¿åçåæ®µè¿è¡æ å° |
| | | statsData.value = (res.data || []).map(item => ({ |
| | | name: item.operationName || "-", |
| | | total: item.productionTaskCount || 0, |
| | | planned: item.planQuantity || 0, |
| | | good: item.goodQuantity || 0, |
| | | bad: item.scrapQty || 0, |
| | | percentage: Number(item.completionStatus || 0), |
| | | })); |
| | | }) |
| | | .finally(() => { |
| | | loading.value = false; |
| | | }); |
| | | }; |
| | | |
| | | const handleQuery = () => { |
| | | getList(); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .app-container { |
| | | padding: 20px; |
| | | background-color: #f0f2f5; |
| | | min-height: calc(100vh - 84px); |
| | | } |
| | | |
| | | .search-bar { |
| | | background: #fff; |
| | | padding: 15px 20px 0; |
| | | border-radius: 4px; |
| | | margin-bottom: 20px; |
| | | box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .mb-16 { |
| | | margin-bottom: 16px; |
| | | } |
| | | |
| | | // 模æ lg="4.8" å 为 element 䏿¯æ 24/5 |
| | | @media only screen and (min-width: 1200px) { |
| | | .el-col-lg-4-8 { |
| | | width: 20%; |
| | | max-width: 20%; |
| | | flex: 0 0 20%; |
| | | } |
| | | } |
| | | |
| | | .stats-card { |
| | | background: #fff; |
| | | border-radius: 8px; |
| | | padding: 16px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05); |
| | | transition: transform 0.3s; |
| | | |
| | | &:hover { |
| | | transform: translateY(-2px); |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: flex-start; |
| | | margin-bottom: 12px; |
| | | |
| | | .process-name { |
| | | background-color: #e6f7ff; |
| | | color: #1890ff; |
| | | padding: 2px 8px; |
| | | border-radius: 4px; |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .header-stats { |
| | | text-align: right; |
| | | |
| | | .stat-row { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | align-items: center; |
| | | gap: 8px; |
| | | margin-bottom: 2px; |
| | | |
| | | .label { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | } |
| | | |
| | | .value { |
| | | font-size: 13px; |
| | | color: #303133; |
| | | font-weight: bold; |
| | | min-width: 24px; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | .card-body { |
| | | padding: 10px 0; |
| | | |
| | | .main-stat { |
| | | .big-number { |
| | | font-size: 28px; |
| | | font-weight: bold; |
| | | color: #303133; |
| | | line-height: 1; |
| | | } |
| | | |
| | | .sub-label { |
| | | font-size: 14px; |
| | | color: #606266; |
| | | margin-top: 8px; |
| | | font-weight: 500; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .card-footer { |
| | | margin-top: 16px; |
| | | |
| | | .progress-info { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | |
| | | .progress-label { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .flex-1 { |
| | | flex: 1; |
| | | } |
| | | |
| | | .percentage-text { |
| | | font-size: 12px; |
| | | color: #606266; |
| | | min-width: 45px; |
| | | text-align: right; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // ä¿®æ£ el-col å¸å±éé
5 å |
| | | :deep(.el-row) { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | } |
| | | |
| | | @media only screen and (min-width: 1200px) { |
| | | .el-col-lg-4\.8 { |
| | | flex: 0 0 20%; |
| | | max-width: 20%; |
| | | } |
| | | } |
| | | </style> |
| | |
| | | :color="progressColor(toProgressPercentage(row?.completionStatus))" |
| | | :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" /> |
| | | </template> |
| | | <template #processRouteStatus="{ row }"> |
| | | <div v-if="row.processRouteStatus && row.processRouteStatus.length" |
| | | class="process-progress-container"> |
| | | <div v-for="(item, index) in row.processRouteStatus" |
| | | :key="index" |
| | | class="process-step"> |
| | | <div class="step-content"> |
| | | <div class="step-circle" |
| | | :class="{ 'is-completed': item.percentage >= 100 }"> |
| | | <span class="step-percentage" |
| | | :style="{ color: item.percentage >= 70 ? item.percentage >= 100 ? '#67c23a' : '#f56c6c' : '#000' }">{{ item.percentage }}%</span> |
| | | </div> |
| | | <div class="step-name">{{ item.name }}</div> |
| | | </div> |
| | | <div v-if="index < row.processRouteStatus.length - 1" |
| | | class="step-line"></div> |
| | | </div> |
| | | </div> |
| | | <span v-else>-</span> |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | <el-dialog v-model="bindRouteDialogVisible" |
| | |
| | | getProductOrderSource, |
| | | updateProductOrder, |
| | | } from "@/api/productionManagement/productionOrder.js"; |
| | | import { productWorkOrderPage } from "@/api/productionManagement/workOrder.js"; |
| | | import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js"; |
| | | import MaterialLedgerDialog from "@/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue"; |
| | | import MaterialDetailDialog from "@/views/productionManagement/productionOrder/components/MaterialDetailDialog.vue"; |
| | |
| | | total: 0, |
| | | }); |
| | | |
| | | const tableColumn = ref([ |
| | | const processColumnWidth = computed(() => { |
| | | if (!tableData.value || tableData.value.length === 0) return "200px"; |
| | | const maxProcesses = Math.max( |
| | | ...tableData.value.map(row => row.processRouteStatus?.length || 0) |
| | | ); |
| | | if (maxProcesses === 0) return "100px"; |
| | | // æ¯ä¸ªå·¥åºåå 36px + çº¿æ¡ 30px = 66pxï¼é¢å¤å 60px è¾¹è·åæåç©ºé´ |
| | | return `${maxProcesses * 66 + 60}px`; |
| | | }); |
| | | |
| | | const tableColumn = computed(() => [ |
| | | { |
| | | label: "ç产订åå·", |
| | | prop: "npsNo", |
| | |
| | | { |
| | | label: "宿æ°é", |
| | | prop: "completeQuantity", |
| | | }, |
| | | { |
| | | label: "å·¥åºç产è¿åº¦", |
| | | prop: "processRouteStatus", |
| | | dataType: "slot", |
| | | slot: "processRouteStatus", |
| | | width: processColumnWidth.value, |
| | | }, |
| | | { |
| | | dataType: "slot", |
| | |
| | | const params = { ...searchForm.value, ...page }; |
| | | params.entryDate = undefined; |
| | | productOrderListPage(params) |
| | | .then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records; |
| | | .then(async res => { |
| | | const records = res.data.records || []; |
| | | // 为æ¯ä¸ªè®¢åæ¥è¯¢å¯¹åºçå·¥åºè¿åº¦æ°æ® |
| | | const processPromises = records.map(async item => { |
| | | if (item.npsNo) { |
| | | try { |
| | | const workOrderRes = await productWorkOrderPage({ |
| | | npsNo: item.npsNo, |
| | | size: 100, |
| | | }); |
| | | const workOrders = workOrderRes.data.records || []; |
| | | // æç
§å·¥åºé¡ºåºæåºï¼å¦ææé¡ºåºå段ï¼å设为 orderNum ææè¿å顺åºï¼ |
| | | // 转æ¢ä¸º processRouteStatus æ ¼å¼ |
| | | const processRouteStatus = workOrders.map(wo => ({ |
| | | name: wo.operationName || "æªç¥å·¥åº", |
| | | percentage: wo.completionStatus > 100 ? 100 : wo.completionStatus, |
| | | })); |
| | | return { ...item, processRouteStatus }; |
| | | } catch (error) { |
| | | console.error(`è·åå·¥å ${item.npsNo} è¿åº¦å¤±è´¥:`, error); |
| | | return { ...item, processRouteStatus: [] }; |
| | | } |
| | | } |
| | | return { ...item, processRouteStatus: [] }; |
| | | }); |
| | | |
| | | tableData.value = await Promise.all(processPromises); |
| | | page.total = res.data.total; |
| | | tableLoading.value = false; |
| | | }) |
| | | .catch(() => { |
| | | tableLoading.value = false; |
| | |
| | | .table_list { |
| | | margin-top: unset; |
| | | } |
| | | |
| | | .process-progress-container { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | padding: 10px 0; |
| | | white-space: nowrap; |
| | | |
| | | .process-step { |
| | | display: flex; |
| | | align-items: center; |
| | | position: relative; |
| | | |
| | | .step-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | z-index: 1; |
| | | |
| | | .step-circle { |
| | | width: 36px; |
| | | height: 36px; |
| | | border-radius: 50%; |
| | | border: 2px solid #409eff; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: #fff; |
| | | margin-bottom: 4px; |
| | | |
| | | .step-percentage { |
| | | font-size: 11px; |
| | | font-weight: bold; |
| | | } |
| | | |
| | | &.is-completed { |
| | | border-color: #67c23a; |
| | | .step-percentage { |
| | | color: #67c23a; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .step-name { |
| | | font-size: 12px; |
| | | color: #606266; |
| | | white-space: nowrap; |
| | | } |
| | | } |
| | | |
| | | .step-line { |
| | | width: 30px; |
| | | height: 1px; |
| | | background-color: #dcdfe6; |
| | | margin: 0 -2px; |
| | | margin-top: -20px; // åä¸å移以对é½åå¿ |
| | | } |
| | | } |
| | | } |
| | | </style> |
| | | <style lang="scss"> |
| | | .status-cell { |
| | |
| | | :value="option.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button @click="handleBack">è¿å</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </template> |
| | |
| | | <el-descriptions-item label="ç产订åå·">{{ rowData.productionOrderDto?.npsNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产ååç§°">{{ rowData.productionOrderDto?.productName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产åè§æ ¼">{{ rowData.productionOrderDto?.model || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç©æç¼ç ">{{ rowData.productionOrderDto?.materialCode || '-' }}</el-descriptions-item> |
| | | <!-- <el-descriptions-item label="ç©æç¼ç ">{{ rowData.productionOrderDto?.materialCode || '-' }}</el-descriptions-item> --> |
| | | <el-descriptions-item label="è®¡åæ°é">{{ rowData.productionOrderDto?.quantity || 0 }} <span class="unit">{{ rowData.productionOrderDto?.unit || '-' }}</span></el-descriptions-item> |
| | | <el-descriptions-item label="å½åç¶æ"> |
| | | <el-tag :type="getStatusType(rowData.productionOrderDto?.status)"> |
| | |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="客æ·åç§°">{{ rowData.productionOrderDto?.customerName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¼å§æ¥æ">{{ rowData.productionOrderDto?.startTime || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¼å§æ¥æ">{{ parseTime(rowData.productionOrderDto?.startTime) || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="宿è¿åº¦"> |
| | | <el-progress :percentage="rowData.productionOrderDto?.completionStatus" |
| | | <el-progress :percentage="rowData.productionOrderDto?.completionStatus>=100?100:rowData.productionOrderDto?.completionStatus" |
| | | :color="customColors(rowData.productionOrderDto?.completionStatus)" |
| | | :status="rowData.productionOrderDto?.completionStatus === 100 ? 'success' : ''" |
| | | style="width: 120px;" /> |
| | | :status="rowData.productionOrderDto?.completionStatus >= 100 ? 'success' : ''" |
| | | style="width: 80%;" /> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | |
| | | <el-table :data="rowData.productionRecords" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column prop="productNo" |
| | | <el-table-column prop="workOrder.workOrderNo" |
| | | label="å·¥åç¼å·" |
| | | align="center"> |
| | | </el-table-column> |
| | | <el-table-column prop="productName" |
| | | label="产ååç§°" |
| | | align="center" /> |
| | | <el-table-column prop="model" |
| | | label="è§æ ¼" |
| | | align="center" /> |
| | | <el-table-column prop="processName" |
| | | label="å·¥åºåç§°" |
| | | align="center" /> |
| | | <el-table-column prop="requiredQuantity" |
| | | <el-table-column label="产ååç§°" |
| | | align="center"> |
| | | <template #default="{ row }"> |
| | | {{ row.workOrder.productName || '-' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="è§æ ¼" |
| | | align="center"> |
| | | <template #default="{ row }"> |
| | | {{ row.workOrder.model || '-' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="workOrder.planQuantity" |
| | | label="éæ±æ°é" |
| | | align="center" /> |
| | | <el-table-column prop="completedQuantity" |
| | | <el-table-column prop="workOrder.completeQuantity" |
| | | label="宿æ°é" |
| | | align="center" /> |
| | | <el-table-column prop="workOrder.completionStatus" |
| | | label="宿è¿åº¦" |
| | | align="center"> |
| | | <template #default="{ row }"> |
| | | <span :style="{ color: customColors(row.workOrder.completionStatus) }">{{ row.workOrder.completionStatus || 0 }}%</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="详æ
" |
| | | align="center" |
| | | width="200"> |
| | |
| | | <div class="detail-container"> |
| | | <!-- åºç¡ä¿¡æ¯ --> |
| | | <div class="detail-section"> |
| | | <h3 class="section-title">åºç¡ä¿¡æ¯</h3> |
| | | <h3 class="section-title">å·¥ååºç¡ä¿¡æ¯</h3> |
| | | <el-descriptions :column="3" |
| | | border> |
| | | <el-descriptions-item label="ç产工åå·">{{ detailData.npsNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="çç»"> |
| | | <el-tag :type="detailData.schedule === 'ç½ç' ? 'primary' : 'warning'">{{ detailData.schedule || '-' }}</el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="产åç¼ç ">{{ detailData.materialCode || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产ååç§°">{{ detailData.productName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="è§æ ¼">{{ detailData.model || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="åæ ¼æ°é"><span class="num2">{{ detailData.qualifiedQuantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item> |
| | | <el-descriptions-item label="ä¸åæ ¼æ°é"><span class="num3">{{ detailData.unqualifiedQuantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item> |
| | | <el-descriptions-item label="æ»æ°é"><span class="num1">{{ detailData.quantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item> |
| | | <el-descriptions-item label="å¼å§æ¶é´">{{ detailData.reportingTime || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç产工åå·">{{ detailData.workOrder.workOrderNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="è®¡åæ°é">{{ detailData.workOrder.planQuantity || 0 }}</el-descriptions-item> |
| | | <el-descriptions-item label="宿æ°é">{{ detailData.workOrder.completeQuantity || 0 }}</el-descriptions-item> |
| | | <el-descriptions-item label="å®é
å¼å§æ¶é´">{{ parseTime(detailData.workOrder.actualStartTime) || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å®é
ç»ææ¶é´">{{ parseTime(detailData.workOrder.actualEndTime) || '-' }}</el-descriptions-item> |
| | | <!-- <el-descriptions-item label="宿è¿åº¦"> |
| | | <el-progress :percentage="detailData.workOrder.completionStatus >= 100 ? 100 : (detailData.workOrder.completionStatus || 0)" |
| | | :color="customColors(detailData.workOrder.completionStatus)" |
| | | :status="detailData.workOrder.completionStatus >= 100 ? 'success' : ''" |
| | | style="width:500px;" /> |
| | | </el-descriptions-item> --> |
| | | <el-descriptions-item label="宿è¿åº¦"><span :style="{ color: customColors(detailData.workOrder.completionStatus) }">{{ detailData.workOrder.completionStatus || 0 }}%</span></el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | <div class="detail-section"> |
| | | <h3 class="section-title">æ¥å·¥æç»</h3> |
| | | <el-table :data="[detailData]" |
| | | <el-table :data="detailData.reports" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column label="æ¥å·¥åå·" |
| | | prop="productNo" |
| | | align="center" /> |
| | | <el-table-column label="äº§åºæ°é" |
| | | prop="qualifiedQuantity" |
| | | align="center" /> |
| | | <el-table-column label="æ¥åºæ°é" |
| | | prop="unqualifiedQuantity" |
| | | <el-table-column label="å建人" |
| | | prop="userName" |
| | | align="center" /> |
| | | <el-table-column label="å建æ¶é´" |
| | | prop="reportingTime" |
| | | align="center" /> |
| | | align="center"> |
| | | <template #default="{ row }"> |
| | | {{ parseTime(row.createTime) }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" |
| | | align="center" |
| | | width="200"> |
| | |
| | | :key="record.id" |
| | | class="quality-record-block"> |
| | | <div class="detail-section"> |
| | | <h3 class="section-title">æ£æµè®°å½ {{ index + 1 }} - {{ record.checkTime }}</h3> |
| | | <h3 class="section-title">æ£æµè®°å½ {{ index + 1 }} - {{ parseTime(record.createTime) }}</h3> |
| | | <el-descriptions :column="3" |
| | | border> |
| | | <el-descriptions-item label="æ£æµæ¥æ">{{ record.checkTime || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç产工åå·">{{ record.workOrderNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å·¥åº">{{ record.process || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ£éªå">{{ record.checkName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ£æµæ¥æ">{{ parseTime(record.createTime) || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ¥å·¥åå·">{{ record.reportNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ£éªå">{{ record.userName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产ååç§°">{{ record.productName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="è§æ ¼åå·">{{ record.model || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ°é">{{ record.quantity || 0 }} {{ record.unit || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ£æµåä½">{{ record.checkCompany || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ£æµç»æ"> |
| | | <el-tag :type="record.checkResult === 'åæ ¼' ? 'success' : 'danger'"> |
| | | {{ record.checkResult || '-' }} |
| | | {{ record.checkResult || 'å¾
æ£æµ' }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | <h4 class="sub-section-title">æ£éªææ å表</h4> |
| | | <el-table :data="record.inspectItems" |
| | | <el-table :data="record.inspectParamList" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column label="åºå·" |
| | |
| | | width="60" |
| | | align="center" /> |
| | | <el-table-column label="ææ " |
| | | prop="itemName" |
| | | prop="parameterItem" |
| | | align="center" /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | |
| | | prop="controlValue" |
| | | align="center" /> |
| | | <el-table-column label="å®é
å¼" |
| | | prop="actualValue" |
| | | prop="testValue" |
| | | align="center" /> |
| | | </el-table> |
| | | </div> |
| | | <!-- <div class="detail-section"> |
| | | |
| | | </div> --> |
| | | <el-divider v-if="index < qualityRecords.length - 1" /> |
| | | </div> |
| | | </div> |
| | |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { useRoute, useRouter } from "vue-router"; |
| | | import { ElMessage } from "element-plus"; |
| | | import { parseTime } from "@/utils/ruoyi"; |
| | | import InputModal from "@/views/productionManagement/productionReporting/Input.vue"; |
| | | import { |
| | | getOrderDetail, |
| | | productOrderListPage, |
| | | } from "@/api/productionManagement/productionOrder"; |
| | | |
| | | const route = useRoute(); |
| | | const router = useRouter(); |
| | |
| | | }); |
| | | const selectedNpsNo = ref(null); |
| | | const npsNoLoading = ref(false); |
| | | const npsNoOptions = ref([ |
| | | { |
| | | id: 1, |
| | | npsNo: "PO20240301001", |
| | | productName: "ç²¾å¯æ¶²å缸", |
| | | model: "HG-100/50-500", |
| | | materialCode: "MAT-2024-001", |
| | | quantity: 500, |
| | | unit: "ä»¶", |
| | | status: 1, |
| | | customerName: "éå·¥æºæ¢°æéå
¬å¸", |
| | | startTime: "2024-03-01", |
| | | completionStatus: 65, |
| | | }, |
| | | { |
| | | id: 2, |
| | | npsNo: "PO20240301002", |
| | | productName: "å·¥ä¸ä¼ºæçµæº", |
| | | model: "SV-400W-3000", |
| | | materialCode: "MAT-2024-002", |
| | | quantity: 200, |
| | | unit: "å°", |
| | | status: 2, |
| | | customerName: "èªå¨å设å¤ç§æå
¬å¸", |
| | | startTime: "2024-03-02", |
| | | completionStatus: 100, |
| | | }, |
| | | { |
| | | id: 3, |
| | | npsNo: "PO20240301003", |
| | | productName: "é«åå¯å°å", |
| | | model: "SR-80-5", |
| | | materialCode: "MAT-2024-003", |
| | | quantity: 5000, |
| | | unit: "个", |
| | | status: 0, |
| | | customerName: "å¯å°ç³»ç»é
ä»¶å", |
| | | startTime: "2024-03-05", |
| | | completionStatus: 0, |
| | | }, |
| | | ]); |
| | | const npsNoOptions = ref([]); |
| | | |
| | | // 详æ
æ°æ® |
| | | const rowData = reactive({ |
| | |
| | | |
| | | // æ¥å·¥è¯¦æ
å¼¹çª |
| | | const detailDialogVisible = ref(false); |
| | | const detailData = ref({}); |
| | | const detailData = ref({ |
| | | workOrder: {}, |
| | | reports: [], |
| | | }); |
| | | |
| | | // æå
¥æ¨¡ææ¡ |
| | | const isShowInput = ref(false); |
| | |
| | | |
| | | // ç¶æå¤ç |
| | | const getStatusType = status => { |
| | | const typeMap = { 0: "info", 1: "primary", 2: "success" }; |
| | | const typeMap = { 1: "primary", 2: "warning", 3: "success", 5: "danger" }; |
| | | return typeMap[status] || "info"; |
| | | }; |
| | | const getStatusText = status => { |
| | | const statusMap = { 0: "æªå¼å§", 1: "ç产ä¸", 2: "已宿" }; |
| | | return statusMap[status] || "æªç¥"; |
| | | const statusMap = { 1: "å¾
å¼å§", 2: "è¿è¡ä¸", 3: "已宿", 5: "å·²ç»æ" }; |
| | | return statusMap[status] || "已忶"; |
| | | }; |
| | | const customColors = percentage => { |
| | | if (percentage < 30) return "#f56c6c"; |
| | |
| | | }; |
| | | |
| | | // 模ææç´¢æ¹æ³ |
| | | const handleNpsNoSearch = query => { |
| | | if (query) { |
| | | npsNoLoading.value = true; |
| | | setTimeout(() => { |
| | | npsNoLoading.value = false; |
| | | }, 300); |
| | | const handleNpsNoSearch = async query => { |
| | | npsNoLoading.value = true; |
| | | try { |
| | | const res = await productOrderListPage({ |
| | | npsNo: query || "", |
| | | pageNum: 1, |
| | | pageSize: 50, |
| | | }); |
| | | // åç
§ productionOrder/index.vue çæ°æ®ç»æ res.data.records |
| | | npsNoOptions.value = res.data?.records || res.rows || []; |
| | | } catch (error) { |
| | | console.error(error); |
| | | } finally { |
| | | npsNoLoading.value = false; |
| | | } |
| | | }; |
| | | |
| | | const handleSearch = id => { |
| | | const handleSearch = async id => { |
| | | const selected = npsNoOptions.value.find(item => item.id === id); |
| | | if (selected) { |
| | | rowData.productionOrderDto = selected; |
| | | rowData.productionRecords = [ |
| | | { |
| | | id: 1001, |
| | | productNo: "MO-2024-001-01", |
| | | productName: selected.productName, |
| | | model: selected.model, |
| | | processName: "æ¯å¯å å·¥", |
| | | requiredQuantity: selected.quantity, |
| | | completedQuantity: Math.floor(selected.quantity * 0.4), |
| | | qualifiedQuantity: Math.floor(selected.quantity * 0.4) - 2, |
| | | unqualifiedQuantity: 2, |
| | | reportingTime: "2024-03-01 10:00:00", |
| | | schedule: "ç½ç", |
| | | postName: "å¼ ä¸", |
| | | unit: selected.unit, |
| | | }, |
| | | { |
| | | id: 1002, |
| | | productNo: "MO-2024-001-02", |
| | | productName: selected.productName, |
| | | model: selected.model, |
| | | processName: "ç²¾å å·¥", |
| | | requiredQuantity: Math.floor(selected.quantity * 0.4), |
| | | completedQuantity: Math.floor(selected.quantity * 0.25), |
| | | qualifiedQuantity: Math.floor(selected.quantity * 0.25), |
| | | unqualifiedQuantity: 0, |
| | | reportingTime: "2024-03-01 16:00:00", |
| | | schedule: "ç½ç", |
| | | postName: "æå", |
| | | unit: selected.unit, |
| | | }, |
| | | ]; |
| | | try { |
| | | const res = await getOrderDetail(selected.npsNo); |
| | | if (res.code === 200) { |
| | | const { productionOrder, workOrderList } = res.data; |
| | | rowData.productionOrderDto = productionOrder || selected; |
| | | rowData.productionRecords = workOrderList || []; |
| | | } else { |
| | | rowData.productionOrderDto = selected; |
| | | rowData.productionRecords = []; |
| | | } |
| | | } catch (error) { |
| | | console.error(error); |
| | | ElMessage.error("è·å订å详æ
失败"); |
| | | rowData.productionOrderDto = selected; |
| | | } |
| | | } |
| | | }; |
| | | |
| | |
| | | }; |
| | | |
| | | const handleClickStep = row => { |
| | | // row æ¯ workOrderList ä¸çä¸é¡¹ï¼å
å« workOrder, reportList, inspectList |
| | | detailData.value = { |
| | | id: row.id || Math.floor(Math.random() * 1000), |
| | | productNo: row.productNo, |
| | | npsNo: rowData.productionOrderDto.npsNo, |
| | | schedule: row.schedule, |
| | | postName: row.postName, |
| | | materialCode: rowData.productionOrderDto.materialCode, |
| | | productName: row.productName, |
| | | model: row.model, |
| | | qualifiedQuantity: row.qualifiedQuantity, |
| | | unqualifiedQuantity: row.unqualifiedQuantity || 0, |
| | | quantity: row.completedQuantity, |
| | | unit: row.unit, |
| | | reportingTime: row.reportingTime, |
| | | productionOperationParamList: [ |
| | | { id: 1, paramName: "主轴转é", inputValue: "2400", unit: "rpm" }, |
| | | { id: 2, paramName: "è¿ç»é度", inputValue: "120", unit: "mm/min" }, |
| | | { id: 3, paramName: "ååæ·±åº¦", inputValue: "0.5", unit: "mm" }, |
| | | { id: 4, paramName: "å·å´æ¶²åå", inputValue: "0.6", unit: "Mpa" }, |
| | | ], |
| | | workOrder: row.workOrder || {}, |
| | | reports: (row.reportList || []).map(r => ({ |
| | | ...r.reportMain, |
| | | productionOperationParamList: r.reportParamList || [], |
| | | })), |
| | | }; |
| | | detailDialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleClickQuality = row => { |
| | | qualityRecords.value = [ |
| | | { |
| | | id: 2001, |
| | | checkTime: "2024-03-01 11:30:00", |
| | | workOrderNo: row.productNo, |
| | | process: row.processName, |
| | | checkName: "è´¨éé¨-ç建å½", |
| | | productName: row.productName, |
| | | model: row.model, |
| | | unit: row.unit, |
| | | quantity: row.completedQuantity, |
| | | checkCompany: "å
é¨å®éªå®¤", |
| | | checkResult: "åæ ¼", |
| | | inspectItems: [ |
| | | { |
| | | id: 1, |
| | | itemName: "å¤å¾å°ºå¯¸", |
| | | unit: "mm", |
| | | standardValue: "100.00±0.05", |
| | | controlValue: "100.00±0.03", |
| | | actualValue: "100.01", |
| | | result: "åæ ¼", |
| | | }, |
| | | { |
| | | id: 2, |
| | | itemName: "å
å¾å°ºå¯¸", |
| | | unit: "mm", |
| | | standardValue: "50.00+0.02/-0", |
| | | controlValue: "50.00+0.01/-0", |
| | | actualValue: "50.01", |
| | | result: "åæ ¼", |
| | | }, |
| | | { |
| | | id: 3, |
| | | itemName: "表é¢ç²ç³åº¦", |
| | | unit: "Ra", |
| | | standardValue: "â¤1.6", |
| | | controlValue: "â¤1.2", |
| | | actualValue: "0.8", |
| | | result: "åæ ¼", |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 2001, |
| | | checkTime: "2024-03-01 11:30:00", |
| | | workOrderNo: row.productNo, |
| | | process: row.processName, |
| | | checkName: "è´¨éé¨-ç建å½", |
| | | productName: row.productName, |
| | | model: row.model, |
| | | unit: row.unit, |
| | | quantity: row.completedQuantity, |
| | | checkCompany: "å
é¨å®éªå®¤", |
| | | checkResult: "åæ ¼", |
| | | inspectItems: [ |
| | | { |
| | | id: 1, |
| | | itemName: "å¤å¾å°ºå¯¸", |
| | | unit: "mm", |
| | | standardValue: "100.00±0.05", |
| | | controlValue: "100.00±0.03", |
| | | actualValue: "100.01", |
| | | result: "åæ ¼", |
| | | }, |
| | | { |
| | | id: 2, |
| | | itemName: "å
å¾å°ºå¯¸", |
| | | unit: "mm", |
| | | standardValue: "50.00+0.02/-0", |
| | | controlValue: "50.00+0.01/-0", |
| | | actualValue: "50.01", |
| | | result: "åæ ¼", |
| | | }, |
| | | { |
| | | id: 3, |
| | | itemName: "表é¢ç²ç³åº¦", |
| | | unit: "Ra", |
| | | standardValue: "â¤1.6", |
| | | controlValue: "â¤1.2", |
| | | actualValue: "0.8", |
| | | result: "åæ ¼", |
| | | }, |
| | | ], |
| | | }, |
| | | ]; |
| | | // row æ¯ workOrderList ä¸çä¸é¡¹ |
| | | const inspects = row.inspectList || []; |
| | | qualityRecords.value = inspects.map(i => ({ |
| | | ...i.inspect, |
| | | reportNo: i.reportNo, |
| | | userName: i.reportMain?.userName || "-", |
| | | inspectParamList: i.inspectParamList || [], |
| | | inspectFileList: i.inspectFileList || [], |
| | | })); |
| | | qualityDialogVisible.value = true; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | onMounted(async () => { |
| | | // åå§å è½½å表 |
| | | await handleNpsNoSearch(); |
| | | |
| | | if (route.query.npsNo) { |
| | | const npsNo = route.query.npsNo; |
| | | const found = npsNoOptions.value.find(item => item.npsNo === npsNo); |
| | |
| | | selectedNpsNo.value = found.id; |
| | | handleSearch(found.id); |
| | | } else { |
| | | // å¦ææ²¡æ¾å°ï¼å建ä¸ä¸ªä¸´æ¶ç |
| | | const mockItem = { |
| | | id: Date.now(), |
| | | npsNo: npsNo, |
| | | productName: route.query.productName || "ç²¾å¯æ¶²å缸", |
| | | model: route.query.model || "HG-100/50-500", |
| | | materialCode: "MAT-2024-MOCK", |
| | | quantity: 100, |
| | | unit: "ä»¶", |
| | | status: 1, |
| | | customerName: "模æå®¢æ·", |
| | | startTime: "2024-03-01", |
| | | completionStatus: 50, |
| | | }; |
| | | npsNoOptions.value.push(mockItem); |
| | | selectedNpsNo.value = mockItem.id; |
| | | handleSearch(mockItem.id); |
| | | // 妿åè¡¨ä¸æ²¡æï¼å¯è½æ¯å页åå ï¼ï¼åæ ¹æ® npsNo 忬¡ç²¾åæç´¢ |
| | | try { |
| | | const res = await productOrderListPage({ |
| | | npsNo, |
| | | pageNum: -1, |
| | | pageSize: -1, |
| | | }); |
| | | const records = res.data?.records || res.rows || []; |
| | | if (records.length > 0) { |
| | | const item = records[0]; |
| | | npsNoOptions.value.unshift(item); |
| | | selectedNpsNo.value = item.id; |
| | | handleSearch(item.id); |
| | | } |
| | | } catch (error) { |
| | | console.error("è·åè·¯ç±åæ°å¯¹åºç订å失败", error); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div class="search-row"> |
| | | <div class="search-item"> |
| | | <span class="search_title">å·¥åç¼å·ï¼</span> |
| | |
| | | </div> |
| | | <div class="search-item"> |
| | | <span class="search_title">ç产订åå·ï¼</span> |
| | | <el-input v-model="searchForm.productOrderNpsNo" |
| | | <el-input v-model="searchForm.npsNo" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | @change="handleQuery" |
| | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | workOrderNo: "", |
| | | productOrderNpsNo: "", |
| | | npsNo: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div class="search-row"> |
| | | <div class="search-item"> |
| | | <span class="search_title">å·¥åç¼å·ï¼</span> |
| | |
| | | </div> |
| | | <div class="search-item"> |
| | | <span class="search_title">ç产订åå·ï¼</span> |
| | | <el-input v-model="searchForm.productOrderNpsNo" |
| | | <el-input v-model="searchForm.npsNo" |
| | | style="width: 240px" |
| | | placeholder="请è¾å
¥" |
| | | @change="handleQuery" |
| | |
| | | import QRCode from "qrcode"; |
| | | import { getCurrentInstance, reactive, toRefs } from "vue"; |
| | | import MaterialDialog from "./components/MaterialDialog.vue"; |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | const FileList = defineAsyncComponent(() => |
| | | import("@/components/Dialog/FileList.vue") |
| | | ); |
| | | |
| | | import useUserStore from "@/store/modules/user"; |
| | | const { proxy } = getCurrentInstance(); |
| | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | workOrderNo: "", |
| | | productOrderNpsNo: "", |
| | | npsNo: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">产ååç§°ï¼</span> |
| | | <el-input |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div style="display: flex;flex-direction: row;align-items: center;"> |
| | | <div> |
| | | <span class="search_title">ç±»åï¼</span> |
| | | <el-form :model="searchForm" inline style="margin-bottom: 0;"> |
| | | <el-form-item label="ç±»åï¼"> |
| | | <el-select v-model="searchForm.inspectType" clearable style="width: 200px" @change="handleQuery"> |
| | | <el-option label="åæææ£éª" :value="0" /> |
| | | <el-option label="è¿ç¨æ£éª" :value="1" /> |
| | | <el-option label="åºåæ£éª" :value="2" /> |
| | | </el-select> |
| | | </div> |
| | | <div style="margin-left: 10px"> |
| | | <span class="search_title">ç¶æï¼</span> |
| | | </el-form-item> |
| | | <el-form-item label="ç¶æï¼"> |
| | | <el-select v-model="searchForm.inspectState" clearable style="width: 200px" @change="handleQuery"> |
| | | <el-option label="å¾
å¤ç" :value="0" /> |
| | | <el-option label="å·²å¤ç" :value="1" /> |
| | | </el-select> |
| | | </div> |
| | | <div style="margin-left: 10px"> |
| | | <span class="search_title">产ååç§°ï¼</span> |
| | | </el-form-item> |
| | | <el-form-item label="产ååç§°ï¼"> |
| | | <el-input |
| | | v-model="searchForm.productName" |
| | | style="width: 200px" |
| | |
| | | clearable |
| | | :prefix-icon="Search" |
| | | /> |
| | | </div> |
| | | <span style="margin-left: 10px" class="search_title">æ£æµæ¥æï¼</span> |
| | | <el-date-picker v-model="searchForm.entryDate" value-format="YYYY-MM-DD" format="YYYY-MM-DD" type="daterange" |
| | | style="width: 300px" |
| | | placeholder="è¯·éæ©" clearable @change="changeDaterange" /> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px">æç´¢</el-button> |
| | | </div> |
| | | <div> |
| | | </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" |
| | | style="width: 300px" |
| | | placeholder="è¯·éæ©" clearable @change="changeDaterange" /> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" @click="handleQuery">æç´¢</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | <div class="mb20" style="text-align: right;"> |
| | | <el-button type="primary" @click="openForm('add')">æ°å¢</el-button> |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | | <PIMTable |
| | | rowKey="id" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">å·¥åºï¼</span> |
| | | <el-input |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">ä¾åºåï¼</span> |
| | | <el-input |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">äºæ
åç§°ï¼</span> |
| | | <el-input v-model="searchForm.accidentName" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">åºæ¥é¢æ¡åç§°ï¼</span> |
| | | <el-input v-model="searchForm.planName" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">å±é©æºåç§°ï¼</span> |
| | | <el-input v-model="searchForm.name" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">å±é©æºåç§°ï¼</span> |
| | | <el-input v-model="searchForm.name" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- æ ç¾é¡µåæ¢ä¸åç审æ¹ç±»å --> |
| | | <div class="search_form"> |
| | | <div class="search_form mb20"> |
| | | <div> |
| | | <span class="search_title">æµç¨ç¼å·ï¼</span> |
| | | <el-input v-model="searchForm.approveId" |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div class="search_form" style="margin-bottom: 20px;"> |
| | | <div> |
| | | <span class="search_title">客æ·åç§°ï¼</span> |
| | | <el-input |
| | |
| | | const { VITE_APP_ENV } = env; |
| | | const baseUrl = |
| | | env.VITE_APP_ENV === "development" |
| | | ? "http://localhost:7005" |
| | | ? "http://1.15.17.182:9003" |
| | | : env.VITE_BASE_API; |
| | | const javaUrl = |
| | | env.VITE_APP_ENV === "development" |