Browse Source

feat:应收账款明细、应收账款汇总、项目经理日报

snow 1 year ago
parent
commit
b47cb8504a
27 changed files with 1181 additions and 15 deletions
  1. 4 4
      src/components/PageContent/src/page-content.tsx
  2. 6 7
      src/components/PageSearch/src/hooks/use-page-search.ts
  3. 3 0
      src/components/PageSearch/src/page-search.vue
  4. 2 2
      src/components/PageSearch/src/utils/create-form-data.ts
  5. 54 0
      src/views/time/receivable/components/all.vue
  6. 93 0
      src/views/time/receivable/components/business.vue
  7. 9 0
      src/views/time/receivable/components/config/apis.ts
  8. 103 0
      src/views/time/receivable/components/config/content.config.ts
  9. 46 0
      src/views/time/receivable/components/config/search.config.ts
  10. 49 0
      src/views/time/receivable/index.vue
  11. 0 0
      src/views/time/receivable/应收账款汇总
  12. 68 0
      src/views/time/receivableDetail/components/all.vue
  13. 107 0
      src/views/time/receivableDetail/components/business.vue
  14. 8 0
      src/views/time/receivableDetail/components/config/apis.ts
  15. 176 0
      src/views/time/receivableDetail/components/config/content.config.ts
  16. 46 0
      src/views/time/receivableDetail/components/config/search.config.ts
  17. 49 0
      src/views/time/receivableDetail/index.vue
  18. 0 0
      src/views/time/receivableDetail/应收装款明细
  19. 54 0
      src/views/time/receivableManager/components/all.vue
  20. 102 0
      src/views/time/receivableManager/components/business.vue
  21. 9 0
      src/views/time/receivableManager/components/config/apis.ts
  22. 95 0
      src/views/time/receivableManager/components/config/content.config.ts
  23. 47 0
      src/views/time/receivableManager/components/config/search.config.ts
  24. 49 0
      src/views/time/receivableManager/index.vue
  25. 0 0
      src/views/time/receivableManager/项目经理日报
  26. 1 1
      src/views/time/reportDaily/components/business.vue
  27. 1 1
      src/views/time/reportDaily/index.vue

+ 4 - 4
src/components/PageContent/src/page-content.tsx

@@ -185,10 +185,10 @@ const PageContent = defineComponent({
 
     onBeforeRouteLeave(({ path }) => {
       //到详情页保存查询参数 到其他页面清空查询参数
-      const isDetail = path.indexOf("Detail") >= 0;
-      const basicParams = isDetail ? getBasicParams() : null;
-      const pagination = isDetail ? getPagination() : null;
-      setSearchParams(basicParams, pagination);
+      // const isDetail = path.indexOf("Detail") >= 0;
+      // const basicParams = isDetail && getBasicParams ? getBasicParams() : null;
+      // const pagination = isDetail && getPagination ? getPagination() : null;
+      // setSearchParams(basicParams, pagination);
     });
 
     const renderExpand = (row) => slots.expand && slots.expand(row)

+ 6 - 7
src/components/PageSearch/src/hooks/use-page-search.ts

@@ -72,14 +72,13 @@ export function usePageSearch(
   }
 
   function handleResetClick(params?: any) {
-    const { result } = resetCallback ? resetCallback(params) : { result: {} };
+    // const { result } = resetCallback ? resetCallback(params) : { result: {} };
+    // console.log(searchCallback)
+    // if (lockKey) {
+    //   result[lockKey] = params[lockKey]
+    // }
 
-    console.log(searchCallback)
-    if (lockKey) {
-      result[lockKey] = params[lockKey]
-    }
-
-    pageContentRef.value?.getPageData(resetEmpty ? {} : result);
+    pageContentRef.value?.getPageData(params);
     resetCallback && resetCallback();
   }
 

+ 3 - 0
src/components/PageSearch/src/page-search.vue

@@ -25,6 +25,9 @@ function handleResetClick() {
     formData.value,
     props.lockKey
   );
+
+  console.log(newFormData);
+  
   formData.value = newFormData;
   emit("resetBtnClick", newFormData);
 }

+ 2 - 2
src/components/PageSearch/src/utils/create-form-data.ts

@@ -18,13 +18,13 @@ export function createFormData(
     } else if (lockKey && lockKey.includes(item.field)) {
       formData[item.field] = source[item.field] || "";
     } else if (isInputGroup) {
-      const defaultSelectType =
-        item.otherOptions?.inputGroupOptions[0]?.value || "";
+      const defaultSelectType = item.otherOptions?.inputGroupOptions[0]?.value || "";
       formData[item.field] = "";
       formData[item.type_field] = defaultSelectType;
     } else {
       formData[item.field] = isCheckBox || isDatepicker || isRange ? [] : "";
     }
   }
+
   return formData;
 }

+ 54 - 0
src/views/time/receivable/components/all.vue

