tangning 1 rok pred
rodič
commit
fda92287ad

+ 1 - 0
package.json

@@ -53,6 +53,7 @@
     "nprogress": "^0.2.0",
     "path-to-regexp": "^6.2.0",
     "pinia": "2.0.0",
+    "print-js": "^1.6.0",
     "qrcode": "^1.4.4",
     "qs": "^6.10.1",
     "resize-observer-polyfill": "^1.5.1",

+ 15 - 1
src/api/equity/index.ts

@@ -1,6 +1,6 @@
 import { defHttp } from '/@/utils/http/axios';
 import { listParams, checkParams, dincrementResult } from './model';
-import { Result } from '/#/axios';
+import { Result, FileStream } from '/#/axios';
 
 enum Api {
   incrementAdd = '/service/agent/increment/add',
@@ -11,6 +11,7 @@ enum Api {
   addDowm = '/service/agent/down/add',
   dowmList = '/service/agent/down/list',
   cameraIncrementLog = '/service/sale/operLog/pageOperLog',
+  listExport = '/service/sale/repairInfo/exportRepairInfo',
 }
 
 export const listApi = (params: listParams) =>
@@ -99,3 +100,16 @@ export const cameraIncrementLog = (params: checkParams) =>
       ignoreCancelToken: true,
     },
   });
+
+export const DownExport = (params) =>
+  defHttp.downloadFile<FileStream>({
+    url: Api.listExport + `?lang=${params.lang}`,
+    params: params,
+    fileName: '工单列表.xlsx',
+    // data: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+    responseType: 'blob',
+  });

+ 11 - 0
src/api/spares/index.ts

