tangning 2 سال پیش
والد
کامیت
b4db8d2f92

+ 2 - 2
.env.development

@@ -7,13 +7,13 @@ VITE_PUBLIC_PATH = ./
 # Cross-domain proxy, you can configure multiple
 # Please note that no line breaks
 # VITE_PROXY = [["/basic-api","http://localhost:3000"],["/upload","https://testeur.4dkankan.com/service/manage/common/upload/files"],["/service","https://testeur.4dkankan.com"]]
-VITE_PROXY = [["/basic-api","http://localhost:3000"],["/upload","https://v4-uat.4dkankan.com/service/manage/common/upload/files"],["/service","http://192.168.0.38:8188/service"]]
+VITE_PROXY = [["/basic-api","http://localhost:3000"],["/upload","https://v4-uat.4dkankan.com/service/manage/common/upload/files"],["/service","https://v4-uat.4dkankan.com"]]
 
 # Delete console
 VITE_DROP_CONSOLE = false
 
 # Basic interface address SPA
-VITE_GLOB_API_URL=
+VITE_GLOB_API_URL=/service
 
 # File upload address, optional
 VITE_GLOB_UPLOAD_URL=/upload

+ 115 - 3
src/api/spares/index.ts

@@ -17,8 +17,10 @@ enum Api {
   sendRegister = '/service/sale/salePersonnel/sendRegister',//发货登记
   supplyOrderList = '/service/sale/supplyPersonnel/supplyOrderList',//维修备件管理 供应链 列表
   partRecovery = '/service/sale/supplyPersonnel/partRecovery',//备件回收
+  partOut = '/service/sale/supplyPersonnel/partOut',//备件出库
   repairOrderList = '/service/sale/repairPersonnel/repairOrderList',//工单列表
   detail = '/service/sale/repairInfo/details',//工单详情
+  process = '/service/sale/repairInfo/process',//工单流程
   partList = '/service/sale/part/list',//备件列表
   faultAllList = '/service/sale/fault/allList',//故障列表
   checkRegisterInfo = ' /service/sale/repairPersonnel/checkRegisterInfo',//维修登记,维修完成回显详情
@@ -26,8 +28,15 @@ enum Api {
   partAllList = '/service/sale/part/allList',//全部备件列表没分页
   partAddOrUpdate = '/service/sale/part/addOrUpdate',//新增设备,修改设备,修改状态
   partInStock = '/service/sale/part/inStock',//添加库存,入库
+  repairAddPart = '/service/sale/repairPersonnel/repairAddPart',//维修中添加备件
   repairOver = '/service/sale/repairPersonnel/repairOver',//维修完成
   partInStockLog = '/service/sale/part/inStockLog',//添加库存,入库 日志列表
+  partInfoList = '/service/sale/supplyPersonnel/partInfo',//备件入库
+  repairTesterList = '/service/sale/repairTest/repairTesterList',//测试列表
+  testPassOrFail = '/service/sale/repairTest/testPassOrFail',//测试列表
+  queryList = '/service/sale/repairInfo/list',//工单查询
+  export = '/service/sale/repairPay/export',//导出列表
+  repairPayList = '/service/sale/repairPay/list',//售后列表
 }
 
 /**
@@ -59,7 +68,16 @@ enum Api {
    },
  });
 
-
+ export const process = (params) =>
+ defHttp.get<Result>({
+   url: Api.process,
+   params: params,
+   headers: {
+     // @ts-ignore
+     ignoreCancelToken: true,
+   },
+ });
+ 
  export const orderReceiving = (params) =>
  defHttp.post<Result>({
    url: Api.orderReceiving,
@@ -93,6 +111,28 @@ enum Api {
    },
  });
 
+ export const exportFile = (params) =>
+ defHttp.get<Result>({
+   url: Api.export,
+   params: params,
+   // data: params,
+   headers: {
+     // @ts-ignore
+     ignoreCancelToken: true,
+   },
+ });
+
+ export const repairPayList = (params) =>
+ defHttp.post<Result>({
+   url: Api.repairPayList,
+   params: params,
+   // data: params,
+   headers: {
+     // @ts-ignore
+     ignoreCancelToken: true,
+   },
+ });
+
  export const updateRemark = (params) =>
  defHttp.post<Result>({
    url: Api.updateRemark,
@@ -104,9 +144,9 @@ enum Api {
    },
  });
 
- export const allList = (params) =>
+ export const queryList = (params) =>
  defHttp.post<Result>({
-   url: Api.allList,
+   url: Api.queryList,
    params: params,
    // data: params,
    headers: {
@@ -115,6 +155,16 @@ enum Api {
    },
  });
 
+ export const allList = (params) =>
+ defHttp.get<Result>({
+   url: Api.allList,
+   params: params,
+   // data: params,
+   headers: {
+     // @ts-ignore
+     ignoreCancelToken: true,
+   },
+ });
 
  export const getPriceList = (params) =>
  defHttp.get<Result>({
@@ -173,6 +223,38 @@ enum Api {
    },
  });
  
+ export const partInfo = (params) =>
+ defHttp.get<Result>({
+   url: Api.partInfoList,
+   params: params,
+   // data: params,
+   headers: {
+     // @ts-ignore
+     ignoreCancelToken: true,
+   },
+ });
+ 
+ export const partRecovery = (params) =>
+ defHttp.post<Result>({
+   url: Api.partRecovery,
+   params: params,
+   // data: params,
+   headers: {
+     // @ts-ignore
+     ignoreCancelToken: true,
+   },
+ });
+
+ export const partOut = (params) =>
+ defHttp.post<Result>({
+   url: Api.partOut,
+   params: params,
+   // data: params,
+   headers: {
+     // @ts-ignore
+     ignoreCancelToken: true,
+   },
+ });
  export const repairOrderList = (params) =>
  defHttp.post<logDataResule>({
    url: Api.repairOrderList,
@@ -272,6 +354,36 @@ enum Api {
      ignoreCancelToken: true,
    },
  });
+
+ export const repairAddPart = (params) =>
+ defHttp.post<detailResult>({
+   url: Api.repairAddPart,
+   params: params,
+   headers: {
+     // @ts-ignore
+     ignoreCancelToken: true,
+   },
+ });
+
+ export const testPassOrFail = (params) =>
+ defHttp.post<detailResult>({
+   url: Api.testPassOrFail,
+   params: params,
+   headers: {
+     // @ts-ignore
+     ignoreCancelToken: true,
+   },
+ });
+ 
+ export const repairTesterList = (params) =>
+ defHttp.post<detailResult>({
+   url: Api.repairTesterList,
+   params: params,
+   headers: {
+     // @ts-ignore
+     ignoreCancelToken: true,
+   },
+ });
  export const DownExport = (params) =>
   defHttp.downloadFile<FileStream>({
     url: Api.export + `?lang=${params.lang}`,

+ 1 - 0
src/api/spares/model.ts

@@ -193,6 +193,7 @@ export interface detailResult {
   repairRegisterVo:any;
   orderReceivingVo:any;
   repairPay:any;
+  RepairComment:any;
   priceList:any[];
 }
 export type InvoiceListResul = BasicPageParams<InvoiceList>;

+ 4 - 0
src/locales/lang/zh-CN/routes/spares.ts

@@ -18,5 +18,9 @@ export default {
     21:'待跟进',
     22:'维修完成',
     23:'已完结',
+    24:'待备料',
+    25:'已备料',
+    26:'待测试',
+    27:'测试完成',
   },
 }

+ 92 - 80
src/views/spares/detail.vue

@@ -17,29 +17,29 @@
             <DescriptionsItem label="产品名称" v-if="detailData.repairerVo"> {{ t(`routes.device.type.${detailData.repairerVo.cameraType || 1}`)  }} </DescriptionsItem>
             <DescriptionsItem label="产品SN码" v-if="detailData.repairerVo"> {{ detailData.repairerVo.cameraSnCode }} </DescriptionsItem>
             <DescriptionsItem label="保修届满日期"> {{ detailData.orderReceivingVo.warrantyExpirationDate }} </DescriptionsItem>
-            <DescriptionsItem label="保修日期"> {{ detailData.orderReceivingVo.warrantyExpirationDate }} </DescriptionsItem>
+            <DescriptionsItem label="报修日期" > {{ detailData.repairerVo?.createTime }} </DescriptionsItem>
             <DescriptionsItem label="送修方式" v-if="detailData.customerAddress"> {{ detailData.customerAddress.sendType?'前台送修':'快递寄送' }} </DescriptionsItem>
-            <DescriptionsItem label="保修类型"> {{ detailData.orderReceivingVo.warrantyType }} </DescriptionsItem>
+            <DescriptionsItem label="保修类型"> {{ detailData.customerAddress.warrantyType == 0?'保修期内':detailData.customerAddress.warrantyType == 1?'保修期外':'非保修项目' }} </DescriptionsItem>
             <DescriptionsItem label="维修单号"> {{ detailData.orderReceivingVo.repairId }} </DescriptionsItem>
             <DescriptionsItem label="上次维修单号" :span="2"> {{ detailData.orderReceivingVo.repairerId }} </DescriptionsItem>
             <DescriptionsItem label="故障描述" :span="3">
               <div>
-                <p>{{ detailData.orderReceivingVo.orderFaultMsg }}</p>
+                <p>{{ detailData.repairerVo.faultMsg }}</p>
                 <ImagePreviewGroup>
-                  <Image :width="80" v-for="item in detailData.orderReceivingVo.orderFaultImg" :key="item" :src="item"></Image>
+                  <Image :width="80" v-for="item in detailData.repairerVo.faultImg" :key="item" :src="item"></Image>
                 </ImagePreviewGroup>
               </div> 
             </DescriptionsItem>
-            <DescriptionsItem label="机器外观" v-if="detailData.orderReceivingVo">
+            <DescriptionsItem label="机器外观">
               <div>
-                <p>{{ detailData.orderReceivingVo.paymentStatus }}</p>
+                <p>{{ detailData.repairRegisterVo?.orderFaultMsg }}</p>
                 <ImagePreviewGroup>
-                  <Image :width="80" v-for="item in [demopng,logo,demopng]" :key="item" :src="item"></Image>
+                  <Image :width="80" v-for="item in detailData.orderReceivingVo?.orderFaultImg" :key="item" :src="item"></Image>
                 </ImagePreviewGroup>
               </div> 
             </DescriptionsItem>
-            <DescriptionsItem label="售后工程师" v-if="detailData.orderReceivingVo"> {{ detailData.orderReceivingVo.sysUserName }} </DescriptionsItem>
-            <DescriptionsItem label="接单日期" v-if="detailData.orderReceivingVo"> {{ detailData.orderReceivingVo.createTime }} </DescriptionsItem>
+            <DescriptionsItem label="售后工程师"> {{ detailData.orderReceivingVo?.sysUserName }} </DescriptionsItem>
+            <DescriptionsItem label="接单日期"> {{ detailData.orderReceivingVo?.createTime }} </DescriptionsItem>
             <DescriptionsItem label="检测结果" v-if="detailData.repairRegisterVo">
               <div>
                 <p>{{detailData.repairRegisterVo.checkResult}}</p>
@@ -48,20 +48,20 @@
                 </ImagePreviewGroup>
               </div> 
             </DescriptionsItem>
-            <DescriptionsItem label="检测日期" v-if="detailData.orderReceivingVo"> {{ detailData.repairRegisterVo.createTime }} </DescriptionsItem>
-            <DescriptionsItem label="所需备件" v-if="detailData.orderReceivingVo"> {{ detailData.orderReceivingVo.shipMobile }} </DescriptionsItem>
+            <DescriptionsItem label="检测日期"> {{ detailData.repairRegisterVo?.createTime }} </DescriptionsItem>
+            <DescriptionsItem label="所需备件"> {{ detailData.orderReceivingVo?.shipMobile }} </DescriptionsItem>
           </Descriptions>
           <Descriptions title="维修清单" :column="3" layout="vertical">
             <DescriptionsItem label="备件信息" :span="3">
               <BasicTable @register="registerTable"></BasicTable>
             </DescriptionsItem>
           </Descriptions>
-          <Descriptions  :column="3" v-if="detailData.repairRegisterVo">
-            <DescriptionsItem label="维修工程师"> {{ detailData.repairRegisterVo.sysUserName }}</DescriptionsItem>
-            <DescriptionsItem label="维修完成日期"> {{ detailData.repairRegisterVo.overTime }} </DescriptionsItem>
-            <DescriptionsItem label="维修记录"> {{ detailData.repairRegisterVo.remark }} </DescriptionsItem>
-            <DescriptionsItem label="测试工程师" v-if="detailData.RepairTestVo"> {{ detailData.RepairTestVo.sysUserName }} </DescriptionsItem>
-            <DescriptionsItem label="测试通过时间" :span="2"> {{ detailData.repairRegisterVo.passTime }} </DescriptionsItem>
+          <Descriptions  :column="3">
+            <DescriptionsItem label="维修工程师"> {{ detailData.repairRegisterVo?.sysUserName }}</DescriptionsItem>
+            <DescriptionsItem label="维修完成日期"> {{ detailData.repairRegisterVo?.overTime }} </DescriptionsItem>
+            <DescriptionsItem label="维修记录"> {{ detailData.repairRegisterVo?.remark }} </DescriptionsItem>
+            <DescriptionsItem label="测试工程师"> {{ detailData.RepairTestVo?.sysUserName }} </DescriptionsItem>
+            <DescriptionsItem label="测试通过时间" :span="2"> {{ detailData.repairRegisterVo?.passTime }} </DescriptionsItem>
             <DescriptionsItem label="支付方式" :span="3"> 
               <div v-if="detailData.repairPay">
                 <p>{{ detailData.repairPay.payType==1?'微信':detailData.repairPay.payType==2?'支付宝':'银行' }}</p>
@@ -73,7 +73,7 @@
             <DescriptionsItem label="取回方式" v-if="detailData.customerAddress"> {{detailData.customerAddress.getType==0?'前台取回':`快递寄回 ${detailData.customerAddress.getTrackingNum}`}}</DescriptionsItem>
             <DescriptionsItem label="收件信息" :span="2" v-if="detailData.customerAddress"> {{detailData.customerAddress.getAddrName}} {{ detailData.customerAddress.getAddrName }}{{ detailData.customerAddress.getAddress }} </DescriptionsItem>
           </Descriptions>
-          <Descriptions title="单据下载" :column="3">
+          <!-- <Descriptions title="单据下载" :column="3">
             <DescriptionsItem label="维修记录" :span="3"> 
               <div class="link">
                 <a v-for="(item,index) in ['www.baidusss.com','www.baidudd.com']" :key="index" :href="item" target="_blank">
@@ -87,32 +87,33 @@
                 <a :href="'www.baidudd.com'" target="_blank">2022101200001维修工单.pdf </a>
               </div>  
             </DescriptionsItem>
+          </Descriptions> -->
+          <Descriptions title="客户评价" :column="3" v-if="detailData.RepairComment">
+            <DescriptionsItem label="评价内容" > {{ detailData.RepairComment.comment }} </DescriptionsItem>
+            <DescriptionsItem label="评分"> {{ detailData.RepairComment.starRank }} </DescriptionsItem>
           </Descriptions>
-          <Descriptions title="客户评价" :column="3" v-if="detailData.orderReceivingVo">
-            <DescriptionsItem label="评价内容" > {{ detailData.orderReceivingVo.userName }} </DescriptionsItem>
-            <DescriptionsItem label="评分"> {{ detailData.orderReceivingVo.userName }} </DescriptionsItem>
-          </Descriptions>
-          <Descriptions title="备注" :column="3" v-if="detailData.repairerVo">
-            <DescriptionsItem label="备注内容"> {{ detailData.repairerVo.remark }} </DescriptionsItem>
+          <Descriptions title="备注" :column="3">
+            <DescriptionsItem label="备注内容"> {{ detailData.repairerVo?.remark }} </DescriptionsItem>
           </Descriptions>
         </div>
       </div>
       <div class="content_right">
         <Timeline>
-          <TimelineItem v-for="(item,indexs) in detailData.priceList" :color="indexs == 0 ?'red':'green'" :key="indexs">
+          <TimelineItem v-for="(item,indexs) in stepList" :color="indexs == 0 ?'red':'green'" :key="indexs">
             <div class="timeItem">
               <div class="name">
-                <span>维修完毕</span>
-                <a-button style="margin-left:50px" @click="handleSubmit"> 接单 </a-button>
+                <span>{{item.remark}}</span>
+                <a-button style="margin-left:50px" @click="handleSubmit"  v-for="butItem in butList" :key="butItem" v-if="indexs == 0"> {{butItem}} </a-button>
               </div>
-              <div class="status">罗*升 完成工单 <span>10-15 12:30</span></div>
-              <div class="itemText">前台取回 / 快递寄回  SF151315352892</div>
-              <div class="itemText">检测结论: 外壳有轻微划痕</div>
+              <div class="status">{{item.sysUserName}}完成{{item.remark}} <span>{{item.createTime}}</span></div>
+              <div class="itemText" v-if="item.customerAddress">{{ item.customerAddress.getType==0?'前台取回':`快递寄回  ${item.customerAddress.getTrackingNum}`}}</div>
+              <div class="itemText" v-if="item.customerAddress">{{ item.customerAddress.sendType==0?'前台送修':`快递寄送  ${item.customerAddress.sendTrackingNum}`}}</div>
+              <div class="itemText" v-if="item.repairRegisterVo">检测结论: {{ item.repairRegisterVo.checkResult}}</div>
               <div class="itemText">所需备件: 镜头x2、电池x1</div>
-              <div class="itemText">机器外观: 外壳有轻微划痕</div>
+              <div class="itemText" v-if="item.orderReceivingVo">机器外观: {{ item.orderReceivingVo.orderFaultMsg}}</div>
               <div class="iamgeList">
                 <ImagePreviewGroup>
-                  <Image :width="80" v-for="item in [demopng,logo,demopng]" :key="item" :src="item"></Image>
+                  <Image :width="80" v-for="item in [logo]" :key="item" :src="item"></Image>
                 </ImagePreviewGroup>
               </div>
             </div>
@@ -121,8 +122,8 @@
       </div>
     </div>
     <div class="bottom_but">
-      <a-button type="primary" @click="goBack">
-        接单
+      <a-button type="primary" v-for="item in butList" :key="item" @click="goBack">
+        {{item}}
       </a-button>
       <a-button type="primary" @click="goBack">
         {{ t('common.back') }}
@@ -135,72 +136,87 @@ import { ref, onMounted, reactive } from 'vue';
 import { useI18n } from '/@/hooks/web/useI18n';
 import { useRouter } from 'vue-router';
 import { useMessage } from '/@/hooks/web/useMessage';
-import { detail } from '/@/api/spares';
+import { detail ,process } from '/@/api/spares';
 import { detailResult } from '/@/api/spares/model';
 import logo from '/@/assets/images/grey-logo.png';
-import demopng from '/@/assets/images/demo.png';
 import { BasicTable, useTable, BasicColumn, TableImg, } from '/@/components/Table';
 import { Timeline, TimelineItem, Descriptions, DescriptionsItem, Image, ImagePreviewGroup } from 'ant-design-vue';
+import { cloneDeep } from 'lodash-es';
 const router = useRouter();
 const { createMessage } = useMessage();
 const { t } = useI18n();
 const repairId = ref<string|string[]>(router.currentRoute.value.params.id || '0')
 const detailData = ref<detailResult>({
-  customer:null,
-  customerAddress:null,
-  repairerVo:null,
-  RepairTestVo:null,
-  repairRegisterVo:null,
-  orderReceivingVo:null,
-  repairPay:null,
+  customer:{},
+  customerAddress:{},
+  repairerVo:{},
+  RepairTestVo:{},
+  repairRegisterVo:{},
+  orderReceivingVo:{},
+  repairPay:{},
+  RepairComment:{},
   priceList:[],
 });
+const stepList = ref([])
+const butList = ref([])
 onMounted(() => {
   getData();
 });
-const dataSource = reactive([
-  {
-    id:1,
-    price:265,
-    name:'00',
-    count:2,
-    total:152
-  },{
-    id:2,
-    price:265,
-    name:'00',
-    count:2,
-    total:152
-  },{
-    id:3,
-    price:null,
-    name:'',
-    count:'合计(元)',
-    total:304
-  }
-])
+let dataSource = reactive([])
 const columns: BasicColumn[] = [
   {
         title: '备件名称',
         dataIndex: 'name',
-        width: 180,
+        width: 150,
   },{
         title: '单价(元)',
         dataIndex: 'price',
-        width: 180,
+        width: 100,
   },{
         title: '数量',
         dataIndex: 'count',
-        width: 180,
+        width: 110,
   },{
         title: '小计(元)',
         dataIndex: 'total',
-        width: 180,
+        width: 140,
   },
 ]
 async function getData() {
-  detailData.value = await detail({repairId:repairId.value})
-  console.log('repairId',detailData.value)
+  let res = await detail({repairId:repairId.value})
+  detailData.value = res
+  let countItem = {
+    id:3,
+    price:null,
+    name:'',
+    count:'合计(元)',
+    total:0
+  }
+  dataSource = res.priceList.map(ele => {
+    countItem.total = countItem.total + ele.price * ele.count
+    return {
+      ...ele,
+      total:ele.price * ele.count
+    }
+  })
+  setTableData(cloneDeep([...dataSource,countItem]));
+  const stepRes = await process({repairId:repairId.value})
+  let butTypeList = {
+    0:['接单',],
+    1:['检测登记',],
+    2:['报价',],
+    3:['修改报价',],
+    4:['付款登记',],
+    5:['备件出库',],
+    6:['添加备件', '完成维修'],
+    7:['备件回收',],
+    8:['测试登记',],
+    9:['付款登记',],
+    10:['发货登记',],
+  }
+  butList.value = stepRes[0]?butTypeList[stepRes[0].repairStatus || 0]:['接单']
+  stepList.value = stepRes
+  console.log('repairId',dataSource,stepRes, butList.value)
 }
 function goBack() {
   router.go(-1);
@@ -208,20 +224,16 @@ function goBack() {
 function handleSubmit() {
   createMessage.success(t('common.optSuccess'));
 }
-const [registerTable] = useTable({
-  dataSource,
+const [registerTable, { setTableData }] = useTable({
+  dataSource:dataSource,
   columns,
+  showSummary:true,
   showIndexColumn:false,
   rowKey:'id', 
+  pagination: false,
   bordered: true,
   canResize: false,
 });
-// import { unref } from 'vue';
-
-// const { currentRoute, replace } = useRouter();
-
-// const { params, query } = unref(currentRoute);
-// const { path, _redirect_type = 'path' } = params;
 </script>
 <style lang="less" scoped>
 .detailPage {
@@ -237,11 +249,11 @@ const [registerTable] = useTable({
     justify-content: space-between;
 
     &_right {
-      width: 300px;
+      width: 400px;
       padding: 40px 20px;
     }
     &_left {
-      width: calc(100% - 300px);
+      width: calc(100% - 400px);
     }
   }
   .bottom_but{

+ 5 - 5
src/views/work/addAccessoryModel.vue

@@ -28,7 +28,7 @@ import { defineComponent, h, onMounted, reactive, ref } from 'vue';
 import { BasicModal, useModalInner } from '/@/components/Modal';
 import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
 import { useMessage } from '/@/hooks/web/useMessage';
-import { partAllList, faultAllList, checkRegister } from '/@/api/spares';
+import { partAllList, faultAllList, checkRegister, repairAddPart } from '/@/api/spares';
 import { useI18n } from '/@/hooks/web/useI18n';
 import { uploadApi } from '/@/api/product/index';
 
@@ -198,7 +198,7 @@ export default defineComponent({
     function addSchemas(number) {
       let parentList: FormSchema[] = [
         {
-          field: 'part_id' + number,
+          field: 'partId' + number,
           label: '备件' + number,
           component: 'ApiSelect',
           colProps: {
@@ -257,15 +257,15 @@ export default defineComponent({
             let partList = [];
             for (let s = 1; s <= n.value; s++) {
               console.log('params', params, partList);
-              if (params[`part_id${s}`]) {
+              if (params[`partId${s}`]) {
                 partList.push({
-                  part_id: params[`part_id${s}`],
+                  partId: params[`partId${s}`],
                   partCount: params[`partCount${s}`],
                 });
               }
             }
             console.log('params', params, partList);
-            await checkRegister({
+            await repairAddPart({
               ...params,
               partList,
             });

+ 55 - 60
src/views/work/aftermarket.vue

@@ -1,19 +1,12 @@
 <template>
-  <PageWrapper contentBackground>
-    <template #footer>
-      <a-tabs v-model:activeKey="tableType" @change="changeTable">
-        <a-tab-pane :key="0" :tab="t('routes.scene.tableType.0')" />
-        <a-tab-pane :key="1" :tab="t('routes.scene.tableType.1')" />
-      </a-tabs></template
-    >
-    <div class="desc-wrap-BasicTable">
     <BasicTable @register="registerTable">
+      <template #toolbar>
+        <a-button type="primary" @click="handleExport"> 导出</a-button>
+      </template>
     </BasicTable>
-  </div>
-</PageWrapper>
 </template>
 <script lang="ts">
-import { defineComponent, onMounted, ref } from 'vue';
+import { defineComponent, onMounted, ref, h, computed } from 'vue';
 import { PageWrapper } from '/@/components/Page';
 import {
   BasicTable,
@@ -30,7 +23,9 @@ import { usePermissionStore } from '/@/store/modules/permission';
 import recoveryModal from './recoveryModal.vue';
 import { useModal } from '/@/components/Modal';
 import { useRouter } from 'vue-router'
-import { saleOrderList } from '/@/api/spares';
+import { repairPayList, DownExport } from '/@/api/spares';
+import { useMessage } from '/@/hooks/web/useMessage';
+import { useLocaleStore } from '/@/store/modules/locale';
 export default defineComponent({
   components: {
     BasicTable,
@@ -47,63 +42,63 @@ export default defineComponent({
     const router = useRouter()
     const { getCheckPerm } = permissionStore;
     const tableType = ref<Recordable>(0); //0看看 、1看见、2深时
+    const { createConfirm } = useMessage();
+    const localeStore = useLocaleStore();
+    const isEn = computed(() => localeStore.getLocale === 'en');
     onMounted(() => {
       // console.log(router.currentRoute.value.params.id);
     });
     const columns: BasicColumn[] = [
       {
-        title: '报修日期',
+        title: '下单时间',
         dataIndex: 'createTime',
         width: 180,
       },
       {
-        title: '客户名称',
-        dataIndex: 'operationType',
-        width: 80,
-        customRender: ({ record }) => {
-          return t(`routes.equity.operation.${record.operationType || 0}`);
-        },
+        title: '订单号',
+        dataIndex: 'orderSn',
+        width: 150,
       },
       {
-        title: '产品类型',
-        dataIndex: 'cameraType',
-        width: 80,
-        customRender: ({ record }) => {
-          return t(`routes.equity.operation.${record.cameraType || 0}`);
-        },
+        title: 'OpenId',
+        dataIndex: 'wxPayOpenId',
+        width: 100,
       },
       {
-        title: '产品SN码',
-        dataIndex: 'cameraSnCode',
-        width: 100,
+        title: '维修单号',
+        dataIndex: 'repairId',
+        width: 150,
       },
       {
-        title: '故障描述',
-        dataIndex: 'faultMsg',
-        width: 100,
+        title: '订单金额(元)',
+        dataIndex: 'payAmount',
+        width: 130,
       },
       {
-        title: '送修方式',
-        dataIndex: 'sendType',
+        title: '支付方式',
+        dataIndex: 'payType	',
         width: 100,
         customRender: ({ record }) => {
-          return record.sendType == 0 ? '前台送修' : '快递寄送';
+          return record.payType	 == 0 ? '银行转账' : record.payType	 == 1 ? '微信' : '支付宝';
         },
       },
       {
-        title: '快递单号',
-        dataIndex: 'sendTrackingNum',
-        width: 100,
+        title: '支付时间',
+        dataIndex: 'payTime',
+        width: 150,
       },
       {
-        title: '状态',
-        dataIndex: 'status',
+        title: '交易号',
+        dataIndex: 'tradeNo',
         width: 100,
       },
       {
-        title: '工单号',
-        dataIndex: 'repairId',
+        title: '订单状态',
+        dataIndex: 'payStatus',
         width: 100,
+        customRender: ({ record }) => {
+          return record.payType	 == 0 ? '未支付' : record.payType	 == 1 ? '已支付' : '支付失败';
+        },
       },
     ];
     const searchForm: Partial<FormProps> = {
@@ -114,27 +109,18 @@ export default defineComponent({
       },
       schemas: [
         {
-          field: 'customerName',
-          component: 'Input',
-          label: '客户名称',
-          colProps: {
-            xl: 7,
-            xxl: 7,
-          },
-        },
-        {
-          field: 'cameraSnCode',
+          field: 'repairId',
           component: 'Input',
-          label: t('routes.device.snCode'),
+          label: '维修单号',
           colProps: {
             xl: 7,
             xxl: 7,
           },
         },
         {
-          field: 'trackingNum',
+          field: 'tradeNo',
           component: 'Input',
-          label: '快递单号',
+          label: '交易号',
           colProps: {
             xl: 7,
             xxl: 7,
@@ -142,7 +128,7 @@ export default defineComponent({
         },
         {
           field: 'timeList',
-          label: '报修日期',
+          label: '支付时间',
           component: 'RangePicker',
           componentProps: {
             maxLength: 100,
@@ -159,7 +145,7 @@ export default defineComponent({
     };
     const [registerRecovery, { openModal }] = useModal();
     const [registerTable, { reload }] = useTable({
-      api: saleOrderList,
+      api: repairPayList,
       columns: columns,
       useSearchForm: true,
       searchInfo: { type: tableType },
@@ -183,16 +169,25 @@ export default defineComponent({
         ...record,
       });
     }
-    function changeTable(val: string) {
-      tableType.value = val;
-      reload();
+    function handleExport() {
+      createConfirm({
+        iconType: 'warning',
+        title: () => h('span', t('common.reminder')),
+        content: () => h('span', t('routes.equity.excelTitle')),
+        onOk: async () => {
+          await DownExport({
+            ...apiData,
+            lang:isEn.value?'en':'cn'
+          });
+        },
+      });
     }
     return {
       registerTable,
       reload,
       t,
       tableType,
-      changeTable,
+      handleExport,
       getCheckPerm,
       handleDetail,
       handleRecover,

+ 3 - 3
src/views/work/checkModel.vue

@@ -197,7 +197,7 @@ export default defineComponent({
     function addSchemas(number) {
       let parentList: FormSchema[] = [
         {
-          field: 'part_id' + number,
+          field: 'partId' + number,
           label: '备件' + number,
           component: 'ApiSelect',
           colProps: {
@@ -256,9 +256,9 @@ export default defineComponent({
         let partList = [];
         for (let s = 1; s <= n.value; s++) {
           console.log('params', params, partList);
-          if (params[`part_id${s}`]) {
+          if (params[`partId${s}`]) {
             partList.push({
-              part_id: params[`part_id${s}`],
+              partId: params[`partId${s}`],
               partCount: params[`partCount${s}`],
             });
           }

+ 115 - 0
src/views/work/deliveryModal.vue

@@ -0,0 +1,115 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="发货登记"
+    @cancel="resetFields"
+    :confirmLoading="loading"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <BasicForm @register="registerForm">
+        <template #text="{ model, field }">
+          {{ model[field]  }}
+        </template>
+      </BasicForm>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, onMounted, reactive, ref } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { sendRegister } from '/@/api/spares';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { uploadApi } from '/@/api/product/index';
+
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const fileFlow = reactive({
+        file:null,
+        type:2,//2-普通发票,3-专用发票
+      })
+      const loading = ref(false)
+      const { createMessage } = useMessage();
+      const schemas: FormSchema[] = [
+          {
+            field: 'repairId',
+            slot: 'text',
+            component: 'Input',
+            label: '维修单号',
+          },{
+            field: 'deviceInfo',
+            component: 'Input',
+            label: '设备信息',
+            slot: 'text',
+            colProps: {
+              span: 18,
+            },
+          },
+          {
+            field: 'trackingNum',
+            component: 'Input',
+            label: '快递单号',
+            required: true,
+            colProps: {
+              span: 18,
+            },
+          }
+      ];
+
+      const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({
+        labelWidth: 120,
+        schemas:schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function onDataReceive(data) {
+        resetFields();
+        setFieldsValue({
+          ...data,
+          deviceInfo:t(`routes.scene.tableType.${data.cameraType}`)+data.cameraSnCode
+        });
+      }
+      const handleSubmit = async () => {
+        loading.value = true
+        try {
+          const params = await validate();
+          await sendRegister(params);
+          closeModal();
+          resetFields();
+          createMessage.success(t('common.optSuccess'));
+          emit('update');
+          loading.value = false
+        } catch (error) {
+          loading.value = false
+          console.log('not passing', error);
+        }
+      };
+      return {
+        register,
+        registerForm,
+        fileFlow,
+        handleSubmit,
+        addListFunc,
+        resetFields,
+        loading,
+        t,
+      };
+    },
+  });
+</script>

+ 328 - 0
src/views/work/detail.vue

@@ -0,0 +1,328 @@
+<template>
+  <div class="detailPage">
+    <div class="topButton">
+      <a-button type="primary" @click="goBack">
+        {{ t('common.back') }}
+      </a-button>
+    </div>
+    <div class="content">
+      <div class="content_left">
+        <div class="content_left_info">
+          <Descriptions title="客户信息" :column="3" v-if="detailData.customer">
+            <DescriptionsItem label="客户名称"> {{ detailData.customer.companyName }}</DescriptionsItem>
+            <DescriptionsItem label="联系人"> {{ detailData.customer.customerName }} </DescriptionsItem>
+            <DescriptionsItem label="联系电话"> {{ detailData.customer.phone }} </DescriptionsItem>
+          </Descriptions>
+          <Descriptions title="产品及故障信息" :column="3" v-if="detailData.orderReceivingVo">
+            <DescriptionsItem label="产品名称" v-if="detailData.repairerVo"> {{ t(`routes.device.type.${detailData.repairerVo.cameraType || 1}`)  }} </DescriptionsItem>
+            <DescriptionsItem label="产品SN码" v-if="detailData.repairerVo"> {{ detailData.repairerVo.cameraSnCode }} </DescriptionsItem>
+            <DescriptionsItem label="保修届满日期"> {{ detailData.orderReceivingVo.warrantyExpirationDate }} </DescriptionsItem>
+            <DescriptionsItem label="报修日期" > {{ detailData.repairerVo?.createTime }} </DescriptionsItem>
+            <DescriptionsItem label="送修方式" v-if="detailData.customerAddress"> {{ detailData.customerAddress.sendType?'前台送修':'快递寄送' }} </DescriptionsItem>
+            <DescriptionsItem label="保修类型"> {{ detailData.customerAddress.warrantyType == 0?'保修期内':detailData.customerAddress.warrantyType == 1?'保修期外':'非保修项目' }} </DescriptionsItem>
+            <DescriptionsItem label="维修单号"> {{ detailData.orderReceivingVo.repairId }} </DescriptionsItem>
+            <DescriptionsItem label="上次维修单号" :span="2"> {{ detailData.orderReceivingVo.repairerId }} </DescriptionsItem>
+            <DescriptionsItem label="故障描述" :span="3">
+              <div>
+                <p>{{ detailData.repairerVo.faultMsg }}</p>
+                <ImagePreviewGroup>
+                  <Image :width="80" v-for="item in detailData.repairerVo.faultImg" :key="item" :src="item"></Image>
+                </ImagePreviewGroup>
+              </div> 
+            </DescriptionsItem>
+            <DescriptionsItem label="机器外观">
+              <div>
+                <p>{{ detailData.repairRegisterVo?.orderFaultMsg }}</p>
+                <ImagePreviewGroup>
+                  <Image :width="80" v-for="item in detailData.orderReceivingVo?.orderFaultImg" :key="item" :src="item"></Image>
+                </ImagePreviewGroup>
+              </div> 
+            </DescriptionsItem>
+            <DescriptionsItem label="售后工程师"> {{ detailData.orderReceivingVo?.sysUserName }} </DescriptionsItem>
+            <DescriptionsItem label="接单日期"> {{ detailData.orderReceivingVo?.createTime }} </DescriptionsItem>
+            <DescriptionsItem label="检测结果" v-if="detailData.repairRegisterVo">
+              <div>
+                <p>{{detailData.repairRegisterVo.checkResult}}</p>
+                <ImagePreviewGroup>
+                  <Image :width="80" v-for="item in detailData.repairRegisterVo.checkImg" :key="item" :src="item"></Image>
+                </ImagePreviewGroup>
+              </div> 
+            </DescriptionsItem>
+            <DescriptionsItem label="检测日期"> {{ detailData.repairRegisterVo?.createTime }} </DescriptionsItem>
+            <DescriptionsItem label="所需备件"> {{ detailData.orderReceivingVo?.shipMobile }} </DescriptionsItem>
+          </Descriptions>
+          <Descriptions title="维修清单" :column="3" layout="vertical">
+            <DescriptionsItem label="备件信息" :span="3">
+              <BasicTable @register="registerTable"></BasicTable>
+            </DescriptionsItem>
+          </Descriptions>
+          <Descriptions  :column="3">
+            <DescriptionsItem label="维修工程师"> {{ detailData.repairRegisterVo?.sysUserName }}</DescriptionsItem>
+            <DescriptionsItem label="维修完成日期"> {{ detailData.repairRegisterVo?.overTime }} </DescriptionsItem>
+            <DescriptionsItem label="维修记录"> {{ detailData.repairRegisterVo?.remark }} </DescriptionsItem>
+            <DescriptionsItem label="测试工程师"> {{ detailData.RepairTestVo?.sysUserName }} </DescriptionsItem>
+            <DescriptionsItem label="测试通过时间" :span="2"> {{ detailData.repairRegisterVo?.passTime }} </DescriptionsItem>
+            <DescriptionsItem label="支付方式" :span="3"> 
+              <div v-if="detailData.repairPay">
+                <p>{{ detailData.repairPay.payType==1?'微信':detailData.repairPay.payType==2?'支付宝':'银行' }}</p>
+                <ImagePreviewGroup>
+                  <Image :width="80" v-for="item in [detailData.repairPay.payImg]" :key="item" :src="item"></Image>
+                </ImagePreviewGroup>
+              </div> 
+            </DescriptionsItem>
+            <DescriptionsItem label="取回方式" v-if="detailData.customerAddress"> {{detailData.customerAddress.getType==0?'前台取回':`快递寄回 ${detailData.customerAddress.getTrackingNum}`}}</DescriptionsItem>
+            <DescriptionsItem label="收件信息" :span="2" v-if="detailData.customerAddress"> {{detailData.customerAddress.getAddrName}} {{ detailData.customerAddress.getAddrName }}{{ detailData.customerAddress.getAddress }} </DescriptionsItem>
+          </Descriptions>
+          <!-- <Descriptions title="单据下载" :column="3">
+            <DescriptionsItem label="维修记录" :span="3"> 
+              <div class="link">
+                <a v-for="(item,index) in ['www.baidusss.com','www.baidudd.com']" :key="index" :href="item" target="_blank">
+                  <span v-if="index !== 0">、</span>
+                  {{ item }}
+                </a>
+              </div>  
+            </DescriptionsItem>
+            <DescriptionsItem label="维修工单" :span="3"> 
+              <div class="link">
+                <a :href="'www.baidudd.com'" target="_blank">2022101200001维修工单.pdf </a>
+              </div>  
+            </DescriptionsItem>
+          </Descriptions> -->
+          <Descriptions title="客户评价" :column="3" v-if="detailData.RepairComment">
+            <DescriptionsItem label="评价内容" > {{ detailData.RepairComment.comment }} </DescriptionsItem>
+            <DescriptionsItem label="评分"> {{ detailData.RepairComment.starRank }} </DescriptionsItem>
+          </Descriptions>
+          <Descriptions title="备注" :column="3">
+            <DescriptionsItem label="备注内容"> {{ detailData.repairerVo?.remark }} </DescriptionsItem>
+          </Descriptions>
+        </div>
+      </div>
+      <div class="content_right">
+        <Timeline>
+          <TimelineItem v-for="(item,indexs) in stepList" :color="indexs == 0 ?'red':'green'" :key="indexs">
+            <div class="timeItem">
+              <div class="name">
+                <span>{{item.remark}}</span>
+                <a-button style="margin-left:50px" @click="handleBut(butItem)"  v-for="butItem in butList" :key="butItem" v-if="indexs == 0"> {{butItem}} </a-button>
+              </div>
+              <div class="status">{{item.sysUserName}}完成{{item.remark}} <span>{{item.createTime}}</span></div>
+              <div class="itemText" v-if="item.customerAddress">{{ item.customerAddress.getType==0?'前台取回':`快递寄回  ${item.customerAddress.getTrackingNum}`}}</div>
+              <div class="itemText" v-if="item.customerAddress">{{ item.customerAddress.sendType==0?'前台送修':`快递寄送  ${item.customerAddress.sendTrackingNum}`}}</div>
+              <div class="itemText" v-if="item.repairRegisterVo">检测结论: {{ item.repairRegisterVo.checkResult}}</div>
+              <div class="itemText">所需备件: 镜头x2、电池x1</div>
+              <div class="itemText" v-if="item.orderReceivingVo">机器外观: {{ item.orderReceivingVo.orderFaultMsg}}</div>
+              <div class="iamgeList">
+                <ImagePreviewGroup>
+                  <Image :width="80" v-for="item in [logo]" :key="item" :src="item"></Image>
+                </ImagePreviewGroup>
+              </div>
+            </div>
+          </TimelineItem>
+        </Timeline>
+      </div>
+    </div>
+    <div class="bottom_but">
+      <a-button type="primary" v-for="item in butList" :key="item" @click="handleBut(item)">
+        {{item}}
+      </a-button>
+      <a-button type="primary" @click="goBack">
+        {{ t('common.back') }}
+      </a-button>
+    </div>
+    <!-- <recoveryModal @update="reload" @register="registerRecovery" /> -->
+    <remarksModal @update="reload" @register="registerRemarks" />
+    <takingOrdersModel @update="reload" @register="registerTakingOrders" />
+    <quoteModel @update="reload" @register="registerQuote" />
+    <deliveryModal @update="reload" @register="registerDelivery" />
+    <payLogModal @update="reload" @register="registerPayLog" />
+    <partsListModal @reload="reload" @register="registerParts" />
+    <checkModel @update="reload" @register="registerCheck" />
+    <addAccessoryModel @update="reload" @register="registerAdd" />
+    <outModal @update="reload" @register="registerOut" />
+    <reviewModal @reload="reload" @register="registerReview" />
+  </div>
+</template>
+<script lang="ts" setup>
+import { ref, onMounted, reactive } from 'vue';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { useRouter } from 'vue-router';
+import { useMessage } from '/@/hooks/web/useMessage';
+import { detail ,process } from '/@/api/spares';
+import { detailResult } from '/@/api/spares/model';
+import { useModal } from '/@/components/Modal';
+// import recoveryModal from './recoveryModal.vue';//录单
+import quoteModel from './quoteModel.vue';
+import deliveryModal from './deliveryModal.vue';
+import payLogModal from './payLogModal.vue';
+import takingOrdersModel from './takingOrdersModel.vue';
+import remarksModal from '../spares/remarksModal.vue';
+import checkModel from './checkModel.vue';
+import partsListModal from './partsListModal.vue';
+import outModal from './outModal.vue';
+import addAccessoryModel from './addAccessoryModel.vue';
+import logo from '/@/assets/images/grey-logo.png';
+import { BasicTable, useTable, BasicColumn, TableImg, } from '/@/components/Table';
+import { Timeline, TimelineItem, Descriptions, DescriptionsItem, Image, ImagePreviewGroup } from 'ant-design-vue';
+import { cloneDeep } from 'lodash-es';
+const router = useRouter();
+const { createMessage } = useMessage();
+const { t } = useI18n();
+const repairId = ref<string|string[]>(router.currentRoute.value.params.id || '0')
+const detailData = ref<detailResult>({
+  customer:{},
+  customerAddress:{},
+  repairerVo:{},
+  RepairTestVo:{},
+  repairRegisterVo:{},
+  orderReceivingVo:{},
+  repairPay:{},
+  RepairComment:{},
+  priceList:[],
+});
+const stepList = ref([])
+const butList = ref([])
+onMounted(() => {
+  getData();
+});
+let dataSource = reactive([])
+const columns: BasicColumn[] = [
+  {
+        title: '备件名称',
+        dataIndex: 'name',
+        width: 150,
+  },{
+        title: '单价(元)',
+        dataIndex: 'price',
+        width: 100,
+  },{
+        title: '数量',
+        dataIndex: 'count',
+        width: 110,
+  },{
+        title: '小计(元)',
+        dataIndex: 'total',
+        width: 140,
+  },
+]
+async function getData() {
+  let res = await detail({repairId:repairId.value})
+  detailData.value = res
+  let countItem = {
+    id:3,
+    price:null,
+    name:'',
+    count:'合计(元)',
+    total:0
+  }
+  dataSource = res.priceList.map(ele => {
+    countItem.total = countItem.total + ele.price * ele.count
+    return {
+      ...ele,
+      total:ele.price * ele.count
+    }
+  })
+  setTableData(cloneDeep([...dataSource,countItem]));
+  const stepRes = await process({repairId:repairId.value})
+  let butTypeList = {
+    0:['接单',],
+    1:['检测登记',],
+    2:['报价',],
+    3:['修改报价',],
+    4:['付款登记',],
+    5:['备件出库',],
+    6:['添加备件', '完成维修'],
+    7:['备件回收',],
+    8:['测试登记',],
+    9:['付款登记',],
+    10:['发货登记',],
+  }
+  butList.value = stepRes[0]?butTypeList[stepRes[0].repairStatus || 0]:['接单']
+  stepList.value = stepRes
+  console.log('repairId',dataSource,stepRes, butList.value)
+}
+function goBack() {
+  router.go(-1);
+}
+function handleBut(item) {
+  console.log('handleBut',item,stepList.value[0].repairStatus)
+  let status = stepList.value[0]?.repairStatus
+  let record = {
+    cameraSnCode:detailData.value.repairerVo?.cameraSnCode,
+    cameraType:detailData.value.repairerVo?.cameraType,
+    repairId:detailData.value.orderReceivingVo?.repairId,
+  };
+  let openList = {
+    1:openTakingOrders,//检测登记
+    2:openQuoteModal,//报价
+    3:openTakingOrders,//修改报价
+    4:openPayLogModal,//付款登记
+    5:registerParts,//备件出库
+    7:registerParts,//备件回收
+    8:openReviewModal,//测试登记
+    9:openPayLogModal,//付款登记
+    10:openDeliveryModal,//发货登记
+    61:openAddModal,//添加备件
+    62:openOutModal,//完成维修
+  }
+  openList[status](true, {
+    ...record,
+    repairManName:detailData.value.repairRegisterVo?.sysUserName,
+  });
+}
+function handleSubmit() {
+  createMessage.success(t('common.optSuccess'));
+}
+function reload(){
+  getData()
+}
+const [registerParts, { openModal:openPartsModal }] = useModal();
+const [registerReview, { openModal:openReviewModal }] = useModal();
+const [registerRecovery, { openModal }] = useModal();
+const [registerQuote, { openModal:openQuoteModal }] = useModal();
+const [registerPayLog, { openModal:openPayLogModal }] = useModal();
+const [registerDelivery, { openModal:openDeliveryModal }] = useModal();
+const [registerTakingOrders, { openModal:openTakingOrders }] = useModal();
+const [registerRemarks, { openModal:openRemarksModal }] = useModal();
+// const [registerRecovery, { openModal }] = useModal();
+const [registerOut, { openModal:openOutModal }] = useModal();
+const [registerAdd, { openModal:openAddModal }] = useModal();
+const [registerTable, { setTableData }] = useTable({
+  dataSource:dataSource,
+  columns,
+  showSummary:true,
+  showIndexColumn:false,
+  rowKey:'id', 
+  pagination: false,
+  bordered: true,
+  canResize: false,
+});
+</script>
+<style lang="less" scoped>
+.detailPage {
+  margin: 20px;
+  padding: 20px;
+  background-color: #fff;
+  .topButton {
+    text-align: right;
+  }
+  .content {
+    width: 100%;
+    display: flex;
+    justify-content: space-between;
+
+    &_right {
+      width: 400px;
+      padding: 40px 20px;
+    }
+    &_left {
+      width: calc(100% - 400px);
+    }
+  }
+  .bottom_but{
+    text-align: center;
+    button{
+      margin: 20px;
+    }
+  }
+}
+</style>

+ 21 - 4
src/views/work/followedList.vue

@@ -27,7 +27,7 @@
             },
             {
               label: '报价',
-              //ifShow:record.status == 2,
+              ifShow:record.status == 2,
               onClick: handleQuote.bind(null, record),
             },
             {
@@ -38,12 +38,12 @@
             {
               label: '付款登记',
               ifShow:record.status == 9,
-              onClick: handleRecover.bind(null, record),
+              onClick: handlePayLog.bind(null, record),
             },
             {
               label: '发货登记',
               ifShow:record.status == 10,
-              onClick: handleRecover.bind(null, record),
+              onClick: handleDelivery.bind(null, record),
             },
             {
               label: '备注',
@@ -57,6 +57,8 @@
     <remarksModal @update="reload" @register="registerRemarks" />
     <takingOrdersModel @update="reload" @register="registerTakingOrders" />
     <quoteModel @update="reload" @register="registerQuote" />
+    <deliveryModal @update="reload" @register="registerDelivery" />
+    <payLogModal @update="reload" @register="registerPayLog" />
     <!-- ifShow: getCheckPerm('device-out') && !Boolean(record.outType), -->
   </div>
 </PageWrapper>
@@ -78,6 +80,8 @@ import { useI18n } from '/@/hooks/web/useI18n';
 import { usePermissionStore } from '/@/store/modules/permission';
 import recoveryModal from './recoveryModal.vue';
 import quoteModel from './quoteModel.vue';
+import deliveryModal from './deliveryModal.vue';
+import payLogModal from './payLogModal.vue';
 import takingOrdersModel from './takingOrdersModel.vue';
 import remarksModal from '../spares/remarksModal.vue';
 
@@ -92,6 +96,8 @@ export default defineComponent({
     recoveryModal,
     takingOrdersModel,
     remarksModal,
+    deliveryModal,
+    payLogModal,
     quoteModel,
     PageWrapper,
     [Tabs.name]: Tabs,
@@ -224,6 +230,8 @@ export default defineComponent({
     };
     const [registerRecovery, { openModal }] = useModal();
     const [registerQuote, { openModal:openQuoteModal }] = useModal();
+    const [registerPayLog, { openModal:openPayLogModal }] = useModal();
+    const [registerDelivery, { openModal:openDeliveryModal }] = useModal();
     const [registerTakingOrders, { openModal:openTakingOrders }] = useModal();
     const [registerRemarks, { openModal:openRemarksModal }] = useModal();
     const [registerTable, { reload }] = useTable({
@@ -254,7 +262,12 @@ export default defineComponent({
     function handleRemarks(record: Recordable) {
       openRemarksModal(true,record);
     }
-    
+    function handlePayLog(record: Recordable) {
+      openPayLogModal(true,record);
+    }
+    function handleDelivery(record: Recordable) {
+      openDeliveryModal(true,record);
+    }
     function handleOrder() {
       openModal(true);
     }
@@ -271,6 +284,8 @@ export default defineComponent({
       t,
       tableType,
       registerRemarks,
+      registerPayLog,
+      registerDelivery,
       changeTable,
       handleOrder,
       getCheckPerm,
@@ -278,6 +293,8 @@ export default defineComponent({
       handleQuote,
       registerTakingOrders,
       handleRecover,
+      handlePayLog,
+      handleDelivery,
       handleRemarks,
       registerQuote,
       registerRecovery,

+ 4 - 1
src/views/work/maintenance.vue

@@ -15,19 +15,21 @@
           :actions="[
             {
               label: '详情',
-              color: 'error',
               onClick: handleDetail.bind(null, record),
             },
             {
               label: '添加备件',
+              ifShow:tableType == 1,
               onClick: handleAdd.bind(null, record),
             },
             {
               label: '完成维修',
+              ifShow:tableType == 1,
               onClick: handleOut.bind(null, record),
             },
             {
               label: '检测登记',
+              ifShow:tableType == 0,
               onClick: handleRecover.bind(null, record),
             },
           ]"
@@ -56,6 +58,7 @@ import {
 import { Tabs } from 'ant-design-vue';
 import { operateSceneList } from '/@/api/operate';
 import { useI18n } from '/@/hooks/web/useI18n';
+
 import { usePermissionStore } from '/@/store/modules/permission';
 import checkModel from './checkModel.vue';
 import outModal from './outModal.vue';

+ 5 - 4
src/views/work/outModal.vue

@@ -34,6 +34,7 @@ import {
   faultAllList,
   checkRegister,
   checkRegisterInfo,
+  partInfo,
   repairOver,
 } from '/@/api/spares';
 import { useI18n } from '/@/hooks/web/useI18n';
@@ -48,7 +49,7 @@ export default defineComponent({
   emits: ['update', 'register'],
   setup(props, { emit }) {
     const n = ref(1);
-    const repairId = ref(1);
+    const repairId = ref('');
     const fileFlow = reactive({
       file: null,
       title: '添加备件',
@@ -110,7 +111,7 @@ export default defineComponent({
       {
         title: '备件编号',
         dataIndex: 'partId',
-        width: 100,
+        width: 80,
       },
       {
         title: '备件名称',
@@ -124,7 +125,7 @@ export default defineComponent({
       },
     ];
     const [registerTable, { reload }] = useTable({
-      api: checkRegisterInfo,
+      api:partInfo,
       columns: columns,
       searchInfo: { repairId: repairId },
       showTableSetting: true,
@@ -209,7 +210,7 @@ export default defineComponent({
     function addSchemas(number) {
       let parentList: FormSchema[] = [
         {
-          field: 'part_id' + number,
+          field: 'partId' + number,
           label: '备件' + number,
           component: 'ApiSelect',
           colProps: {

+ 116 - 0
src/views/work/partsListModal.vue

@@ -0,0 +1,116 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    :title="modelRef.title"
+    @visible-change="handleVisibleChange"
+    @cancel="resetFields"
+    @ok="handleSubmit"
+    :min-height="0"
+  >
+    <div class="pt-2px pr-3px recoverPage">
+      <div class="form_item"><div class="item_lable">维修单号:</div>{{modelRef.repairId}}</div>
+      <div class="form_item"><div class="item_lable">维修工程师:</div>{{modelRef.repairManName}}</div>
+      <BasicTable @register="registerTable" />
+      <div class="tips" v-if="modelRef.title == '备件出库'">注:请按备件清单给维修工程师提供备件</div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+import { defineComponent, ref, onMounted, h } from 'vue';
+import { BasicModal, useModalInner } from '/@/components/Modal';
+import { BasicTable, useTable, BasicColumn } from '/@/components/Table';
+import { useMessage } from '/@/hooks/web/useMessage';
+import { partInfo, partRecovery, partOut } from '/@/api/spares';
+import { useI18n } from '/@/hooks/web/useI18n';
+const { t } = useI18n();
+export default defineComponent({
+  components: { BasicModal, BasicTable },
+  props: {
+    userData: { type: Object },
+  },
+  emits: ['reload'],
+  setup(_, { emit }) {
+    const repairId = ref('')
+    const modelRef = ref({
+      title:'设备入库',
+      repairId:'0000123',
+      repairManName:'',
+    });
+    const columns: BasicColumn[] = [
+      {
+        title: '备件编号',
+        dataIndex: 'partId',
+        width: 100,
+      },{
+        title: '备件名称',
+        dataIndex: 'partName',
+        width: 100,
+      },{
+        title: '数量',
+        dataIndex: 'partCount',
+        width: 100,
+      },
+    ]
+    const [registerTable, { reload }] = useTable({
+      api: partInfo,
+      searchInfo: {repairId:repairId},
+      immediate:false,
+      pagination:false,
+      columns,
+    });
+    const { createMessage, createConfirm } = useMessage();
+    onMounted(() => {});
+    let addListFunc = () => {};
+    const [register, { closeModal }] = useModalInner((data) => {
+      // console.log(data);
+      data && onDataReceive(data);
+    });
+
+    function onDataReceive(data) {
+      modelRef.value.title = data.status == 5?'备件出库':'备件回收';
+      repairId.value = data.repairId
+      modelRef.value.repairId = data.repairId;
+      modelRef.value.repairManName = data.repairManName;
+      reload()
+    }
+    function handleVisibleChange() {}
+
+    const handleSubmit = async () => {
+      let api = modelRef.value.title == '备件出库'?partOut:partRecovery
+      createConfirm({
+          iconType: 'warning',
+          title: () => h('span', '温馨提示'),
+          content: `确定要提交${modelRef.value.title == '备件出库'?'出库':'备件回收'}吗?`,
+          onOk: async () => {
+            await api({repairId:modelRef.value.repairId})
+            createMessage.success(t('common.optSuccess'));
+            closeModal();
+            emit('reload');
+          },
+        });
+    };
+    return {
+      register,
+      modelRef,
+      registerTable,
+      handleVisibleChange,
+      handleSubmit,
+      addListFunc,
+      t,
+    };
+  },
+});
+</script>
+<style lang="less" scoped>
+.recoverPage{
+  .form_item{
+    line-height: 30px;
+    .item_lable{
+      display: inline-block;
+      width: 100px;
+      text-align: right;
+    }
+  }
+}
+</style>

+ 158 - 0
src/views/work/payLogModal.vue

@@ -0,0 +1,158 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="付款登记"
+    @cancel="resetFields"
+    :confirmLoading="loading"
+    @ok="handleSubmit"
+  >
+    <div class="pt-2px pr-3px">
+      <BasicForm @register="registerForm">
+        <template #text="{ model, field }">
+          {{ model[field]  }}
+        </template>
+      </BasicForm>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts">
+  import { defineComponent, onMounted, reactive, ref, h } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { payRegister } from '/@/api/spares';
+  import { useI18n } from '/@/hooks/web/useI18n';
+  import { uploadApi } from '/@/api/product/index';
+
+  const { t } = useI18n();
+  export default defineComponent({
+    components: { BasicModal, BasicForm },
+    props: {
+      userData: { type: Object },
+    },
+    emits: ['update', 'register'],
+    setup(props, { emit }) {
+      const fileFlow = reactive({
+        file:null,
+        type:2,//2-普通发票,3-专用发票
+      })
+      const loading = ref(false)
+      const { createMessage, createConfirm } = useMessage();
+      const schemas: FormSchema[] = [
+          {
+            field: 'repairId',
+            slot: 'text',
+            component: 'Input',
+            label: '维修单号',
+          },{
+            field: 'deviceInfo',
+            component: 'Input',
+            label: '设备信息',
+            slot: 'text',
+            colProps: {
+              span: 18,
+            },
+          },
+          {
+            field: 'payAmount',
+            component: 'Input',
+            label: '应收金额',
+            slot: 'text',
+            colProps: {
+              span: 24,
+            },
+          },{
+            field: 'payType',
+            component: 'Select',
+            label: '付款方式',
+            required: true,
+            colProps: {
+              span: 18,
+            },
+            defaultValue:0,
+            componentProps: {
+              options: [
+                {
+                  label: '银行转账',
+                  value: 0,
+                  key: 0,
+                }
+              ],
+            },
+          },{
+            field: 'payImg',
+            component: 'Upload',
+            label: '付款凭证',
+            required: true,
+            rules: [{ required: true, message: t('common.uploadMessge') }],
+            itemProps: {
+              validateTrigger: 'blur',
+            },
+            componentProps: {
+              api: uploadApi,
+              maxNumber: 5,
+              maxSize: 10,
+              accept: ['jpeg','jpg','png'],
+            },
+            colProps: {
+              span: 22,
+            },
+          },
+      ];
+
+      const [registerForm, { validate, resetFields, setFieldsValue, updateSchema }] = useForm({
+        labelWidth: 120,
+        schemas:schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+      onMounted(() => {});
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        data && onDataReceive(data);
+      });
+      function onDataReceive(data) {
+        resetFields();
+        setFieldsValue({
+          ...data,
+          deviceInfo:t(`routes.scene.tableType.${data.cameraType}`)+data.cameraSnCode
+        });
+      }
+      const handleSubmit = async () => {
+        createConfirm({
+          iconType: 'warning',
+          title: () => h('span', '温馨提示'),
+          content: '删除设备后需要重新入库<br/>确定删除吗?',
+          onOk: async () => {
+            loading.value = true
+            try {
+              const params = await validate();
+              await payRegister(params);
+              closeModal();
+              resetFields();
+              createMessage.success(t('common.optSuccess'));
+              emit('update');
+              loading.value = false
+            } catch (error) {
+              loading.value = false
+              console.log('not passing', error);
+            }
+          },
+        });
+      };
+      return {
+        register,
+        registerForm,
+        fileFlow,
+        handleSubmit,
+        addListFunc,
+        resetFields,
+        loading,
+        t,
+      };
+    },
+  });
+</script>

+ 210 - 35
src/views/work/query.vue

@@ -2,8 +2,18 @@
   <PageWrapper contentBackground>
     <template #footer>
       <a-tabs v-model:activeKey="tableType" @change="changeTable">
-        <a-tab-pane :key="0" :tab="t('routes.scene.tableType.0')" />
-        <a-tab-pane :key="1" :tab="t('routes.scene.tableType.1')" />
+        <a-tab-pane :key="null" :tab="t('routes.spares.tableType.-1')" />
+        <a-tab-pane :key="0" :tab="t('routes.spares.tableType.0')" />
+        <a-tab-pane :key="1" :tab="t('routes.spares.tableType.1')" />
+        <a-tab-pane :key="2" :tab="t('routes.spares.tableType.2')" />
+        <a-tab-pane :key="3" :tab="t('routes.spares.tableType.3')" />
+        <a-tab-pane :key="4" :tab="t('routes.spares.tableType.4')" />
+        <a-tab-pane :key="5" :tab="t('routes.spares.tableType.5')" />
+        <a-tab-pane :key="6" :tab="t('routes.spares.tableType.6')" />
+        <a-tab-pane :key="7" :tab="t('routes.spares.tableType.7')" />
+        <a-tab-pane :key="8" :tab="t('routes.spares.tableType.8')" />
+        <a-tab-pane :key="9" :tab="t('routes.spares.tableType.9')" />
+        <a-tab-pane :key="10" :tab="t('routes.spares.tableType.10')" />
       </a-tabs></template
     >
     <div class="desc-wrap-BasicTable">
@@ -17,10 +27,6 @@
               color: 'error',
               onClick: handleDetail.bind(null, record),
             },
-            {
-              label: '备件回收',
-              onClick: handleRecover.bind(null, record),
-            },
           ]"
         />
       </template>
@@ -48,7 +54,7 @@ import { usePermissionStore } from '/@/store/modules/permission';
 import recoveryModal from './recoveryModal.vue';
 import { useModal } from '/@/components/Modal';
 import { useRouter } from 'vue-router'
-import { saleOrderList } from '/@/api/spares';
+import { queryList, faultAllList, getByRoleType } from '/@/api/spares';
 export default defineComponent({
   components: {
     BasicTable,
@@ -96,30 +102,53 @@ export default defineComponent({
         width: 100,
       },
       {
-        title: '故障描述',
-        dataIndex: 'faultMsg',
+        title: '报修方式',
+        dataIndex: 'receiverType',
         width: 100,
+        customRender: ({ record }) => {
+          return record.receiverType == 0 ? '系统录单' : '公众号报修';
+        },
       },
       {
-        title: '送修方式',
-        dataIndex: 'sendType',
+        title: '保修类型',
+        dataIndex: 'warrantyType',
         width: 100,
         customRender: ({ record }) => {
-          return record.sendType == 0 ? '前台送修' : '快递寄送';
+          return record.warrantyType == 0 ? '保修期内' : record.warrantyType == 1 ? '保修期外' : '非保修项目';
         },
+      },{
+        title: '售后工程师',
+        dataIndex: 'saleName',
+        width: 100,
+      },{
+        title: '接单日期',
+        dataIndex: 'createTime',
+        width: 100,
       },
       {
-        title: '快递单号',
-        dataIndex: 'sendTrackingNum',
+        title: '故障分析',
+        dataIndex: 'checkResult',
+        width: 100,
+      },
+      {
+        title: '维修工程师',
+        dataIndex: 'repairManName',
+        width: 100,
+      },{
+        title: '维修完成日期',
+        dataIndex: 'testPassTime',
         width: 100,
       },
       {
         title: '状态',
         dataIndex: 'status',
         width: 100,
+        customRender: ({ record }) => {
+          return t(`routes.spares.tableType.${record.status || 0}`);
+        },
       },
       {
-        title: '工单号',
+        title: '维修单号',
         dataIndex: 'repairId',
         width: 100,
       },
@@ -141,30 +170,177 @@ export default defineComponent({
       },
       schemas: [
         {
-          field: 'customerName',
-          component: 'Input',
-          label: '客户名称',
+          field: 'type',
+          component: 'Select',
+          label: t('routes.device.deviceType'),
           colProps: {
-            xl: 7,
-            xxl: 7,
+            span: 7,
           },
-        },
-        {
+          componentProps: {
+            options: [
+              {
+                  label: '公众号保修',
+                  value: 0,
+                  key: '0',
+                },{
+                label: '后台录单',
+                value: 1,
+                key: '1',
+              },
+            ],
+          },
+        },{
+          field: 'type',
+          component: 'Select',
+          label: t('routes.device.deviceType'),
+          colProps: {
+            span: 7,
+          },
+          componentProps: {
+            options: [
+              {
+                label: t('routes.device.type.1'),
+                value: 0,
+                key: '0',
+              },
+              {
+                label: t('routes.device.type.2'),
+                value: 1,
+                key: '1',
+              },
+              {
+                label: t('routes.device.type.3'),
+                value: 2,
+                key: '2',
+              },
+            ],
+          },
+        },{
           field: 'cameraSnCode',
           component: 'Input',
-          label: t('routes.device.snCode'),
+          label: 'SN码',
           colProps: {
-            xl: 7,
-            xxl: 7,
+            span: 7,
           },
-        },
-        {
-          field: 'trackingNum',
+        },{
+          field: 'customerName',
           component: 'Input',
-          label: '快递单号',
+          label: '客户名称',
+          colProps: {
+            span: 7,
+          },
+        },{
+          field: 'warrantyType',
+          component: 'Select',
+          label: '保修类型',
+          colProps: {
+            span: 7,
+          },
+          componentProps: {
+            options: [
+              {
+                  label: '保修期内',
+                  value: 0,
+                  key: '0',
+                },{
+                label: '保修期外',
+                value: 1,
+                key: '1',
+              },{
+                label: '非保修项目',
+                value: 2,
+                key: '2',
+              },
+            ],
+          },
+        },{
+          field: 'faultId',
+          component: 'ApiSelect',
+          label: '故障类型',
+          componentProps: {
+            maxLength: 50,
+            api: faultAllList,
+            numberToString: true,
+            labelField: 'faultMsg',
+            valueField: 'faultId',
+            immediate: true,
+          },
+          colProps: {
+            span: 7,
+          },
+        },{
+          field: 'saleId',
+          label: '售后工程师',
+          component: 'ApiSelect',
+          componentProps: {
+            api: getByRoleType,
+            numberToString: true,
+            labelField: 'nickName',
+            valueField: 'id',
+            immediate: true,
+            params: {
+              roleType: 2,
+            },
+          },
           colProps: {
-            xl: 7,
-            xxl: 7,
+            span: 7,
+          },
+        },{
+          field: 'repairManId',
+          label: '维修工程师',
+          component: 'ApiSelect',
+          componentProps: {
+            api: getByRoleType,
+            numberToString: true,
+            labelField: 'nickName',
+            valueField: 'id',
+            immediate: true,
+            params: {
+              roleType: 3,
+            },
+          },
+          colProps: {
+            span: 7,
+          },
+        },{
+          field: 'payStatus',
+          component: 'Select',
+          label: '支付状态',
+          colProps: {
+            span: 7,
+          },
+          componentProps: {
+            options: [
+              {
+                  label: '待支付',
+                  value: 0,
+                  key: '0',
+                },{
+                label: '已支付',
+                value: 1,
+                key: '1',
+              },
+            ],
+          },
+        },{
+          field: 'commentStatus',
+          component: 'Select',
+          label: '支付状态',
+          colProps: {
+            span: 7,
+          },
+          componentProps: {
+            options: [
+              {
+                  label: '未评论',
+                  value: 0,
+                  key: '0',
+                },{
+                label: '已评论',
+                value: 1,
+                key: '1',
+              },
+            ],
           },
         },
         {
@@ -178,18 +354,17 @@ export default defineComponent({
             showTime: true,
           },
           colProps: {
-            xl: 7,
-            xxl: 7,
+            span: 7,
           },
         },
       ],
     };
     const [registerRecovery, { openModal }] = useModal();
     const [registerTable, { reload }] = useTable({
-      api: saleOrderList,
+      api: queryList,
       columns: columns,
       useSearchForm: true,
-      searchInfo: { type: tableType },
+      searchInfo: { status: tableType },
       formConfig: searchForm,
       showTableSetting: true,
       showIndexColumn: false,

+ 112 - 21
src/views/work/quoteModel.vue

@@ -4,7 +4,7 @@
     @register="register"
     title="维修报价"
     width="700px"
-    @cancel="resetFields"
+    @cancel="clearInfo"
     :confirmLoading="loading"
     @ok="handleSubmit"
   >
@@ -14,13 +14,16 @@
           {{ model[field] }}
         </template>
         <template #add>
-          <Button  @click="add">更新总价</Button>
           <Button  @click="add" style="margin-left:20px">添加人工</Button>
         </template> 
         <template #del="{ field }">
           <Button @click="del(field)">删除</Button>
         </template>
       </BasicForm>
+      <div class="priceCount">
+        <Button  @click="updataCount">更新总价</Button>
+        <div class="label" v-if="fileFlow.priceCount">总价:{{ fileFlow.priceCount }}</div>
+      </div>
     </div>
   </BasicModal>
 </template>
@@ -29,8 +32,7 @@
   import { BasicModal, useModalInner } from '/@/components/Modal';
   import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
   import { useMessage } from '/@/hooks/web/useMessage';
-  import { InvoiceRegister } from '/@/api/order';
-  import { getPriceList } from '/@/api/spares'
+  import { getPriceList, checkRegisterInfo, addOrUpdatePriceList, allList } from '/@/api/spares'
   import { useI18n } from '/@/hooks/web/useI18n';
   import { uploadApi } from '/@/api/product/index';
 
@@ -46,16 +48,19 @@
       const fileFlow = reactive({
         file:null,
         type:2,//2-普通发票,3-专用发票
+        count:1,//第一次报价
+        priceCount:0,//总价
+        priceLists:[],
+        priceListsPrice:{}
       })
       const loading = ref(false)
-      const { createMessage } = useMessage();
-      let schemas: FormSchema[] = [
+      const { createMessage,createConfirm } = useMessage();
+      const schemas: FormSchema[] = [
           {
             field: 'id',
             component: 'Input',
             show:false,
             label: '发票编号',
-            required: true,
           },
           {
             field: 'repairId',
@@ -93,22 +98,34 @@
           },
       ];
 
-      const [registerForm, { validate, resetFields, setFieldsValue, removeSchemaByFiled, appendSchemaByField }] = useForm({
-        labelWidth: 100,
+      const [registerForm, { validate, getFieldsValue, resetFields, setFieldsValue, removeSchemaByFiled, appendSchemaByField, updateSchema }] = useForm({
+        labelWidth: 180,
         schemas:schemas,
         showActionButtonGroup: false,
         actionColOptions: {
           span: 24,
         },
       });
-      onMounted(() => {});
+      onMounted(async () => {
+        let allListOption = await allList()//获取价格
+        console.log('allList',allListOption)
+        fileFlow.priceListsPrice
+        allListOption.map(ele => {
+          fileFlow.priceListsPrice[ele.laborCostId] = ele.price
+        })
+      });
       let addListFunc = () => {};
       const [register, { closeModal }] = useModalInner((data) => {
         data && onDataReceive(data);
       });
       async function onDataReceive(data) {
-        const { priceLists, count } = await getPriceList({repairId:data.repairId})
-        console.log('repairId',priceLists, count)
+
+        const { priceLists, count } = await getPriceList({repairId:data.repairId})//
+        updateSchema({
+          field:'0',
+          label:`第${count || 1}次报价`,
+        })
+        addPriceItem(priceLists)
         resetFields();
         fileFlow.type = data.type
         setFieldsValue({
@@ -127,6 +144,38 @@
         })
         n.value++
       }
+      function addPriceItem(list){
+        fileFlow.priceLists = list
+        let priceSchema = []
+        let valueObj = {}
+        list.map(ele => {
+          valueObj[`priceList${ele.priceListId}`] = ele.count || 1
+          priceSchema.unshift({
+            field: 'priceList' + ele.priceListId,
+            label: ele.name+'次数',
+            component: 'InputNumber',
+            defaultValue:ele.count || 1,
+            suffix:ele.price+"元/次",
+            colProps: {
+              span: 13,
+            },
+            required: true,
+            componentProps: {
+              disabled:ele.status == 1,
+              min:1,
+              max:999,
+              maxLength: 15,
+            },
+          })
+        })
+        priceSchema.map(item =>{
+          console.log('priceSchema',item)
+          appendSchemaByField(item,'')
+        })
+        setTimeout(()=>{
+          setFieldsValue(valueObj)
+        },100)
+      }
       function addSchemas(number){
         let parentList: FormSchema[] = [
           {
@@ -138,15 +187,13 @@
             },
             required: true,
             componentProps: {
-              maxLength: 15,
-              api: InvoiceRegister,
-              fieldNames: {
-                label: 'name',
-                key: 'id',
-                value: 'id',
-              },
-              showSearch: true,
-              optionFilterProp: 'label',
+              api: allList,
+              labelField: 'name',
+              valueField: 'laborCostId',
+              showSearch:true,
+              onChange:(value)=>{
+                console.log('onchange',value,arguments)
+              }
             },
           },
           {
@@ -190,6 +237,7 @@
             closeModal();
             emit('update');
             loading.value = false
+            clearInfo()
           },
         });
         } catch (error) {
@@ -197,6 +245,38 @@
           console.log('not passing', error);
         }
       };
+      function updataCount(){
+        let fromData = getFieldsValue() ,count = 0
+        fileFlow.priceListsPrice
+        fileFlow.priceLists.map(ele => {
+          count = count + fromData[`priceList${ele.priceListId}`]*ele.price
+        })
+        for (let index = 1; index < n.value; index++) {
+          if(fromData[`deviceType${index}`] && fromData[`device_${index}`]){
+            let priceId = fromData[`deviceType${index}`]
+            let fromPrice = fromData[`device_${index}`] * fileFlow.priceListsPrice[priceId]
+            count = count +fromPrice
+          }
+        }
+        fileFlow.priceCount = count
+        console.log('fromData',fromData)
+      }
+
+      function clearInfo(){
+        let indexa = n.value;
+        fileFlow.priceCount = 0
+        resetFields()
+        let clearFiled = []
+        fileFlow.priceLists.map(ele =>{
+          clearFiled.push(`priceList${ele.priceListId}`)
+        })
+        for (let index = 1; index < indexa; index++) {
+          clearFiled.push(`deviceType${index}`, `device_${index}`, `${index}`)
+        }
+        removeSchemaByFiled(clearFiled);
+        n.value = 1
+      }
+
       return {
         register,
         registerForm,
@@ -205,6 +285,8 @@
         addListFunc,
         resetFields,
         loading,
+        clearInfo,
+        updataCount,
         t,
         del,
         add,
@@ -212,3 +294,12 @@
     },
   });
 </script>
+
+<style lang="less" scoped>
+.priceCount{
+  padding: 20px 180px;
+  .label{
+    display: inline-block;
+  }
+}
+</style>

+ 252 - 0
src/views/work/repairsparesList.vue

@@ -0,0 +1,252 @@
+<template>
+  <PageWrapper contentBackground>
+    <template #footer>
+      <a-tabs v-model:activeKey="tableType" @change="changeTable">
+        <a-tab-pane :key="0" :tab="t('routes.spares.tableType.24')" />
+        <a-tab-pane :key="1" :tab="t('routes.spares.tableType.25')" />
+        <a-tab-pane :key="2" :tab="t('routes.spares.tableType.7')" />
+      </a-tabs></template
+    >
+    <div class="desc-wrap-BasicTable">
+    <BasicTable @register="registerTable">
+      <template #toolbar>
+        <a-button type="primary" @click="handleOrder" v-if="getCheckPerm('invoice-export')"> 录单</a-button>
+      </template>
+      <template #action="{ record }">
+        <TableAction
+          stopButtonPropagation
+          :actions="[
+            {
+              label: '详情',
+              onClick: handleDetail.bind(null, record),
+            },
+            {
+              label: '备件出库',
+              ifShow: tableType == 0,
+              onClick: handleRecover.bind(null, record),
+            },
+            {
+              label: '备件回收',
+              ifShow: tableType == 2,
+              onClick: handleRecover.bind(null, record),
+            },
+          ]"
+        />
+      </template>
+    </BasicTable>
+    <partsListModal @reload="reload" @register="registerRecovery" />
+    <!-- ifShow: getCheckPerm('device-out') && !Boolean(record.outType), -->
+  </div>
+</PageWrapper>
+</template>
+<script lang="ts">
+import { defineComponent, onMounted, ref } from 'vue';
+import { PageWrapper } from '/@/components/Page';
+import {
+  BasicTable,
+  useTable,
+  TableAction,
+  BasicColumn,
+  TableImg,
+  FormProps,
+} from '/@/components/Table';
+import { Tabs } from 'ant-design-vue';
+import { operateSceneList } from '/@/api/operate';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { usePermissionStore } from '/@/store/modules/permission';
+import partsListModal from './partsListModal.vue';
+import { useModal } from '/@/components/Modal';
+import { useRouter } from 'vue-router'
+import { supplyOrderList } from '/@/api/spares';
+export default defineComponent({
+  components: {
+    BasicTable,
+    TableAction,
+    TableImg,
+    partsListModal,
+    PageWrapper,
+    [Tabs.name]: Tabs,
+    [Tabs.TabPane.name]: Tabs.TabPane,
+  },
+  setup() {
+    const { t } = useI18n();
+    const permissionStore = usePermissionStore();
+    const router = useRouter()
+    const { getCheckPerm } = permissionStore;
+    const tableType = ref<Recordable>(0); //0看看 、1看见、2深时
+    onMounted(() => {
+      // console.log(router.currentRoute.value.params.id);
+    });
+    const columns: BasicColumn[] = [
+      {
+        title: '报修日期',
+        dataIndex: 'createTime',
+        width: 180,
+      },
+      {
+        title: '客户名称',
+        dataIndex: 'operationType',
+        width: 80,
+        customRender: ({ record }) => {
+          return t(`routes.equity.operation.${record.operationType || 0}`);
+        },
+      },
+      {
+        title: '产品类型',
+        dataIndex: 'cameraType',
+        width: 80,
+        customRender: ({ record }) => {
+          return t(`routes.equity.operation.${record.cameraType || 0}`);
+        },
+      },
+      {
+        title: '产品SN码',
+        dataIndex: 'cameraSnCode',
+        width: 100,
+      },
+      {
+        title: '接单日期',
+        dataIndex: 'orderReceivingTime',
+        width: 100,
+      },
+      {
+        title: '维修工程师',
+        dataIndex: 'repairManName',
+        width: 100,
+      },
+      {
+        title: '故障分析',
+        dataIndex: 'checkResult',
+        width: 150,
+      },
+      {
+        title: '状态',
+        dataIndex: 'status',
+        width: 100,
+        customRender: ({ record }) => {
+          return t(`routes.spares.tableType.${record.status || 0}`);
+        },
+      },
+      {
+        title: '工单号',
+        dataIndex: 'repairId',
+        width: 100,
+      },
+      {
+        title: t('common.operating'),
+        dataIndex: 'action',
+        slots: { customRender: 'action' },
+        ifShow: true,
+        fixed: 'right',
+        flag: 'ACTION',
+        width: 120,
+      },
+    ];
+    const searchForm: Partial<FormProps> = {
+      labelWidth: 120,
+      autoAdvancedLine: 1,
+      actionColOptions: {
+        span: 24,
+      },
+      schemas: [
+        {
+          field: 'customerName',
+          component: 'Input',
+          label: '客户名称',
+          colProps: {
+            xl: 7,
+            xxl: 7,
+          },
+        },
+        {
+          field: 'cameraSnCode',
+          component: 'Input',
+          label: t('routes.device.snCode'),
+          colProps: {
+            xl: 7,
+            xxl: 7,
+          },
+        },
+        {
+          field: 'trackingNum',
+          component: 'Input',
+          label: '快递单号',
+          colProps: {
+            xl: 7,
+            xxl: 7,
+          },
+        },
+        {
+          field: 'timeList',
+          label: '报修日期',
+          component: 'RangePicker',
+          componentProps: {
+            maxLength: 100,
+            format: 'YYYY-MM-DD',
+            valueFormat: 'YYYY-MM-DD',
+            showTime: true,
+          },
+          colProps: {
+            xl: 7,
+            xxl: 7,
+          },
+        },
+      ],
+    };
+    const [registerRecovery, { openModal }] = useModal();
+    const [registerTable, { reload }] = useTable({
+      api: supplyOrderList,
+      columns: columns,
+      useSearchForm: true,
+      searchInfo: { statusParam: tableType },
+      formConfig: searchForm,
+      showTableSetting: true,
+      showIndexColumn: false,
+      fetchSetting: {
+        pageField: 'pageNum',
+        sizeField: 'pageSize',
+        listField: 'list',
+        totalField: 'total',
+      },
+      canResize: false,
+    });
+    async function handleDetail(record: Recordable) {
+      console.log('record', record);
+      router.push({path:`detail/${record.id||'20230215174919387'}`})
+    }
+    async function handleRecover(record: Recordable) {
+      openModal(true, {
+        tableType:tableType.value,
+        ...record,
+      });
+    }
+    function handleOrder() {
+      openModal(true);
+    }
+    function changeTable(val: string) {
+      tableType.value = val;
+      reload();
+    }
+    return {
+      registerTable,
+      reload,
+      t,
+      tableType,
+      changeTable,
+      handleOrder,
+      getCheckPerm,
+      handleDetail,
+      handleRecover,
+      registerRecovery,
+    };
+  },
+});
+</script>
+<style lang="less" scoped>
+.desc-wrap-BasicTable {
+  background-color: #f0f2f5;
+  .vben-basic-table-form-container {
+    padding: 0;
+  }
+}
+</style>

+ 158 - 0
src/views/work/reviewModal.vue

@@ -0,0 +1,158 @@
+<template>
+  <BasicModal
+    v-bind="$attrs"
+    @register="register"
+    title="接单"
+    @cancel="resetFields"
+    @ok="handleSubmit"
+    :min-height="0"
+  >
+    <BasicForm @register="registerForm" >
+        <template #text="{ model, field }">
+          {{ model[field]  }}
+        </template>
+    </BasicForm>
+  </BasicModal>
+</template>
+<script lang="ts">
+import { defineComponent, ref, onMounted, h } from 'vue';
+import { BasicModal, useModalInner } from '/@/components/Modal';
+import { useMessage } from '/@/hooks/web/useMessage';
+import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
+import { testPassOrFail } from '/@/api/spares';
+import { uploadApi } from '/@/api/product/index';
+import { useI18n } from '/@/hooks/web/useI18n';
+const { t } = useI18n();
+export default defineComponent({
+  components: { BasicModal, BasicForm },
+  props: {
+    userData: { type: Object },
+  },
+  emits: ['reload'],
+  setup(_, { emit }) {
+    const modelRef = ref({});
+    const schemas: FormSchema[] = [
+      {
+        field: 'repairId',
+        component: 'Input',
+        slot: 'text',
+        label: '维修单号',
+        componentProps: {
+          maxLength: 50,
+        },        colProps: {
+          span: 18,
+        },  
+      },
+      {
+        field: 'deviceType',
+        component: 'Input',
+        slot: 'text',
+        label: '设备信息',
+      },{
+        field: 'resultStatus',
+        component: 'RadioGroup',
+        required: true,
+        label: '测试结果',
+        defaultValue:0,
+        componentProps: {
+          options:[
+            { label: '通过', value: 0 },
+            { label: '不通过', value: 1 },
+          ],
+        },
+      },
+      {
+        field: 'resultInfo',
+        component: 'InputTextArea',
+        label: '测试描述',
+        componentProps: {
+          maxLength: 500,
+          rows: 3,
+        },
+        colProps: {
+          span: 18,
+        },
+      },
+      {
+        field: 'resultImg',
+        component: 'Upload',
+        label: '相关图片',
+        itemProps: {
+          validateTrigger: 'blur',
+        },
+        componentProps: {
+          api: uploadApi,
+          // fileFlow:true,
+          maxNumber: 5,
+          maxSize: 5,
+          accept: ['jpeg', 'jpg', 'png'],
+        },
+        colProps: {
+          span: 12,
+        },
+      },
+    ];
+    const [registerForm, { validate, resetFields, setFieldsValue }] = useForm({
+      labelWidth: 100,
+      schemas: schemas,
+      showActionButtonGroup: false,
+      actionColOptions: {
+        span: 24,
+      },
+    });
+    const { createMessage, createConfirm } = useMessage();
+    onMounted(() => {});
+    let addListFunc = () => {};
+    const [register, { closeModal }] = useModalInner((data) => {
+      // console.log(data);
+      data && onDataReceive(data);
+    });
+
+    function onDataReceive(data) {
+      modelRef.value = data;
+      resetFields();
+      setFieldsValue({
+        ...data,
+        deviceType:t(`routes.scene.tableType.${data.cameraType || 0}`) +' '+ data.cameraSnCode
+      });
+    }
+
+    const handleSubmit = async () => {
+      createConfirm({
+        iconType: 'warning',
+        title: () => h('span', '温馨提示'),
+        content: '确定要提交测试结果吗?',
+        onOk: async () => {
+          const params = await validate()
+          const res = await testPassOrFail(params);
+          console.log('validate',params,res)
+          createMessage.success(t('common.optSuccess'));
+          closeModal();
+          emit('reload');
+        },
+      });
+    };
+    return {
+      register,
+      model: modelRef,
+      registerForm,
+      handleSubmit,
+      addListFunc,
+      resetFields,
+      t,
+    };
+  },
+});
+</script>
+<style lang="less" scoped>
+.recoverPage {
+  .form_item {
+    line-height: 30px;
+    .item_lable {
+      display: inline-block;
+      width: 100px;
+      text-align: right;
+    }
+  }
+}
+</style>

+ 251 - 0
src/views/work/testList.vue

@@ -0,0 +1,251 @@
+<template>
+  <PageWrapper contentBackground>
+    <template #footer>
+      <a-tabs v-model:activeKey="tableType" @change="changeTable">
+        <a-tab-pane :key="0" :tab="t('routes.spares.tableType.26')" />
+        <a-tab-pane :key="1" :tab="t('routes.spares.tableType.27')" />
+      </a-tabs></template
+    >
+    <div class="desc-wrap-BasicTable">
+    <BasicTable @register="registerTable">
+      <template #toolbar>
+        <a-button type="primary" @click="handleOrder" v-if="getCheckPerm('invoice-export')"> 录单</a-button>
+      </template>
+      <template #action="{ record }">
+        <TableAction
+          stopButtonPropagation
+          :actions="[
+            {
+              label: '详情',
+              onClick: handleDetail.bind(null, record),
+            },
+            {
+              label: '测试登记',
+              ifShow: tableType == 0,
+              onClick: handleRecover.bind(null, record),
+            },
+          ]"
+        />
+      </template>
+    </BasicTable>
+    <reviewModal @reload="reload" @register="registerRecovery" />
+    <!-- ifShow: getCheckPerm('device-out') && !Boolean(record.outType), -->
+  </div>
+</PageWrapper>
+</template>
+<script lang="ts">
+import { defineComponent, onMounted, ref } from 'vue';
+import { PageWrapper } from '/@/components/Page';
+import {
+  BasicTable,
+  useTable,
+  TableAction,
+  BasicColumn,
+  TableImg,
+  FormProps,
+} from '/@/components/Table';
+import { Tabs } from 'ant-design-vue';
+import { operateSceneList } from '/@/api/operate';
+import { useI18n } from '/@/hooks/web/useI18n';
+import { usePermissionStore } from '/@/store/modules/permission';
+import reviewModal from './reviewModal.vue';
+import { useModal } from '/@/components/Modal';
+import { useRouter } from 'vue-router'
+import { repairTesterList } from '/@/api/spares';
+export default defineComponent({
+  components: {
+    BasicTable,
+    TableAction,
+    TableImg,
+    reviewModal,
+    PageWrapper,
+    [Tabs.name]: Tabs,
+    [Tabs.TabPane.name]: Tabs.TabPane,
+  },
+  setup() {
+    const { t } = useI18n();
+    const permissionStore = usePermissionStore();
+    const router = useRouter()
+    const { getCheckPerm } = permissionStore;
+    const tableType = ref<Recordable>(0); //0看看 、1看见、2深时
+    onMounted(() => {
+      // console.log(router.currentRoute.value.params.id);
+    });
+    const columns: BasicColumn[] = [
+      {
+        title: '报修日期',
+        dataIndex: 'createTime',
+        width: 180,
+      },
+      {
+        title: '客户名称',
+        dataIndex: 'operationType',
+        width: 80,
+        customRender: ({ record }) => {
+          return t(`routes.equity.operation.${record.operationType || 0}`);
+        },
+      },
+      {
+        title: '产品类型',
+        dataIndex: 'cameraType',
+        width: 80,
+        customRender: ({ record }) => {
+          return t(`routes.equity.operation.${record.cameraType || 0}`);
+        },
+      },
+      {
+        title: '产品SN码',
+        dataIndex: 'cameraSnCode',
+        width: 100,
+      },
+      {
+        title: '售后工程师',
+        dataIndex: 'repairManName',
+        width: 100,
+      },
+      {
+        title: '接单日期',
+        dataIndex: 'orderReceivingTime',
+        width: 100,
+      },
+      {
+        title: '故障分析',
+        dataIndex: 'checkResult',
+        width: 150,
+      },
+      {
+        title: '维修工程师',
+        dataIndex: 'repairManName',
+        width: 100,
+      },
+      {
+        title: '状态',
+        dataIndex: 'status',
+        width: 100,
+        customRender: ({ record }) => {
+          return t(`routes.spares.tableType.${record.status || 0}`);
+        },
+      },
+      {
+        title: '工单号',
+        dataIndex: 'repairId',
+        width: 100,
+      },
+      {
+        title: t('common.operating'),
+        dataIndex: 'action',
+        slots: { customRender: 'action' },
+        ifShow: true,
+        fixed: 'right',
+        flag: 'ACTION',
+        width: 120,
+      },
+    ];
+    const searchForm: Partial<FormProps> = {
+      labelWidth: 120,
+      autoAdvancedLine: 1,
+      actionColOptions: {
+        span: 24,
+      },
+      schemas: [
+        {
+          field: 'customerName',
+          component: 'Input',
+          label: '客户名称',
+          colProps: {
+            xl: 7,
+            xxl: 7,
+          },
+        },
+        {
+          field: 'cameraSnCode',
+          component: 'Input',
+          label: t('routes.device.snCode'),
+          colProps: {
+            xl: 7,
+            xxl: 7,
+          },
+        },
+        {
+          field: 'trackingNum',
+          component: 'Input',
+          label: '快递单号',
+          colProps: {
+            xl: 7,
+            xxl: 7,
+          },
+        },
+        {
+          field: 'timeList',
+          label: '报修日期',
+          component: 'RangePicker',
+          componentProps: {
+            maxLength: 100,
+            format: 'YYYY-MM-DD',
+            valueFormat: 'YYYY-MM-DD',
+            showTime: true,
+          },
+          colProps: {
+            xl: 7,
+            xxl: 7,
+          },
+        },
+      ],
+    };
+    const [registerRecovery, { openModal }] = useModal();
+    const [registerTable, { reload }] = useTable({
+      api: repairTesterList,
+      columns: columns,
+      useSearchForm: true,
+      searchInfo: { statusParam: tableType },
+      formConfig: searchForm,
+      showTableSetting: true,
+      showIndexColumn: false,
+      fetchSetting: {
+        pageField: 'pageNum',
+        sizeField: 'pageSize',
+        listField: 'list',
+        totalField: 'total',
+      },
+      canResize: false,
+    });
+    async function handleDetail(record: Recordable) {
+      console.log('record', record);
+      router.push({path:`detail/${record.id||'20230215174919387'}`})
+    }
+    async function handleRecover(record: Recordable) {
+      openModal(true, {
+        tableType:tableType.value,
+        ...record,
+      });
+    }
+    function handleOrder() {
+      openModal(true);
+    }
+    function changeTable(val: string) {
+      tableType.value = val;
+      reload();
+    }
+    return {
+      registerTable,
+      reload,
+      t,
+      tableType,
+      changeTable,
+      handleOrder,
+      getCheckPerm,
+      handleDetail,
+      handleRecover,
+      registerRecovery,
+    };
+  },
+});
+</script>
+<style lang="less" scoped>
+.desc-wrap-BasicTable {
+  background-color: #f0f2f5;
+  .vben-basic-table-form-container {
+    padding: 0;
+  }
+}
+</style>