@@ -0,0 +1,54 @@
+<script setup lang="ts">
+import { ref } from "vue";
+import searchConfig from "./config/search.config";
+import contentConfig from "./config/content.config";
+
+import { PageContentInstance } from "/@/components/PageContent";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
+import { usePageSearch, type PageHooks } from "/@/hooks/page";
+import { isBeyondTime } from "/@/views/time/_utils";
+import { frontEndExport } from "/@/utils/export";
+import { usePermission } from "/@/hooks/core";
+
+const pageName = "receivable";
+const { hasPermissionWithCode } = usePermission(pageName);
+const pageContentRef = ref<PageContentInstance | null>(null);
+
+const hooks: PageHooks = {
+  pageSearchHook: () => {
+    return usePageSearch(undefined, undefined, searchConfig);
+  }
+};
+
+async function handleExportAllReport() {
+  const params = pageContentRef.value.getBasicParams() || {};
+  const { start, end } = params;
+  const beyondTime = isBeyondTime({ start, end, len: 30 });
+  if (beyondTime) return;
+  const data = pageContentRef.value.getData();
+  frontEndExport({ columns: contentConfig.columns, name: "应收账款汇总.xlsx", data });
+}
+</script>
+
+<template>
+  <page-auth :page-name="pageName">
+    <page-container
+      :hooks="hooks"
+      :page-name="pageName"
+      :get-content-ref="ref => (pageContentRef = ref)"
+      :content-config="contentConfig"
+      :search-config="searchConfig"
+    >
+      <template #content_header>
+        <el-button
+          v-if="hasPermissionWithCode('9')"
+          @click="handleExportAllReport"
+          size="small"
+          :icon="useRenderIcon('arrow-up-line')"
+          type="primary"
+          >导出</el-button
+        >
+      </template>
+    </page-container>
+  </page-auth>
+</template>

+ 93 - 0
src/views/time/receivable/components/business.vue

@@ -0,0 +1,93 @@
+<script setup lang="ts">
+import { ref, watch } from "vue";
+import apis from "./config/apis";
+import { ElMessage } from "element-plus";
+import { usePermission } from "/@/hooks/core";
+import { frontEndExport } from "/@/utils/export";
+import { isBeyondTime } from "/@/views/time/_utils";
+import sourceSearchConfig from "./config/search.config";
+import sourceContentConfig from "./config/content.config";
+import { usePageSearch, type PageHooks } from "/@/hooks/page";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
+import { PageContentInstance } from "/@/components/PageContent";
+import { useBusinessSearch, useBusinessContent } from "./../../_hooks";
+import { useUserStore } from "/@/store/modules/user";
+
+const pageContentRef = ref<PageContentInstance | null>(null);
+const lockKey = "companyNo";
+
+const pageName = "receivable";
+const { hasPermissionWithCode } = usePermission(pageName);
+
+const userStore = useUserStore();
+const { searchConfig } = useBusinessSearch({
+  sourceConfig: sourceSearchConfig,
+  queryField: "companyNo"
+});
+
+const searchConfigRef = ref(searchConfig);
+
+const { contentConfig } = useBusinessContent({
+  sourceConfig: sourceContentConfig,
+  apis: { httpList: apis.list }
+});
+
+const hooks: PageHooks = {
+  pageSearchHook: () =>
+    usePageSearch(undefined, undefined, searchConfig, false, lockKey)
+};
+
+watch(
+  () => userStore.level,
+  level => {
+    const { formItems } = searchConfigRef.value;
+    const index = formItems.findIndex(({ field }) => field === "depart_id");
+    const { itemid = "" } = userStore.info || {};
+
+    if (Number(level) === 2) {
+      searchConfigRef.value.formItems[index].disabled = Number(level) === 2;
+      searchConfigRef.value.formItems[index].defaultValue = itemid;
+    }
+  },
+  {
+    immediate: true
+  }
+);
+
+async function handleExportAllReport() {
+  const params = pageContentRef.value.getBasicParams() || {};
+
+  const { start, end } = params;
+
+  if (!params[lockKey]) {
+    ElMessage.warning("请选择业务公司");
+    return;
+  }
+
+  const beyondTime = isBeyondTime({ end,  start, len: 30 });
+  if (beyondTime) return;
+  const data = pageContentRef.value.getData();
+  frontEndExport({ columns: contentConfig.columns, name: "应收账款汇总.xlsx", data });
+}
+</script>
+
+<template>
+  <PageContainer
+    :hooks="hooks"
+    :getContentRef="ref => (pageContentRef = ref)"
+    :content-config="contentConfig"
+    :search-config="searchConfig"
+    lockKey="relaComNo"
+  >
+    <template #content_header>
+      <el-button
+        v-if="hasPermissionWithCode('18')"
+        :icon="useRenderIcon('arrow-up-line')"
+        @click="handleExportAllReport"
+        size="small"
+        type="primary"
+        >导出</el-button
+      >
+    </template>
+  </PageContainer>
+</template>

+ 9 - 0
src/views/time/receivable/components/config/apis.ts

@@ -0,0 +1,9 @@
+import { createHttpRequest } from "/@/views/time/_http";
+
+const baseUrl = "admin/report/";
+
+
+export default {
+  list: createHttpRequest(`${baseUrl}dzListByUser`),
+  businessList: createHttpRequest("")
+};

+ 103 - 0
src/views/time/receivable/components/config/content.config.ts