@@ -43,6 +43,7 @@ enum Api {
   checkAccount = '/service/sale/repairCheckAccount/checkAccount',
   u8ListList = '/service/sale/repairU8/u8List',
   u8Send = '/service/sale/repairU8/u8Send',
+  invoiceRegister = '/service/sale/repairInvoice/invoiceRegister',
 }
 
 /**
@@ -403,6 +404,16 @@ export const repairOver = (params) =>
     },
   });
 
+export const invoiceRegister = (params) =>
+  defHttp.post<detailResult>({
+    url: Api.invoiceRegister,
+    params: params,
+    headers: {
+      // @ts-ignore
+      ignoreCancelToken: true,
+    },
+  });
+
 export const partInStockLog = (params) =>
   defHttp.post<detailResult>({
     url: Api.partInStockLog,

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

@@ -196,6 +196,7 @@ export interface detailResult {
   priceList: any[];
   lastRepairId: any;
   haveButton: any;
+  repairInvoice: any;
 }
 export type InvoiceListResul = BasicPageParams<InvoiceList>;
 /**

+ 2 - 1
src/views/Accounting/index.vue

@@ -3,6 +3,7 @@
     <template #footer>
       <a-tabs v-model:activeKey="tableType" @change="changeTable">
         <a-tab-pane :key="0" tab="待核账" />
+        <a-tab-pane :key="1" tab="已核账" />
       </a-tabs>
     </template>
     <div class="desc-wrap-BasicTable">
@@ -18,7 +19,7 @@
               },
               {
                 label: '到账登记',
-                ifShow: getCheckPerm('Account_registration'),
+                ifShow: getCheckPerm('Account_registration') && tableType != 1,
                 onClick: handleRecover.bind(null, record),
               },
             ]"

+ 1 - 1
src/views/spares/detail.vue

@@ -391,7 +391,7 @@
 
       &_right {
         width: 400px;
-        padding: 40px 20px;
+        padding: 40px 0px 40px 20px;
       }
       &_left {
         width: calc(100% - 400px);

+ 42 - 3
src/views/work/detail.vue

@@ -1,11 +1,12 @@
 <template>
   <div class="detailPage">
     <div class="topButton">
+      <a-button type="primary" style="margin-right: 20px" @click="enterDialog"> 打印 </a-button>
       <a-button type="primary" @click="goBack">
         {{ t('common.back') }}
       </a-button>
     </div>
-    <div class="content">
+    <div class="content" ref="print" id="print">
       <div class="content_left">
         <div class="content_left_info">
           <Descriptions title="客户信息" :column="3" v-if="detailData.customer">
@@ -17,6 +18,23 @@
             </DescriptionsItem>
             <DescriptionsItem label="联系电话"> {{ detailData.customer.phone }} </DescriptionsItem>
           </Descriptions>
+          <Descriptions title="发票信息" :column="3" v-if="detailData.repairInvoice">
+            <DescriptionsItem label="是否开票">
+              {{ detailData.repairInvoice.repairId ? '是' : '否' }}</DescriptionsItem
+            >
+            <DescriptionsItem
+              v-if="detailData.repairInvoice && detailData.repairInvoice.invoiceHead"
+              label="发票抬头"
+            >
+              {{ detailData.repairInvoice.invoiceHead }}
+            </DescriptionsItem>
+            <DescriptionsItem
+              v-if="detailData.repairInvoice && detailData.repairInvoice.invoiceNum"
+              label="税号"
+            >
+              {{ detailData.repairInvoice.invoiceNum }}
+            </DescriptionsItem>
+          </Descriptions>
           <Descriptions title="产品及故障信息" :column="3">
             <DescriptionsItem label="产品名称" v-if="detailData.repairerVo">
               {{ t(`routes.scene.tableType.${detailData.repairerVo.cameraType}`) }}
@@ -166,7 +184,7 @@
                 </PreviewGroup>
               </div>
             </DescriptionsItem>
-            <DescriptionsItem label="支付备注" :span="3">
+            <DescriptionsItem style="padding-bottom: 16px" label="支付备注" :span="3">
               {{ detailData.repairPay?.remark }}
             </DescriptionsItem>
             <DescriptionsItem label="回单备注" :span="3">
@@ -339,6 +357,7 @@
   import { detail, process, detailDownExport } from '/@/api/spares';
   import { detailResult } from '/@/api/spares/model';
   import { useModal } from '/@/components/Modal';
+  import printJS from 'print-js';
   // import recoveryModal from './recoveryModal.vue';//录单
   import quoteModel from './quoteModel.vue';
   import deliveryModal from './deliveryModal.vue';
@@ -385,6 +404,7 @@
       const router = useRouter();
       const { createMessage, createConfirm } = useMessage();
       const { t } = useI18n();
+      const print = ref(null);
       const permissionStore = usePermissionStore();
       const { getCheckPerm } = permissionStore;
       const repairId = ref<string | string[]>(router.currentRoute.value.params.id || '0');
@@ -435,6 +455,18 @@
           width: 140,
         },
       ];
+      async function enterDialog() {
+        const style =
+          '@page {margin:0mm 10mm};' +
+          '@media print { .status{ overflow:hidden;text-overflow:ellipsis;white-space:nowrap; }}'; //打印时去掉眉页眉尾
+        printJS({
+          printable: 'print', // 标签元素id
+          type: 'html',
+          headerStyle: 'font-weight:400;text-align:center;',
+          targetStyles: ['*'],
+          style,
+        });
+      }
       async function getData() {
         const stepRes = await process({ repairId: repairId.value });
         let butTypeList = {
@@ -659,6 +691,8 @@
         stepList,
         dowmFile,
         t,
+        enterDialog,
+        print,
       };
     },
   });
@@ -687,8 +721,13 @@
 
       &_right {
         width: 400px;
-        padding: 40px 20px;
+        padding: 40px 0px 40px 20px;
         .timeItem {
+          .status {
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+          }
           .ant-image-img {
             width: 100%;
             height: 100%;

+ 22 - 0
src/views/work/followedList.vue

@@ -61,6 +61,11 @@
                 ifShow: getCheckPerm('work_mark'),
                 onClick: handleRemarks.bind(null, record),
               },
+              {
+                label: '开票信息',
+                ifShow: getCheckPerm('work_mark') && record.status > 80 && record.warrantyType != 0 && record.warrantyType != 3 && record.payAmount != 0 && record.invoiceStatus == 0,
+                onClick: handleInvoice.bind(null, record),
+              },
             ]"
           />
         </template>
@@ -72,6 +77,7 @@
       <deliveryModal @update="reload" @register="registerDelivery" />
       <payLogModal @update="reload" @register="registerPayLog" />
       <confirmPriceModal @update="reload" @register="registerConfirmPrice" />
+      <invoiceModal @update="reload" @register="registerInvoice" />
       <!-- ifShow: getCheckPerm('device-out') && !Boolean(record.outType), -->
     </div>
   </PageWrapper>
@@ -95,6 +101,7 @@
   import quoteModel from './quoteModel.vue';
   import deliveryModal from './deliveryModal.vue';
   import payLogModal from './payLogModal.vue';
+  import invoiceModal from './invoiceModal.vue';
   import takingOrdersModel from './takingOrdersModel.vue';
   import remarksModal from '../spares/remarksModal.vue';
   import confirmPriceModal from './confirmPriceModal.vue';
@@ -114,6 +121,7 @@
       payLogModal,
       confirmPriceModal,
       quoteModel,
+      invoiceModal,
       PageWrapper,
       [Tabs.name]: Tabs,
       [Tabs.TabPane.name]: Tabs.TabPane,
@@ -183,6 +191,14 @@
           width: 150,
         },
         {
+          title: '需要开票',
+          dataIndex: 'invoiceStatus',
+          width: 80,
+          customRender: ({ record }) => {
+            return record.invoiceStatus == 0 ? '否' : '是';
+          },
+        },
+        {
           title: t('common.operating'),
           dataIndex: 'action',
           slots: { customRender: 'action' },
@@ -259,6 +275,7 @@
       const [registerDelivery, { openModal: openDeliveryModal }] = useModal();
       const [registerTakingOrders, { openModal: openTakingOrders }] = useModal();
       const [registerRemarks, { openModal: openRemarksModal }] = useModal();
+      const [registerInvoice, { openModal: openInvoiceModal }] = useModal();
       const [registerTable, { reload }] = useTable({
         api: saleOrderList,
         columns: columns,
@@ -287,6 +304,9 @@
       function handleRemarks(record: Recordable) {
         openRemarksModal(true, record);
       }
+      function handleInvoice(record: Recordable) {
+        openInvoiceModal(true, record);
+      }
       function handlePayLog(record: Recordable) {
         openPayLogModal(true, record);
       }
@@ -316,6 +336,7 @@
         tableType,
         registerRemarks,
         registerPayLog,
+        registerInvoice,
         registerDelivery,
         registerConfirmPrice,
         changeTable,
@@ -329,6 +350,7 @@
         handlePayLog,
         handleDelivery,
         handleRemarks,
+        handleInvoice,
         registerQuote,
         registerRecovery,
       };

+ 383 - 0
src/views/work/invoiceModal.vue

@@ -0,0 +1,383 @@
+<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, 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,
+    partInfo,
+    partInfo,
+    invoiceRegister,
+    repairOver,
+  } 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 n = ref(1);
+      const repairId = ref('');
+      const fileFlow = reactive({
+        file: null,
+        invoiceAmount: 0,
+        repairId: null,
+      });
+      const loading = ref(false);
+      const { createMessage, createConfirm } = useMessage();
+      let schemas: FormSchema[] = [
+        {
+          field: 'companyName',
+          component: 'Input',
+          label: '客户名称',
+          slot: 'text',
+          colProps: {
+            span: 18,
+          },
+        },
+        {
+          field: 'repairId',
+          component: 'Input',
+          label: '维修单号',
+          slot: 'text',
+          colProps: {
+            span: 24,
+          },
+        },
+        {
+          field: 'deviceType',
+          component: 'Input',
+          label: '设备信息',
+          slot: 'text',
+          colProps: {
+            span: 18,
+          },
+        },
+        {
+          field: 'defineDamage',
+          component: 'RadioGroup',
+          label: '是否开票',
+          defaultValue: 1,
+          componentProps: {
+            options: [
+              {
+                label: '是',
+                value: 1,
+              },
+              {
+                label: '否',
+                value: 0,
+              },
+            ],
+            onChange: (val) => {
+              handleUpShow(val.target.value == 1 ? true : false);
+            },
+          },
+          colProps: {
+            span: 22,
+          },
+        },
+        {
+          field: 'invoiceType',
+          component: 'RadioGroup',
+          label: '发票类型',
+          defaultValue: 0,
+          componentProps: {
+            options: [
+              {
+                label: '普通发票',
+                value: 0,
+              },
+              {
+                label: '专用发票',
+                value: 1,
+              },
+            ],
+          },
+          colProps: {
+            span: 22,
+          },
+        },
+        {
+          field: 'invoiceHead',
+          component: 'Input',
+          label: '发票抬头',
+          componentProps: {
+            disabled: true,
+          },
+          colProps: {
+            span: 18,
+          },
+        },
+        {
+          field: 'invoiceNum',
+          component: 'Input',
+          label: '税号',
+          colProps: {
+            span: 18,
+          },
+        },
+        {
+          field: 'bank',
+          component: 'Input',
+          label: '开户银行',
+          colProps: {
+            span: 18,
+          },
+        },
+        {
+          field: 'bankAccount',
+          component: 'Input',
+          label: '银行账户',
+          colProps: {
+            span: 18,
+          },
+        },
+        {
+          field: 'address',
+          component: 'Input',
+          label: '企业地址',
+          colProps: {
+            span: 18,
+          },
+        },
+        {
+          field: 'phone',
+          component: 'Input',
+          label: '企业电话',
+          colProps: {
+            span: 18,
+          },
+        },
+        {
+          field: 'invoiceEmail',
+          component: 'Input',
+          label: '电子邮箱',
+          colProps: {
+            span: 18,
+          },
+          required: true,
+          componentProps: {
+            placeholder: '请填写接收发票邮箱',
+            maxLength: 50,
+          },
+        },
+        {
+          field: 'getAddress',
+          component: 'Input',
+          label: '收件地址',
+          colProps: {
+            span: 18,
+          },
+          required: true,
+          componentProps: {
+            placeholder: '请填写收件地址',
+            maxLength: 50,
+          },
+        },
+        {
+          field: 'getAddrName',
+          component: 'Input',
+          label: '收件人',
+          colProps: {
+            span: 18,
+          },
+          required: true,
+          componentProps: {
+            placeholder: '请填写收件人',
+            maxLength: 50,
+          },
+        },
+        {
+          field: 'getAddrPhone',
+          component: 'Input',
+          label: '收件人电话',
+          colProps: {
+            span: 18,
+          },
+          required: true,
+          rules: [
+            {
+              required: true,
+              // @ts-ignore
+              validator: async (rule, value) => {
+                var reg_tel =
+                  /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;
+                // var reg = /\S+@\S+\.\S+/;
+                if (!value) {
+                  /* eslint-disable-next-line */
+
+                  return Promise.reject(t('common.phone'));
+                }
+                if (!reg_tel.test(value)) {
+                  /* eslint-disable-next-line */
+                return Promise.reject(t('common.phoneError'));
+                }
+                return Promise.resolve();
+              },
+              trigger: 'change',
+            },
+          ],
+          componentProps: {
+            placeholder: '请填写手机号',
+            maxLength: 50,
+          },
+        },
+      ];
+      const [
+        registerForm,
+        {
+          validate,
+          resetFields,
+          setFieldsValue,
+          removeSchemaByFiled,
+          appendSchemaByField,
+          updateSchema,
+        },
+      ] = useForm({
+        labelWidth: 100,
+        schemas: schemas,
+        showActionButtonGroup: false,
+        actionColOptions: {
+          span: 24,
+        },
+      });
+      onMounted(() => {});
+      // getFaultList();
+      let addListFunc = () => {};
+      const [register, { closeModal }] = useModalInner((data) => {
+        repairId.value = data?.repairId;
+        data && onDataReceive(data);
+      });
+      async function getFaultList() {
+        const res = await faultAllList({});
+        fileFlow.faultList = res.map((item) => {
+          return {
+            ...item,
+            label: item.faultMsg,
+            value: item.faultId,
+          };
+        });
+      }
+
+      function onDataReceive(data) {
+        resetFields();
+        fileFlow.invoiceAmount = data.payAmount;
+        fileFlow.repairId = data.repairId;
+        console.log('openOutModal', fileFlow, data);
+        setFieldsValue({
+          ...data,
+          invoiceHead: data.companyName,
+          deviceType: t(`routes.scene.tableType.${data.cameraType}`) + ' ' + data.cameraSnCode,
+        });
+      }
+      const handleUpShow = async (val) => {
+        console.log(val);
+        updateSchema([
+          {
+            field: 'invoiceType',
+            ifShow: val,
+          },
+          {
+            field: 'companyName',
+            ifShow: val,
+          },
+          {
+            field: 'invoiceNum',
+            ifShow: val,
+          },
+          {
+            field: 'bank',
+            ifShow: val,
+          },
+          {
+            field: 'bankAccount',
+            ifShow: val,
+          },
+          {
+            field: 'address',
+            ifShow: val,
+          },
+          {
+            field: 'phone',
+            ifShow: val,
+          },
+          {
+            field: 'invoiceEmail',
+            ifShow: val,
+          },
+          {
+            field: 'getAddress',
+            ifShow: val,
+          },
+          {
+            field: 'getAddrName',
+            ifShow: val,
+          },
+          {
+            field: 'getAddrPhone',
+            ifShow: val,
+          },
+        ]);
+      };
+      const handleSubmit = async () => {
+        const params = await validate();
+        try {
+          createConfirm({
+            iconType: 'warning',
+            title: () => h('span', '温馨提示'),
+            content: '确定要开具发票吗?',
+            onOk: async () => {
+              loading.value = true;
+              await invoiceRegister({...params,...fileFlow});
+              loading.value = false;
+              createMessage.success(t('common.optSuccess'));
+              closeModal();
+              emit('update');
+            },
+            onCancel: () => {
+              loading.value = false;
+            },
+          });
+        } catch (error) {
+          loading.value = false;
+          console.log('not passing', error);
+        }
+      };
+      return {
+        register,
+        registerForm,
+        fileFlow,
+        handleSubmit,
+        addListFunc,
+        resetFields,
+        loading,
+        t,
+      };
+    },
+  });
+</script>

