From a2d9fcb259621829bf4ec9680b5dbeac95ab5805 Mon Sep 17 00:00:00 2001
From: gaoluyang <2820782392@qq.com>
Date: 星期四, 15 十月 2026 16:19:54 +0800
Subject: [PATCH] fix(crm): 销售目标达成分析默认查当前季度

---
 src/views/mes/dv/spare/modules/action.vue |   95 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 95 insertions(+), 0 deletions(-)

diff --git a/src/views/mes/dv/spare/modules/action.vue b/src/views/mes/dv/spare/modules/action.vue
new file mode 100644
index 0000000..fb77318
--- /dev/null
+++ b/src/views/mes/dv/spare/modules/action.vue
@@ -0,0 +1,95 @@
+<script setup lang="ts">
+import type { SpareMovement, SparePart, SpareAction } from '#/api/mes/dv/spare';
+import type { FormInstance } from 'ant-design-vue';
+import { computed, reactive, ref } from 'vue';
+import { useVbenModal } from '@vben/common-ui';
+import { Alert, Form, Input, InputNumber, Select } from 'ant-design-vue';
+import { getSparePage, spareAction } from '#/api/mes/dv/spare';
+import { getRepairPage } from '#/api/mes/dv/repair';
+import { getSimpleUserList } from '#/api/system/user';
+const emit = defineEmits(['success']);
+const formRef = ref<FormInstance>();
+const type = ref<'issue'|'receive'|'return'>('issue');
+const saving = ref(false);
+const loadError = ref('');
+const original = ref<SpareMovement>();
+const parts = ref<SparePart[]>([]);
+const repairs = ref<{label:string;value:number}[]>([]);
+const users = ref<{label:string;value:number}[]>([]);
+const model = reactive<SpareAction>({ requestKey: '', quantity: 1, remark: '' });
+const fixedPart = ref(false), fixedRepair = ref(false);
+let partSeq = 0, repairSeq = 0, openSeq = 0;
+const title = computed(() => ({issue:'缁翠慨棰嗙敤澶囦欢',receive:'澶囦欢鍏ュ簱',return:'閫�鍥炴湭浣跨敤澶囦欢'})[type.value]);
+const chosenPart = computed(() => parts.value.find(p => p.id === model.sparePartId));
+const maxQuantity = computed(() => type.value === 'return' ? Number(original.value?.returnableQuantity ?? 0) : type.value === 'issue' ? Number(chosenPart.value?.stockQuantity ?? 0) : undefined);
+const required = [{required:true,message:'璇峰~鍐欐椤�'}];
+async function searchParts(name='') {
+  const seq = ++partSeq;
+  try { const result = await getSparePage({pageNo:1,pageSize:50,status:0,name}); if(seq === partSeq) parts.value=result.list; }
+  catch { if(seq===partSeq) loadError.value='澶囦欢鍔犺浇澶辫触锛岃閲嶆柊鎵撳紑寮圭獥鍚庨噸璇�'; }
+}
+async function searchRepairs(code='') {
+  const seq=++repairSeq;
+  try { const result=await getRepairPage({pageNo:1,pageSize:50,code} as Parameters<typeof getRepairPage>[0]);
+    if(seq===repairSeq) repairs.value=result.list.filter(r=>r.status===0||r.status===1).map(r=>({value:r.id!,label:`${r.code} 路 ${r.machineryName || r.name || ''}`}));
+  } catch { if(seq===repairSeq) loadError.value='缁翠慨鍗曞姞杞藉け璐ワ紝璇烽噸鏂版墦寮�寮圭獥鍚庨噸璇�'; }
+}
+const [Modal, modalApi] = useVbenModal({
+  onBeforeClose:()=>!saving.value,
+  async onOpenChange(open) {
+    const seq=++openSeq;
+    if(!open) { partSeq++; repairSeq++; return; }
+    const data=modalApi.getData<{type:'issue'|'receive'|'return';part?:SparePart;repairId?:number;repairCode?:string;original?:SpareMovement}>();
+    type.value=data.type; original.value=data.original; loadError.value='';
+    fixedPart.value=!!data.part||data.type==='return'; fixedRepair.value=!!data.repairId;
+    Object.assign(model,{requestKey:crypto.randomUUID(),sparePartId:data.part?.id,repairId:data.repairId,originalId:data.original?.id,receiverUserId:undefined,quantity:1,remark:''});
+    parts.value=data.part?[data.part]:[]; repairs.value=[]; users.value=[]; formRef.value?.clearValidate();
+    if(data.repairId) repairs.value=[{value:data.repairId,label:data.repairCode || String(data.repairId)}];
+    modalApi.lock();
+    try {
+      const jobs:Promise<unknown>[]=[];
+      if(data.type!=='return'&&!data.part) jobs.push(searchParts());
+      if(data.type==='issue'&&!data.repairId) jobs.push(searchRepairs());
+      if(data.type==='issue') jobs.push(getSimpleUserList().then(list=>{if(seq===openSeq)users.value=list.filter(u=>u.id!==undefined).map(u=>({value:u.id!,label:u.nickname}));}));
+      await Promise.all(jobs);
+    } catch { if(seq===openSeq) loadError.value='鍩虹鏁版嵁鍔犺浇澶辫触锛岃閲嶆柊鎵撳紑寮圭獥鍚庨噸璇�'; }
+    finally { if(seq===openSeq) modalApi.unlock(); }
+  },
+  async onConfirm() {
+    if(saving.value||loadError.value)return;
+    await formRef.value?.validate();
+    saving.value=true;modalApi.lock();
+    try { await spareAction(type.value,{...model}); emit('success');saving.value=false;await modalApi.close(); }
+    finally { saving.value=false;modalApi.unlock(); }
+  },
+});
+const quantityRules = [{required:true,message:'璇疯緭鍏ユ暟閲�'}, {validator:async (_:unknown,value:number)=>{
+  if(!Number.isFinite(value)||value<=0)throw new Error('鏁伴噺蹇呴』澶т簬0');
+  if(maxQuantity.value!==undefined && value>maxQuantity.value) throw new Error(type.value==='return'?'瓒呰繃鍙��鍥炴暟閲�':'瓒呰繃褰撳墠鍙敤搴撳瓨');
+}}];
+</script>
+<template>
+  <Modal :title="title" class="w-full sm:w-[600px]">
+    <Alert v-if="loadError" :message="loadError" type="error" class="mb-4" />
+    <Alert v-else class="mb-4" type="info" :message="type === 'issue' ? '棰嗙敤绔嬪嵆鎵e噺搴撳瓨锛屽苟鍏宠仈褰撳墠缁翠慨鍗曘�傝鏍稿澶囦欢銆侀鐢ㄤ汉鍜屾暟閲忋��' : type === 'return' ? '浠呴��鍥炴湭浣跨敤鐨勫浠讹紝绱閫�鍥炰笉鑳借秴杩囧師棰嗙敤鏁伴噺銆�' : '鍏ュ簱澧炲姞搴撳瓨骞朵繚鐣欒褰曪紝璇峰~鍐欒ˉ璐ф潵婧愭垨鍗曟嵁缂栧彿銆�'" />
+    <Form ref="formRef" :model="model" layout="vertical">
+      <Form.Item v-if="type === 'return'" label="鍘熼鐢ㄨ褰�">
+        {{ original?.repairCode }} 路 {{ original?.sparePartName }} 路 鍙��鍥� {{ original?.returnableQuantity }} {{ original?.unit }}
+      </Form.Item>
+      <Form.Item v-else label="澶囦欢" name="sparePartId" :rules="required">
+        <Select v-model:value="model.sparePartId" show-search :disabled="fixedPart || saving" :filter-option="false" placeholder="杈撳叆澶囦欢鍚嶇О鏌ユ壘" :options="parts.map(p=>({value:p.id,label:p.code+' 路 '+p.name+' 路 搴撳瓨 '+p.stockQuantity+' '+p.unit}))" @search="searchParts" />
+      </Form.Item>
+      <Form.Item v-if="type === 'issue'" label="鍏宠仈缁翠慨鍗�" name="repairId" :rules="required">
+        <Select v-model:value="model.repairId" :disabled="fixedRepair || saving" show-search :filter-option="false" :options="repairs" placeholder="杈撳叆缁翠慨鍗曠紪鍙锋煡鎵撅紙鑽夌鎴栫淮淇腑锛�" @search="searchRepairs" />
+      </Form.Item>
+      <Form.Item v-if="type === 'issue'" label="棰嗙敤浜�" name="receiverUserId" :rules="required">
+        <Select v-model:value="model.receiverUserId" show-search option-filter-prop="label" :options="users" placeholder="璇烽�夋嫨棰嗙敤浜�" :disabled="saving" />
+      </Form.Item>
+      <Form.Item :label="'鏁伴噺'+(chosenPart ? '锛�'+chosenPart.unit+'锛�' : '')" name="quantity" :rules="quantityRules">
+        <InputNumber v-model:value="model.quantity" :min="0.001" :precision="3" class="w-full" :disabled="saving" />
+      </Form.Item>
+      <Form.Item label="鎿嶄綔璇存槑" name="remark" :rules="required"><Input.TextArea v-model:value="model.remark" :maxlength="500" :rows="3" :disabled="saving" placeholder="濉啓棰嗙敤鐢ㄩ�斻�佸叆搴撴潵婧愭垨閫�鍥炲師鍥�" /></Form.Item>
+    </Form>
+  </Modal>
+</template>
+

--
Gitblit v1.9.3