@@ -0,0 +1,103 @@
+/* eslint-disable prettier/prettier */
+import { BeforeRequestType, ContentConfig } from "/@/components/PageContent";
+import apis from "./apis";
+import { isBeyondTime } from "/@/views/reportCollection/_utils";
+import { addition } from "/@/utils/calc";
+
+const columns = [
+  {
+    prop: 'ownerName',
+    label: '销售员',
+    minWidth: '155px'
+  },
+  {
+    prop: 'department',
+    label: '所在部门',
+    minWidth: '155px'
+  },
+  {
+    prop: 'wpay_fee',
+    label: '未回款总额',
+    minWidth: '155px'
+  },
+
+  {
+    prop: 'pay_fee',
+    label: '回款进行中总额',
+    minWidth: '155px'
+  },
+  {
+    prop: 'apay_fee',
+    label: '已回款总额',
+    minWidth: '155px'
+  },
+  {
+    prop: 'winv_fee',
+    label: '未开票总额',
+    minWidth: '155px'
+  },
+  {
+    prop: 'inv_fee',
+    label: '开票进行中总额',
+    minWidth: '155px'
+  },
+  {
+    prop: 'ainv_fee',
+    label: '已开票总额',
+    minWidth: '155px'
+  }
+];
+
+const contentConfig: ContentConfig = {
+  columns,
+  showTitle: false,
+  responseCode: 0,
+  notPagination: true,
+  superUserNoAction: false,
+  tableRowClassName({ rowIndex }) {
+    if (rowIndex === 0) {
+      return "warning-row"
+    }
+  },
+  beforeRequestList(params) {
+    const { start, end } = params;
+    const beyondTime = isBeyondTime({ name: "下单时间", len: 30, start, end });
+    if (beyondTime) return BeforeRequestType.EMPTY
+    return BeforeRequestType.NEXT;
+  },
+  handleData(list) {
+    const mapTotal: Record<string, string | number> = {
+      ownerName: '合计',
+      department: '--',
+      wpay_fee: 0,
+      pay_fee: 0,
+      apay_fee: 0,
+      winv_fee: 0,
+      inv_fee: 0,
+      ainv_fee: 0,
+    }
+
+    list.forEach(item => {
+      const {
+        wpay_fee,
+        pay_fee,
+        apay_fee,
+        winv_fee,
+        inv_fee,
+        ainv_fee
+      } = item;
+
+      mapTotal.wpay_fee = Number(addition(mapTotal.wpay_fee, wpay_fee)).toFixed(0);
+      mapTotal.pay_fee = Number(addition(mapTotal.pay_fee, pay_fee)).toFixed(2);
+      mapTotal.apay_fee = Number(addition(mapTotal.apay_fee, apay_fee)).toFixed(2);
+      mapTotal.winv_fee = Number(addition(mapTotal.winv_fee, winv_fee)).toFixed(2);
+      mapTotal.inv_fee = Number(addition(mapTotal.inv_fee, inv_fee)).toFixed(2);
+      mapTotal.ainv_fee = Number(addition(mapTotal.ainv_fee, ainv_fee)).toFixed(2);
+    });
+
+    return [mapTotal, ...list]
+  },
+  apis: { httpList: apis.list }
+};
+
+export default contentConfig;

+ 46 - 0
src/views/time/receivable/components/config/search.config.ts

@@ -0,0 +1,46 @@
+import { FormConfig } from "/@/components/PageSearch";
+import dayjs from "dayjs";
+import { useUserStore } from "/@/store/modules/user";
+
+const now = new Date();
+const start = dayjs(now).subtract(30, 'days').format("YYYY-MM-DD");
+const end = dayjs(now).format('YYYY-MM-DD');
+
+const searchFormConfig: FormConfig = {
+  formItems: [
+    {
+      field: "date",
+      type: "date_picker",
+      defaultValue: [start, end],
+      trigger: "change",
+      otherOptions: {
+        type: "daterange",
+        startPlaceholder: "下单开始时间",
+        endPlaceholder: "下单结束时间",
+        valueFormat: "YYYY-MM-DD",
+        startProp: "start",
+        endProp: "end"
+      }
+    },
+    {
+      field: "depart_id",
+      type: "depart-query",
+      trigger: "change"
+    },
+    {
+      field: 'plat_type',
+      type: 'select',
+      trigger: 'change',
+      defaultValue: '1',
+      options: [
+        { value: '1', label: 'toB' },
+        { value: '2', label: 'toC' }
+      ],
+      otherOptions: {
+        clearable: false
+      }
+    }
+  ]
+};
+
+export default searchFormConfig;

+ 49 - 0
src/views/time/receivable/index.vue

@@ -0,0 +1,49 @@
+<script setup lang="ts">
+import { shallowRef, onMounted } from "vue";
+import All from "./components/all.vue";
+import Business from "./components/business.vue";
+import { usePermission } from "/@/hooks/core";
+import NoAuth from "/@/components/NoAuth/NoAuth.vue";
+
+const actived = shallowRef("");
+
+const { hasPermissionWithCode } = usePermission("receivable");
+
+onMounted(() => {
+  if (hasPermissionWithCode("3")) {
+    actived.value = "3";
+  } else if (hasPermissionWithCode("11")) {
+    actived.value = "11";
+  }
+});
+</script>
+
+<template>
+  <div class="report-container">
+    <el-tabs v-model="actived" style="color: #fff" v-if="actived">
+      <el-tab-pane label="查看全部" name="3" v-if="hasPermissionWithCode('3')">
+        <all v-if="actived === '3'" />
+      </el-tab-pane>
+
+      <el-tab-pane
+        name="11"
+        label="查看业务公司"
+        v-if="hasPermissionWithCode('11')"
+      >
+        <business v-if="actived === '11'" />
+      </el-tab-pane>
+    </el-tabs>
+
+    <no-auth v-else />
+  </div>
+</template>
+
+<style scoped lang="scss">
+.report-container {
+  height: calc(100vh - 48px);
+  :deep(.el-tabs__header) {
+    background-color: #fff;
+    padding: 10px 10px 0;
+  }
+}
+</style>