+ 18 - 1
src/views/work/query.vue

@@ -19,6 +19,9 @@
     ></template>
     <div class="desc-wrap-BasicTable">
       <BasicTable @register="registerTable" v-show="tableType == null">
+        <template #toolbar>
+          <a-button type="primary" @click="handleExport"> 导出</a-button>
+        </template>
         <template #action="{ record }">
           <TableAction
             stopButtonPropagation
@@ -52,7 +55,7 @@
   </PageWrapper>
 </template>
 <script lang="ts">
-  import { defineComponent, onMounted, ref, onActivated } from 'vue';
+  import { defineComponent, onMounted, ref, onActivated, h } from 'vue';
   import { PageWrapper } from '/@/components/Page';
   import {
     BasicTable,
@@ -68,8 +71,10 @@
   import { usePermissionStore } from '/@/store/modules/permission';
   import recoveryModal from './recoveryModal.vue';
   import { useModal } from '/@/components/Modal';
+  import { useMessage } from '/@/hooks/web/useMessage';
   import { useRouter } from 'vue-router';
   import { queryList, faultAllList, getByRoleType } from '/@/api/spares';
+  import { DownExport } from '/@/api/equity';
   export default defineComponent({
     name: '工单查询',
     components: {
@@ -85,6 +90,7 @@
       const { t } = useI18n();
       const permissionStore = usePermissionStore();
       const router = useRouter();
+      const { createConfirm } = useMessage();
       const { getCheckPerm } = permissionStore;
       const tableType = ref<Recordable>(null); //0看看 、1看见、2深时
       onMounted(() => {
@@ -562,6 +568,16 @@
         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({});
+          },
+        });
+      }
       return {
         registerTable,
         registerTable1,
@@ -573,6 +589,7 @@
         handleDetail,
         handleRecover,
         registerRecovery,
+        handleExport,
       };
     },
   });

+ 5 - 0
yarn.lock

@@ -8987,6 +8987,11 @@ pretty-format@^27.0.0, pretty-format@^27.5.1:
     ansi-styles "^5.0.0"
     react-is "^17.0.1"
 
+print-js@^1.6.0:
+  version "1.6.0"
+  resolved "http://192.168.0.47:4873/print-js/-/print-js-1.6.0.tgz#692b046cf31992b46afa6c6d8a9db1c69d431d1f"
+  integrity sha512-BfnOIzSKbqGRtO4o0rnj/K3681BSd2QUrsIZy/+WdCIugjIswjmx3lDEZpXB2ruGf9d4b3YNINri81+J0FsBWg==
+
 process-nextick-args@~2.0.0:
   version "2.0.1"
   resolved "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz"