| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <!-- æ¥è¯¢æ¡ä»¶ --> |
| | | <el-form |
| | | :model="queryParams" |
| | | ref="queryForm" |
| | | :inline="true" |
| | | v-show="showSearch" |
| | | label-width="90px" |
| | | > |
| | | <el-form-item label="产ååå·" prop="productModel"> |
| | | <el-input |
| | | v-model="queryParams.productModel" |
| | | placeholder="请è¾å
¥äº§ååå·" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="客æ·åç§°" prop="customerName"> |
| | | <el-input |
| | | v-model="queryParams.customerName" |
| | | placeholder="请è¾å
¥å®¢æ·åç§°" |
| | | clearable |
| | | @keyup.enter.native="handleQuery" |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å馿¶é´" prop="feedbackRange"> |
| | | <el-date-picker |
| | | v-model="queryParams.feedbackRange" |
| | | type="daterange" |
| | | range-separator="è³" |
| | | start-placeholder="å¼å§æ¥æ" |
| | | end-placeholder="ç»ææ¥æ" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | <el-form-item label="å¤çç¶æ" prop="status"> |
| | | <el-select |
| | | v-model="queryParams.status" |
| | | placeholder="è¯·éæ©å¤çç¶æ" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="item in statusOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" icon="Search" @click="handleQuery"> |
| | | æç´¢ |
| | | </el-button> |
| | | <el-button icon="Refresh" @click="resetQuery">éç½®</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | |
| | | <!-- æä½åº --> |
| | | <el-row :gutter="10" class="mb8"> |
| | | <el-col :span="3"> |
| | | <el-button |
| | | type="primary" |
| | | plain |
| | | icon="Plus" |
| | | @click="handleAdd" |
| | | > |
| | | æ°å¢å®åè´¨éè®°å½ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="3"> |
| | | <el-button |
| | | type="success" |
| | | plain |
| | | icon="Edit" |
| | | :disabled="single" |
| | | @click="handleUpdate" |
| | | > |
| | | ä¿®æ¹ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="3"> |
| | | <el-button |
| | | type="danger" |
| | | plain |
| | | icon="Delete" |
| | | :disabled="multiple" |
| | | @click="handleDelete" |
| | | > |
| | | å é¤ |
| | | </el-button> |
| | | </el-col> |
| | | <el-col :span="3"> |
| | | <el-button |
| | | type="warning" |
| | | plain |
| | | icon="Download" |
| | | @click="handleExport" |
| | | > |
| | | å¯¼åº |
| | | </el-button> |
| | | </el-col> |
| | | <right-toolbar |
| | | v-model:showSearch="showSearch" |
| | | @queryTable="getList" |
| | | /> |
| | | </el-row> |
| | | |
| | | <!-- æ°æ®è¡¨ --> |
| | | <el-table |
| | | v-loading="loading" |
| | | :data="afterSalesList" |
| | | @selection-change="handleSelectionChange" |
| | | > |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | <el-table-column label="åºå·" type="index" width="55" align="center" /> |
| | | <el-table-column label="éå®ååå·" prop="contractNo" width="160" /> |
| | | <el-table-column label="产åç¼å·" prop="productCode" width="140" /> |
| | | <el-table-column label="产ååå·" prop="productModel" width="140" /> |
| | | <el-table-column label="客æ·åç§°" prop="customerName" width="160" /> |
| | | <el-table-column label="èç³»æ¹å¼" prop="contact" width="140" /> |
| | | <el-table-column label="å馿¶é´" prop="feedbackTime" width="160"> |
| | | <template #default="scope"> |
| | | <span>{{ scope.row.feedbackTime }}</span> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="é®é¢æè¿°" prop="problemDesc" show-overflow-tooltip /> |
| | | <el-table-column label="ç»´ä¿®æ
åµ" prop="repairInfo" show-overflow-tooltip /> |
| | | <el-table-column label="å¤çç»æ" prop="result" show-overflow-tooltip /> |
| | | <el-table-column label="å¤çç¶æ" prop="status" width="120" align="center"> |
| | | <template #default="scope"> |
| | | <dict-tag |
| | | :options="statusOptions" |
| | | :value="scope.row.status" |
| | | /> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="æä½" align="center" class-name="small-padding fixed-width" width="160" fixed="right"> |
| | | <template #default="scope"> |
| | | <el-button size="small" type="text" icon="Edit" @click="handleUpdate(scope.row)"> |
| | | ä¿®æ¹ |
| | | </el-button> |
| | | <el-button size="small" type="text" icon="Delete" @click="handleDelete(scope.row)"> |
| | | å é¤ |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | |
| | | <pagination |
| | | v-show="total > 0" |
| | | :total="total" |
| | | v-model:page="queryParams.pageNum" |
| | | v-model:limit="queryParams.pageSize" |
| | | @pagination="getList" |
| | | /> |
| | | |
| | | <!-- æ°å¢/ä¿®æ¹å¼¹çª --> |
| | | <el-dialog |
| | | :title="title" |
| | | v-model="open" |
| | | width="900px" |
| | | append-to-body |
| | | > |
| | | <el-form |
| | | ref="formRef" |
| | | :model="form" |
| | | :rules="rules" |
| | | label-width="110px" |
| | | > |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="éå®ååå·" prop="contractNo"> |
| | | <el-input |
| | | v-model="form.contractNo" |
| | | placeholder="è¯·éæ©å
³èéå®ååå·" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="产åç¼å·" prop="productCode"> |
| | | <el-input |
| | | v-model="form.productCode" |
| | | placeholder="è¯·éæ©å
³è产åç¼å·" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="产ååå·" prop="productModel"> |
| | | <el-input |
| | | v-model="form.productModel" |
| | | placeholder="请è¾å
¥äº§ååå·" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="客æ·åç§°" prop="customerName"> |
| | | <el-input |
| | | v-model="form.customerName" |
| | | placeholder="请è¾å
¥å®¢æ·åç§°" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="èç³»æ¹å¼" prop="contact"> |
| | | <el-input |
| | | v-model="form.contact" |
| | | placeholder="请è¾å
¥å®¢æ·èç³»æ¹å¼" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å馿¶é´" prop="feedbackTime"> |
| | | <el-date-picker |
| | | v-model="form.feedbackTime" |
| | | type="datetime" |
| | | value-format="YYYY-MM-DD HH:mm:ss" |
| | | format="YYYY-MM-DD HH:mm" |
| | | placeholder="è¯·éæ©å馿¶é´" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="客æ·åé¦é®é¢" prop="problemDesc"> |
| | | <el-input |
| | | v-model="form.problemDesc" |
| | | type="textarea" |
| | | :rows="3" |
| | | placeholder="请详ç»è®°å½å®¢æ·åé¦é®é¢ãç°è±¡æè¿°çä¿¡æ¯" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="ç»´ä¿®æ
åµ" prop="repairInfo"> |
| | | <el-input |
| | | v-model="form.repairInfo" |
| | | type="textarea" |
| | | :rows="2" |
| | | placeholder="è®°å½ç»´ä¿®è¿ç¨ã使ç¨å¤ä»¶ãè¿ä¿®æ¬¡æ°ç" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¤çç»æ" prop="result"> |
| | | <el-input |
| | | v-model="form.result" |
| | | type="textarea" |
| | | :rows="2" |
| | | placeholder="è®°å½æç»å¤çç»æï¼å¦æ´æ¢ãéè´§ãå级ç" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row> |
| | | <el-col :span="12"> |
| | | <el-form-item label="å¤çç¶æ" prop="status"> |
| | | <el-select |
| | | v-model="form.status" |
| | | placeholder="è¯·éæ©å¤çç¶æ" |
| | | > |
| | | <el-option |
| | | v-for="item in statusOptions" |
| | | :key="item.value" |
| | | :label="item.label" |
| | | :value="item.value" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="夿³¨" prop="remark"> |
| | | <el-input |
| | | v-model="form.remark" |
| | | type="textarea" |
| | | :rows="2" |
| | | placeholder="å¯è®°å½åç»è·è¸ªæè§ãå¤çç»è®ºç" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">ç¡® å®</el-button> |
| | | <el-button @click="cancel">å æ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup name="AfterSalesTraceability"> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | // ç¶æåå
¸ |
| | | const statusOptions = ref([ |
| | | { label: "å¾
å¤ç", value: "0" }, |
| | | { label: "å¤çä¸", value: "1" }, |
| | | { label: "已宿", value: "2" }, |
| | | { label: "å·²å
³é", value: "3" }, |
| | | ]); |
| | | |
| | | // 模æå®åè´¨éæ°æ® |
| | | const afterSalesList = ref([ |
| | | { |
| | | id: 1, |
| | | contractNo: "SC-2024-001", |
| | | productCode: "P-10001", |
| | | productModel: "XG-500A", |
| | | customerName: "ååçµåç§ææéå
¬å¸", |
| | | contact: "å¼ å·¥ / 13800000001", |
| | | feedbackTime: "2024-12-01 10:23:00", |
| | | problemDesc: "使ç¨ä¸ä¸ªæååºç°é´ææ§æçµï¼å½±å产线稳å®è¿è¡ã", |
| | | repairInfo: "宿工ç¨å¸ä¸é¨æ£ä¿®ï¼æ´æ¢çµæºæ¨¡åå¹¶å åºæ¥çº¿ç«¯åã", |
| | | result: "æ´æ¢çµæºæ»æï¼æ¢å¤æ£å¸¸ä½¿ç¨ï¼å»ºè®®å®¢æ·å¢å UPSä¿æ¤ã", |
| | | status: "2", |
| | | remark: "åå
¥éç¹è·è¸ªå®¢æ·ï¼åç»è§å¯ä¸ä¸ªå£åº¦ã", |
| | | }, |
| | | { |
| | | id: 2, |
| | | contractNo: "SC-2024-015", |
| | | productCode: "P-10045", |
| | | productModel: "XG-500B", |
| | | customerName: "åä¸ç²¾å¯å¶é æéå
¬å¸", |
| | | contact: "æå·¥ / 13800000002", |
| | | feedbackTime: "2024-12-05 15:40:00", |
| | | problemDesc: "é¨åæ¹æ¬¡åºç°å¤å£³å®è±ï¼å®¢æ·æè¯å¤è§è´¨éä¸è¾¾æ ã", |
| | | repairInfo: "ä¸ç产ç°åºæ ¸æ¥ï¼ç¡®è®¤æ¥ææ¬è¿åå
è£
ç¯èåå¨ç£ç¢°é£é©ã", |
| | | result: "对é®é¢æ¹æ¬¡éæ°è¿å·¥ï¼è¡¥åè¯åï¼å¹¶ä¼åå
è£
鲿¤æ¹æ¡ã", |
| | | status: "1", |
| | | remark: "éè·è¸ªåç»æ¹æ¬¡æè¯çååã", |
| | | }, |
| | | { |
| | | id: 3, |
| | | contractNo: "SC-2024-032", |
| | | productCode: "P-10110", |
| | | productModel: "XG-600C", |
| | | customerName: "è¥¿åæ°è½æºç§æè¡ä»½", |
| | | contact: "çå·¥ / 13800000003", |
| | | feedbackTime: "2024-11-28 09:15:00", |
| | | problemDesc: "ç°åºè°è¯æ¶åç°æ¥å£ä¸å
¼å®¹ï¼éè¦éé
å®¢æ·æ§çç³»ç»ã", |
| | | repairInfo: "è¿ç¨ææ¯æ¯æ+ç°åºå·¥ç¨å¸èåææ¥ï¼æä¾è¿æ¸¡éé
æ¹æ¡ã", |
| | | result: "éè¿æ´æ¢æ¥æä»¶å¹¶å级åºä»¶çæ¬è§£å³ã", |
| | | status: "0", |
| | | remark: "å»ºè®®ä¸æ¬¡åååç½®æ²éæ¥å£è§æ ¼ã", |
| | | }, |
| | | ]); |
| | | |
| | | const open = ref(false); |
| | | const loading = ref(false); |
| | | const showSearch = ref(true); |
| | | const ids = ref([]); |
| | | const single = ref(true); |
| | | const multiple = ref(true); |
| | | const total = ref(3); |
| | | const title = ref("æ°å¢å®åè´¨éè®°å½"); |
| | | |
| | | const data = reactive({ |
| | | form: {}, |
| | | queryParams: { |
| | | pageNum: 1, |
| | | pageSize: 10, |
| | | productModel: null, |
| | | customerName: null, |
| | | feedbackRange: [], |
| | | status: null, |
| | | }, |
| | | rules: { |
| | | contractNo: [ |
| | | { required: true, message: "éå®ååå·ä¸è½ä¸ºç©º", trigger: "blur" }, |
| | | ], |
| | | productCode: [ |
| | | { required: true, message: "产åç¼å·ä¸è½ä¸ºç©º", trigger: "blur" }, |
| | | ], |
| | | productModel: [ |
| | | { required: true, message: "产ååå·ä¸è½ä¸ºç©º", trigger: "blur" }, |
| | | ], |
| | | customerName: [ |
| | | { required: true, message: "客æ·åç§°ä¸è½ä¸ºç©º", trigger: "blur" }, |
| | | ], |
| | | contact: [ |
| | | { required: true, message: "èç³»æ¹å¼ä¸è½ä¸ºç©º", trigger: "blur" }, |
| | | ], |
| | | feedbackTime: [ |
| | | { required: true, message: "å馿¶é´ä¸è½ä¸ºç©º", trigger: "change" }, |
| | | ], |
| | | problemDesc: [ |
| | | { required: true, message: "客æ·åé¦é®é¢ä¸è½ä¸ºç©º", trigger: "blur" }, |
| | | ], |
| | | status: [ |
| | | { required: true, message: "å¤çç¶æä¸è½ä¸ºç©º", trigger: "change" }, |
| | | ], |
| | | }, |
| | | }); |
| | | |
| | | const { queryParams, form, rules } = toRefs(data); |
| | | |
| | | // æ¥è¯¢å表ï¼ä»
å端çéï¼ä¸è°æ¥å£ï¼ |
| | | function getList() { |
| | | loading.value = true; |
| | | const list = afterSalesList.value.filter((item) => { |
| | | if ( |
| | | queryParams.value.productModel && |
| | | !item.productModel |
| | | ?.toLowerCase() |
| | | .includes(queryParams.value.productModel.toLowerCase()) |
| | | ) { |
| | | return false; |
| | | } |
| | | if ( |
| | | queryParams.value.customerName && |
| | | !item.customerName |
| | | ?.toLowerCase() |
| | | .includes(queryParams.value.customerName.toLowerCase()) |
| | | ) { |
| | | return false; |
| | | } |
| | | if (queryParams.value.status && item.status !== queryParams.value.status) { |
| | | return false; |
| | | } |
| | | if ( |
| | | Array.isArray(queryParams.value.feedbackRange) && |
| | | queryParams.value.feedbackRange.length === 2 |
| | | ) { |
| | | const [start, end] = queryParams.value.feedbackRange; |
| | | const dateStr = item.feedbackTime?.slice(0, 10); |
| | | if (dateStr < start || dateStr > end) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | }); |
| | | total.value = list.length; |
| | | // æ¤å¤æªåå页ï¼ä»
模æå
¨éå±ç¤º |
| | | afterSalesList.value = list; |
| | | loading.value = false; |
| | | } |
| | | |
| | | // åæ¶ |
| | | function cancel() { |
| | | open.value = false; |
| | | reset(); |
| | | } |
| | | |
| | | // 表åéç½® |
| | | function reset() { |
| | | form.value = { |
| | | id: null, |
| | | contractNo: null, |
| | | productCode: null, |
| | | productModel: null, |
| | | customerName: null, |
| | | contact: null, |
| | | feedbackTime: null, |
| | | problemDesc: null, |
| | | repairInfo: null, |
| | | result: null, |
| | | status: "0", |
| | | remark: null, |
| | | }; |
| | | proxy.resetForm("formRef"); |
| | | } |
| | | |
| | | // æç´¢ |
| | | function handleQuery() { |
| | | queryParams.value.pageNum = 1; |
| | | getList(); |
| | | } |
| | | |
| | | // éç½® |
| | | function resetQuery() { |
| | | proxy.resetForm("queryForm"); |
| | | queryParams.value.feedbackRange = []; |
| | | handleQuery(); |
| | | } |
| | | |
| | | // å¤é |
| | | function handleSelectionChange(selection) { |
| | | ids.value = selection.map((item) => item.id); |
| | | single.value = selection.length !== 1; |
| | | multiple.value = !selection.length; |
| | | } |
| | | |
| | | // æ°å¢ |
| | | function handleAdd() { |
| | | reset(); |
| | | open.value = true; |
| | | title.value = "æ°å¢å®åè´¨éè®°å½"; |
| | | } |
| | | |
| | | // ä¿®æ¹ |
| | | function handleUpdate(row) { |
| | | reset(); |
| | | const current = row || afterSalesList.value.find((item) => item.id === ids.value[0]); |
| | | if (current) { |
| | | form.value = { ...current }; |
| | | open.value = true; |
| | | title.value = "ä¿®æ¹å®åè´¨éè®°å½"; |
| | | } |
| | | } |
| | | |
| | | // æäº¤ |
| | | function submitForm() { |
| | | proxy.$refs["formRef"].validate((valid) => { |
| | | if (valid) { |
| | | if (form.value.id != null) { |
| | | // ä¿®æ¹ï¼æ¿æ¢æ¬å°æ¨¡ææ°æ® |
| | | const index = afterSalesList.value.findIndex( |
| | | (item) => item.id === form.value.id |
| | | ); |
| | | if (index !== -1) { |
| | | afterSalesList.value.splice(index, 1, { ...form.value }); |
| | | } |
| | | proxy.$modal.msgSuccess("ä¿®æ¹æå"); |
| | | } else { |
| | | // æ°å¢ï¼æå
¥æ¬å°æ¨¡ææ°æ® |
| | | const newId = |
| | | afterSalesList.value.length > 0 |
| | | ? Math.max(...afterSalesList.value.map((i) => i.id)) + 1 |
| | | : 1; |
| | | afterSalesList.value.push({ ...form.value, id: newId }); |
| | | proxy.$modal.msgSuccess("æ°å¢æå"); |
| | | } |
| | | open.value = false; |
| | | getList(); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // å é¤ |
| | | function handleDelete(row) { |
| | | const deleteIds = row?.id ? [row.id] : ids.value; |
| | | if (!deleteIds || deleteIds.length === 0) { |
| | | proxy.$modal.msgWarning("请å
éæ©è¦å é¤çè®°å½"); |
| | | return; |
| | | } |
| | | ElMessageBox.confirm( |
| | | 'æ¯å¦ç¡®è®¤å é¤éä¸çå®åè´¨éè®°å½ï¼', |
| | | "è¦å", |
| | | { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | } |
| | | ) |
| | | .then(() => { |
| | | // å端å 餿¬å°æ¨¡ææ°æ® |
| | | afterSalesList.value = afterSalesList.value.filter( |
| | | (item) => !deleteIds.includes(item.id) |
| | | ); |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getList(); |
| | | }) |
| | | .catch(() => {}); |
| | | } |
| | | |
| | | // å¯¼åº |
| | | function handleExport() { |
| | | proxy.$modal.msgSuccess("导åºåè½ä¸ºæ¼ç¤ºåè½ï¼å½åæªå¯¹æ¥å®é
å¯¼åºæ¥å£"); |
| | | } |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .mb8 { |
| | | margin-bottom: 8px; |
| | | } |
| | | .dialog-footer { |
| | | text-align: right; |
| | | } |
| | | </style> |
| | | |