+ 0 - 0
src/views/time/receivable/应收账款汇总


+ 68 - 0
src/views/time/receivableDetail/components/all.vue

@@ -0,0 +1,68 @@
+<script setup lang="ts">
+import { ref, shallowRef } from "vue";
+import searchConfig from "./config/search.config";
+import contentConfig from "./config/content.config";
+
+import { PageContentInstance } from "/@/components/PageContent";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
+import { usePageSearch, type PageHooks } from "/@/hooks/page";
+import { isBeyondTime } from "/@/views/time/_utils";
+import { httpRequsetExport } from "/@/utils/export";
+import { usePermission } from "/@/hooks/core";
+
+const pageName = "reportDaily";
+const { hasPermissionWithCode } = usePermission(pageName);
+const pageContentRef = ref<PageContentInstance | null>(null);
+const loading = shallowRef(false);
+
+const hooks: PageHooks = {
+  pageSearchHook: () => {
+    return usePageSearch(undefined, undefined, searchConfig);
+  }
+};
+
+const callback = {
+  onSuccess: () => (loading.value = false),
+  onStart: () => (loading.value = true),
+  onFail: () => (loading.value = false)
+};
+
+async function handleExportAllReport() {
+  const params = pageContentRef.value.getBasicParams() || {};
+  const { start, end } = params;
+  const beyondTime = isBeyondTime({ start, end, len: 30 });
+  if (beyondTime) return;
+
+
+  await httpRequsetExport({
+    fileType: "aplication/x-msexecl",
+    name: "应收账款明细.xlsx",
+    url: "report/dzListExport",
+    ...callback,
+    params
+  });
+}
+</script>
+
+<template>
+  <page-auth :page-name="pageName" v-loading="loading">
+    <page-container
+      :hooks="hooks"
+      :page-name="pageName"
+      :get-content-ref="ref => (pageContentRef = ref)"
+      :content-config="contentConfig"
+      :search-config="searchConfig"
+    >
+      <template #content_header>
+        <el-button
+          v-if="hasPermissionWithCode('9')"
+          @click="handleExportAllReport"
+          size="small"
+          :icon="useRenderIcon('arrow-up-line')"
+          type="primary"
+          >导出</el-button
+        >
+      </template>
+    </page-container>
+  </page-auth>
+</template>

+ 107 - 0
src/views/time/receivableDetail/components/business.vue

@@ -0,0 +1,107 @@
+<script setup lang="ts">
+import { ref, watch ,shallowRef} from "vue";
+import apis from "./config/apis";
+import { ElMessage } from "element-plus";
+import { usePermission } from "/@/hooks/core";
+import { frontEndExport } from "/@/utils/export";
+import { isBeyondTime } from "/@/views/time/_utils";
+import sourceSearchConfig from "./config/search.config";
+import sourceContentConfig from "./config/content.config";
+import { usePageSearch, type PageHooks } from "/@/hooks/page";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
+import { PageContentInstance } from "/@/components/PageContent";
+import { useBusinessSearch, useBusinessContent } from "./../../_hooks";
+import { useUserStore } from "/@/store/modules/user";
+import { httpRequsetExport } from "/@/utils/export";
+
+const pageContentRef = ref<PageContentInstance | null>(null);
+const lockKey = "companyNo";
+
+const pageName = "reportDaily";
+const { hasPermissionWithCode } = usePermission(pageName);
+const loading = shallowRef(false);
+
+const userStore = useUserStore();
+const { searchConfig } = useBusinessSearch({
+  sourceConfig: sourceSearchConfig,
+  queryField: "companyNo"
+});
+
+const searchConfigRef = ref(searchConfig);
+
+const { contentConfig } = useBusinessContent({
+  sourceConfig: sourceContentConfig,
+  apis: { httpList: apis.list }
+});
+
+const hooks: PageHooks = {
+  pageSearchHook: () =>
+    usePageSearch(undefined, undefined, searchConfig, false, lockKey)
+};
+
+watch(
+  () => userStore.level,
+  level => {
+    const { formItems } = searchConfigRef.value;
+    const index = formItems.findIndex(({ field }) => field === "depart_id");
+    const { itemid = "" } = userStore.info || {};
+
+    if (Number(level) === 2) {
+      searchConfigRef.value.formItems[index].disabled = Number(level) === 2;
+      searchConfigRef.value.formItems[index].defaultValue = itemid;
+    }
+  },
+  {
+    immediate: true
+  }
+);
+
+const callback = {
+  onSuccess: () => (loading.value = false),
+  onStart: () => (loading.value = true),
+  onFail: () => (loading.value = false)
+};
+
+async function handleExportAllReport() {
+  const params = pageContentRef.value.getBasicParams() || {};
+  const { start, end } = params;
+
+  if (!params[lockKey]) {
+    ElMessage.warning("请选择业务公司");
+    return;
+  }
+
+  const beyondTime = isBeyondTime({ start, end, len: 30 });
+  if (beyondTime) return;
+
+  await httpRequsetExport({
+    fileType: "aplication/x-msexecl",
+    name: "应收账款明细.xlsx",
+    url: "report/dzListExport",
+    ...callback,
+    params
+  });
+}
+</script>
+
+<template>
+  <PageContainer
+    :hooks="hooks"
+    :getContentRef="ref => (pageContentRef = ref)"
+    :content-config="contentConfig"
+    :search-config="searchConfig"
+    lockKey="companyNo"
+    v-loading="loading"
+  >
+    <template #content_header>
+      <el-button
+        v-if="hasPermissionWithCode('18')"
+        :icon="useRenderIcon('arrow-up-line')"
+        @click="handleExportAllReport"
+        size="small"
+        type="primary"
+        >导出</el-button
+      >
+    </template>
+  </PageContainer>
+</template>

+ 8 - 0
src/views/time/receivableDetail/components/config/apis.ts

@@ -0,0 +1,8 @@
+import { createHttpRequest } from "/@/views/time/_http";
+
+const baseUrl = "admin/report/";
+
+export default {
+  list: createHttpRequest(`${baseUrl}dzList`),
+  export: createHttpRequest(`${baseUrl}dzListExport`)
+};

+ 176 - 0
src/views/time/receivableDetail/components/config/content.config.ts

@@ -0,0 +1,176 @@
+/* eslint-disable prettier/prettier */
+import { BeforeRequestType, ContentConfig } from "/@/components/PageContent";
+import apis from "./apis";
+import { isBeyondTime } from "/@/views/reportCollection/_utils";
+import { addition } from "/@/utils/calc";
+import { h } from "vue";
+import { ElTag } from "element-plus";
+
+const send_status_list = [
+  { value: "1", label: "未发货", type: "warning" },
+  { value: "2", label: "部分已发", type: "primary" },
+  { value: "3", label: "全部已发", type: "success" },
+  { value: "4", label: "发货完成", type: "warning" }
+];
+
+const inv_status_list = [
+  { value: "1", label: "未开票", type: "warning" },
+  { value: "2", label: "部分开票", type: "primary" },
+  { value: "3", label: "全部开票", type: "success" }
+];
+
+
+const pay_status_list = [
+  { value: "1", label: "未回款", type: "warning" },
+  { value: "2", label: "部分回款", type: "primary" },
+  { value: "3", label: "全部回款", type: "success" }
+];
+
+
+
+const columns = [
+  {
+    type: 'index',
+    label: '序号',
+    minWidth: '50px'
+  },
+  {
+    prop: 'sequenceNo',
+    label: '确认单编号',
+    minWidth: '155px'
+  },
+  {
+    prop: 'cxCode',
+    label: '销售订单主编号',
+    minWidth: '155px'
+  },
+
+  {
+    prop: 'createdTime',
+    label: '确认单下单时间',
+    minWidth: '155px'
+  },
+  {
+    prop: 'customerName',
+    label: '客户名称',
+    minWidth: '155px'
+  },
+  {
+    prop: 'department',
+    label: '业务员部门',
+    minWidth: '155px'
+  },
+  {
+    prop: 'ownerName',
+    label: '业务员',
+    width: '90px',
+  },
+  {
+    prop: 'goodName',
+    label: '产品名称',
+    width: '100px',
+  },
+  {
+    prop: 'goodNum',
+    label: '下单数量',
+    width: '100px',
+  },
+  {
+    prop: 'goodPrice',
+    label: '销售单价',
+    width: '100px',
+  },
+  {
+    prop: 'totalPrice',
+    label: '销售总额',
+    width: '100px',
+  },
+  {
+    prop: 'apay_fee',
+    label: '已回款',
+    width: '100px',
+  },
+  {
+    prop: 'wpay_fee',
+    label: '未回款',
+    width: '100px',
+  },
+  {
+    prop: 'ainv_fee',
+    label: '已开票',
+    width: '100px',
+  },
+  {
+    prop: 'winv_fee',
+    label: '未开票',
+    width: '100px',
+  },
+  {
+    prop: 'ainv_wpay',
+    label: '开票进行中',
+    width: '100px',
+  },
+  {
+    prop: 'inv_fee',
+    label: '已开票未回款',
+    width: '100px',
+  },
+  {
+    prop: 'pay_status',
+    label: "回款状态",
+    width: '100px',
+    cellRenderer({ row }) {
+      const item = pay_status_list.find(({ value }) => String(value) === String(row.pay_status))
+      return h(ElTag, {
+        type: item ? item.type : "danger",
+        size: 'small'
+      }, {
+        default: () => item ? item.label : "--"
+      })
+    }
+  },
+  {
+    prop: 'inv_status',
+    label: "开票状态",
+    width: '100px',
+    cellRenderer({ row }) {
+      const item = inv_status_list.find(({ value }) => String(value) === String(row.inv_status))
+      return h(ElTag, {
+        type: item ? item.type : "danger",
+        size: 'small'
+      }, {
+        default: () => item ? item.label : "--"
+      })
+    }
+  },
+  {
+    prop: 'sendStatus',
+    label: "发货状态",
+    width: '100px',
+    cellRenderer({ row }) {
+      const item = send_status_list.find(({ value }) => String(value) === String(row.sendStatus))
+      return h(ElTag, {
+        type: item ? item.type : "danger",
+        size: 'small'
+      }, {
+        default: () => item ? item.label : "--"
+      })
+    }
+  }
+];
+
+const contentConfig: ContentConfig = {
+  columns,
+  showTitle: false,
+  superUserNoAction: false,
+  responseCode: 0,
+  beforeRequestList(params) {
+    const { start, end } = params;
+    const beyondTime = isBeyondTime({ name: "下单时间", len: 30, start, end });
+    if (beyondTime) return BeforeRequestType.EMPTY
+    return BeforeRequestType.NEXT;
+  },
+  apis: { httpList: apis.list }
+};
+
+export default contentConfig;

+ 46 - 0
src/views/time/receivableDetail/components/config/search.config.ts

@@ -0,0 +1,46 @@
+import { FormConfig } from "/@/components/PageSearch";
+import { useUserStore } from "/@/store/modules/user";
+import dayjs from "dayjs";
+
+const now = new Date();
+const start = dayjs(now).subtract(30, 'days').format("YYYY-MM-DD");
+const end = dayjs(now).format('YYYY-MM-DD');
+
+const searchFormConfig: FormConfig = {
+  formItems: [
+    {
+      field: "date",
+      type: "date_picker",
+      trigger: "change",
+      defaultValue: [start, end],
+      otherOptions: {
+        type: "daterange",
+        startPlaceholder: "下单开始时间",
+        endPlaceholder: "下单结束时间",
+        valueFormat: "YYYY-MM-DD",
+        startProp: "start",
+        endProp: "end"
+      }
+    },
+    {
+      field: "depart_id",
+      type: "depart-query",
+      trigger: "change"
+    },
+    {
+      field: 'plat_type',
+      type: 'select',
+      trigger: 'change',
+      defaultValue: '1',
+      options: [
+        { value: '1', label: 'toB' },
+        { value: '2', label: 'toC' }
+      ],
+      otherOptions: {
+        clearable: false
+      }
+    }
+  ]
+};
+
+export default searchFormConfig;

+ 49 - 0
src/views/time/receivableDetail/index.vue

@@ -0,0 +1,49 @@
+<script setup lang="ts">
+import { shallowRef, onMounted } from "vue";
+import All from "./components/all.vue";
+import Business from "./components/business.vue";
+import { usePermission } from "/@/hooks/core";
+import NoAuth from "/@/components/NoAuth/NoAuth.vue";
+
+const actived = shallowRef("");
+
+const { hasPermissionWithCode } = usePermission("reportDaily");
+
+onMounted(() => {
+  if (hasPermissionWithCode("3")) {
+    actived.value = "3";
+  } else if (hasPermissionWithCode("11")) {
+    actived.value = "11";
+  }
+});
+</script>
+
+<template>
+  <div class="report-container">
+    <el-tabs v-model="actived" style="color: #fff" v-if="actived">
+      <el-tab-pane label="查看全部" name="3" v-if="hasPermissionWithCode('3')">
+        <all v-if="actived === '3'" />
+      </el-tab-pane>
+
+      <el-tab-pane
+        name="11"
+        label="查看业务公司"
+        v-if="hasPermissionWithCode('11')"
+      >
+        <business v-if="actived === '11'" />
+      </el-tab-pane>
+    </el-tabs>
+
+    <no-auth v-else />
+  </div>
+</template>
+
+<style scoped lang="scss">
+.report-container {
+  height: calc(100vh - 48px);
+  :deep(.el-tabs__header) {
+    background-color: #fff;
+    padding: 10px 10px 0;
+  }
+}
+</style>

+ 0 - 0
src/views/time/receivableDetail/应收装款明细


+ 54 - 0
src/views/time/receivableManager/components/all.vue

@@ -0,0 +1,54 @@
+<script setup lang="ts">
+import { ref } from "vue";
+import searchConfig from "./config/search.config";
+import contentConfig from "./config/content.config";
+
+import { PageContentInstance } from "/@/components/PageContent";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
+import { usePageSearch, type PageHooks } from "/@/hooks/page";
+import { isBeyondTime } from "/@/views/time/_utils";
+import { frontEndExport } from "/@/utils/export";
+import { usePermission } from "/@/hooks/core";
+
+const pageName = "receivableManager";
+const { hasPermissionWithCode } = usePermission(pageName);
+const pageContentRef = ref<PageContentInstance | null>(null);
+
+const hooks: PageHooks = {
+  pageSearchHook: () => {
+    return usePageSearch(undefined, undefined, searchConfig);
+  }
+};
+
+async function handleExportAllReport() {
+  const params = pageContentRef.value.getBasicParams() || {};
+  const { start, end } = params;
+  const beyondTime = isBeyondTime({ start, end, len: 30 });
+  if (beyondTime) return;
+  const data = pageContentRef.value.getData();
+  frontEndExport({ columns: contentConfig.columns, name: "项目经理日报.xlsx", data });
+}
+</script>
+
+<template>
+  <page-auth :page-name="pageName">
+    <page-container
+      :hooks="hooks"
+      :page-name="pageName"
+      :get-content-ref="ref => (pageContentRef = ref)"
+      :content-config="contentConfig"
+      :search-config="searchConfig"
+    >
+      <template #content_header>
+        <el-button
+          v-if="hasPermissionWithCode('9')"
+          @click="handleExportAllReport"
+          size="small"
+          :icon="useRenderIcon('arrow-up-line')"
+          type="primary"
+          >导出</el-button
+        >
+      </template>
+    </page-container>
+  </page-auth>
+</template>

+ 102 - 0
src/views/time/receivableManager/components/business.vue

@@ -0,0 +1,102 @@
+<script setup lang="ts">
+import { ref, watch } from "vue";
+import apis from "./config/apis";
+import { ElMessage } from "element-plus";
+import { usePermission } from "/@/hooks/core";
+import { frontEndExport } from "/@/utils/export";
+import { isBeyondTime } from "/@/views/time/_utils";
+import sourceSearchConfig from "./config/search.config";
+import sourceContentConfig from "./config/content.config";
+import { usePageSearch, type PageHooks } from "/@/hooks/page";
+import { useRenderIcon } from "/@/components/ReIcon/src/hooks";
+import { PageContentInstance } from "/@/components/PageContent";
+import { useBusinessSearch, useBusinessContent } from "./../../_hooks";
+import { useUserStore } from "/@/store/modules/user";
+
+const pageContentRef = ref<PageContentInstance | null>(null);
+const lockKey = "companyNo";
+
+const pageName = "receivableManager";
+const { hasPermissionWithCode } = usePermission(pageName);
+
+const userStore = useUserStore();
+const { searchConfig } = useBusinessSearch({
+  sourceConfig: sourceSearchConfig,
+  queryField: "companyNo"
+});
+
+const searchConfigRef = ref(searchConfig);
+
+const { contentConfig } = useBusinessContent({
+  sourceConfig: sourceContentConfig,
+  apis: { httpList: apis.list }
+});
+
+const hooks: PageHooks = {
+  pageSearchHook: () =>
+    usePageSearch(undefined, undefined, searchConfig, false, lockKey)
+};
+
+watch(
+  () => userStore.level,
+  level => {
+    const { formItems } = searchConfigRef.value;
+    const index = formItems.findIndex(({ field }) => field === "depart_id");
+    const { itemid = "" } = userStore.info || {};
+
+    if (Number(level) === 2) {
+      searchConfigRef.value.formItems[index].disabled = Number(level) === 2;
+      searchConfigRef.value.formItems[index].defaultValue = itemid;
+    }
+  },
+  {
+    immediate: true
+  }
+);
+
+async function handleExportAllReport() {
+  const params = pageContentRef.value.getBasicParams() || {};
+
+  const { start, end } = params;
+
+  if (!params[lockKey]) {
+    ElMessage.warning("请选择业务公司");
+    return;
+  }
+
+  const beyondTime = isBeyondTime({
+    end,
+    start,
+    len: 30
+  });
+
+  if (beyondTime) return;
+  const data = pageContentRef.value.getData();
+  frontEndExport({
+    columns: contentConfig.columns,
+    name: "项目经理日报.xlsx",
+    data
+  });
+}
+</script>
+
+<template>
+  <PageContainer
+    :hooks="hooks"
+    :getContentRef="ref => (pageContentRef = ref)"
+    :content-config="contentConfig"
+    :search-config="searchConfig"
+    lockKey="relaComNo"
+  >
+    <template #content_header>
+      <el-button
+        v-if="hasPermissionWithCode('18')"
+        :icon="useRenderIcon('arrow-up-line')"
+        @click="handleExportAllReport"
+        size="small"
+        type="primary"
+        >导出</el-button
+      >
+    </template>
+  </PageContainer>
+</template>

+ 9 - 0
src/views/time/receivableManager/components/config/apis.ts

@@ -0,0 +1,9 @@
+import { createHttpRequest } from "/@/views/time/_http";
+
+const baseUrl = "admin/report/";
+
+
+export default {
+  list: createHttpRequest(`${baseUrl}dzListByManager`),
+  businessList: createHttpRequest("")
+};

+ 95 - 0
src/views/time/receivableManager/components/config/content.config.ts

@@ -0,0 +1,95 @@
+/* eslint-disable prettier/prettier */
+import { BeforeRequestType, ContentConfig } from "/@/components/PageContent";
+import apis from "./apis";
+import { isBeyondTime } from "/@/views/reportCollection/_utils";
+import { addition } from "/@/utils/calc";
+
+const columns = [
+  {
+    prop: 'manager',
+    label: '项目经理',
+    minWidth: '155px'
+  },
+  {
+    prop: 'department',
+    label: '所在部门',
+    minWidth: '155px'
+  },
+  {
+    prop: 'orderNum',
+    label: '订单数量',
+    minWidth: '100px'
+  },
+
+  {
+    prop: 'totalPrice',
+    label: '销售金额',
+    minWidth: '100px'
+  },
+  {
+    prop: 'th_fee',
+    label: '退货金额',
+    minWidth: '100px'
+  },
+  {
+    prop: 'realTotal',
+    label: '实际金额',
+    minWidth: '100px'
+  },
+];
+
+const contentConfig: ContentConfig = {
+  columns,
+  showTitle: false,
+  responseCode: 0,
+  notPagination: true,
+  superUserNoAction: false,
+  beforeRequestList(params) {
+    const { start, end } = params;
+    const beyondTime = isBeyondTime({
+      name: "下单时间",
+      len: 30,
+      start,
+      end,
+    });
+
+    if (beyondTime) {
+      return BeforeRequestType.EMPTY
+    }
+    return BeforeRequestType.NEXT;
+  },
+  tableRowClassName({ rowIndex }) {
+    if (rowIndex === 0) {
+      return "warning-row"
+    }
+  },
+  handleData(list) {
+    const mapTotal: Record<string, string | number> = {
+      manager: '合计',
+      department: '--',
+      orderNum: 0,
+      totalPrice: 0,
+      th_fee: 0,
+      realTotal: 0,
+    }
+
+    list.forEach(item => {
+      const {
+        orderNum,
+        totalPrice,
+        th_fee,
+        realTotal,
+      } = item;
+
+      mapTotal.orderNum = Number(addition(mapTotal.orderNum, orderNum)).toFixed(0);
+      mapTotal.totalPrice = Number(addition(mapTotal.totalPrice, totalPrice)).toFixed(2);
+      mapTotal.th_fee = Number(addition(mapTotal.th_fee, th_fee)).toFixed(2);
+      mapTotal.realTotal = Number(addition(mapTotal.realTotal, realTotal)).toFixed(2);
+    });
+
+    return [mapTotal, ...list]
+  },
+  apis: { httpList: apis.list }
+};
+
+export default contentConfig;

+ 47 - 0
src/views/time/receivableManager/components/config/search.config.ts

@@ -0,0 +1,47 @@
+import { FormConfig } from "/@/components/PageSearch";
+import dayjs from "dayjs";
+import { useUserStore } from "/@/store/modules/user";
+
+const now = new Date();
+const start = dayjs(now).format("YYYY-MM-DD");
+
+const searchFormConfig: FormConfig = {
+  formItems: [
+    {
+      field: "date",
+      type: "date_picker",
+      defaultValue: [start, start],
+      trigger: "change",
+      otherOptions: {
+        type: "daterange",
+        startPlaceholder: "下单开始时间",
+        endPlaceholder: "下单结束时间",
+        valueFormat: "YYYY-MM-DD",
+        startProp: "start",
+        endProp: "end"
+      }
+    },
+    {
+      field: "depart_id",
+      type: "depart-query",
+      trigger: "change"
+      // disabled: Number(level) === 1,
+      // defaultValue: info.item || ""
+    },
+    {
+      field: 'plat_type',
+      type: 'select',
+      trigger: 'change',
+      defaultValue: '1',
+      options: [
+        { value: '1', label: 'toB' },
+        { value: '2', label: 'toC' }
+      ],
+      otherOptions: {
+        clearable: false
+      }
+    }
+  ]
+};
+
+export default searchFormConfig;

+ 49 - 0
src/views/time/receivableManager/index.vue

@@ -0,0 +1,49 @@
+<script setup lang="ts">
+import { shallowRef, onMounted } from "vue";
+import All from "./components/all.vue";
+import Business from "./components/business.vue";
+import { usePermission } from "/@/hooks/core";
+import NoAuth from "/@/components/NoAuth/NoAuth.vue";
+
+const actived = shallowRef("");
+
+const { hasPermissionWithCode } = usePermission("receivableManager");
+
+onMounted(() => {
+  if (hasPermissionWithCode("3")) {
+    actived.value = "3";
+  } else if (hasPermissionWithCode("11")) {
+    actived.value = "11";
+  }
+});
+</script>
+
+<template>
+  <div class="report-container">
+    <el-tabs v-model="actived" style="color: #fff" v-if="actived">
+      <el-tab-pane label="查看全部" name="3" v-if="hasPermissionWithCode('3')">
+        <all v-if="actived === '3'" />
+      </el-tab-pane>
+
+      <el-tab-pane
+        name="11"
+        label="查看业务公司"
+        v-if="hasPermissionWithCode('11')"
+      >
+        <business v-if="actived === '11'" />
+      </el-tab-pane>
+    </el-tabs>
+
+    <no-auth v-else />
+  </div>
+</template>
+
+<style scoped lang="scss">
+.report-container {
+  height: calc(100vh - 48px);
+  :deep(.el-tabs__header) {
+    background-color: #fff;
+    padding: 10px 10px 0;
+  }
+}
+</style>

+ 0 - 0
src/views/time/receivableManager/项目经理日报


+ 1 - 1
src/views/time/reportDaily/components/business.vue

@@ -16,7 +16,7 @@ import { useUserStore } from "/@/store/modules/user";
 const pageContentRef = ref<PageContentInstance | null>(null);
 const lockKey = "companyNo";
 
-const pageName = "reportDaily";
+const pageName = "receivableManager";
 const { hasPermissionWithCode } = usePermission(pageName);
 
 const userStore = useUserStore();

+ 1 - 1
src/views/time/reportDaily/index.vue

@@ -7,7 +7,7 @@ import NoAuth from "/@/components/NoAuth/NoAuth.vue";
 
 const actived = shallowRef("");
 
-const { hasPermissionWithCode } = usePermission("reportDaily");
+const { hasPermissionWithCode } = usePermission("receivableManager");
 
 onMounted(() => {
   if (hasPermissionWithCode("3")) {