Ver código fonte

oa部分功能完善

cz 11 meses atrás
pai
commit
64b1ad15b5

+ 30 - 0
src/router/index.js

@@ -661,6 +661,36 @@ const routes = [{
 				name: "开票申请",
 				component: () => import("../views/oa/invoicingApplication/index.vue"),
 			},
+			{
+				path: "personalInvoice",
+				name: "个人电子发票提交",
+				component: () => import("../views/oa/personalInvoice/index.vue"),
+			},
+			{
+				path: "invoiceTaxDeduction",
+				name: "电子发票抵税提交",
+				component: () => import("../views/oa/invoiceTaxDeduction/index.vue"),
+			},
+			{
+				path: "sealManage",
+				name: "印章管理",
+				component: () => import("../views/oa/sealManage/index.vue"),
+			},
+			{
+				path: "subsidyAmount",
+				name: "学历对应补贴金额",
+				component: () => import("../views/oa/subsidyAmount/index.vue"),
+			},
+			{
+				path: "processingBill",
+				name: "外包加工账单",
+				component: () => import("../views/oa/processingBill/index.vue"),
+			},
+			{
+				path: "processingBillAdd",
+				name: "外包加工账单明细",
+				component: () => import("../views/oa/processingBill/add.vue"),
+			},
 			// 
 
 		]

+ 179 - 0
src/views/oa/invoiceTaxDeduction/index.vue

@@ -0,0 +1,179 @@
+<template>
+  <van-nav-bar :title="'电子发票抵税提交'" left-text="" left-arrow @click-left="onClickLeft" @click-right="onClickRight">
+    <!-- <template #right>
+      {{ $t("common.add") }}
+    </template> -->
+  </van-nav-bar>
+  <van-search v-model="req.keyword" :placeholder="$t('common.pleaseEnterKeywords')" @search="onRefresh" />
+  <van-pull-refresh v-model="loading" @refresh="onRefresh">
+    <div class="list">
+      <van-list v-model:loading="loading" :finished="finished" :finished-text="$t('common.noMore')" @load="getList" style="margin-bottom: 60px">
+        <commonList :data="listData" @onClick="toDtl" :config="listConfig">
+
+          <template #useMethod="{row}">
+            <div style="width:100%">
+              {{dictKeyValue(row.useMethod,useMethodData)}}
+            </div>
+          </template>
+
+          <template #isContract="{row}">
+            <div style="width:100%">
+              {{dictKeyValue(row.isContract,sealIsContract)}}
+            </div>
+          </template>
+
+          <template #status="{row}">
+            <div style="width:100%">
+              {{dictValueLabel(row.status,statusData)}}
+            </div>
+          </template>
+
+        </commonList>
+      </van-list>
+    </div>
+  </van-pull-refresh>
+  <!-- <van-action-sheet v-model:show="actionType" :actions="actions" @select="onSelect" /> -->
+</template>
+<script setup>
+import { ref, getCurrentInstance } from "vue";
+import commonList from "@/components/common-list.vue";
+import { getAllDict } from "@/utils/auth";
+
+const proxy = getCurrentInstance().proxy;
+const sealIsContract = getAllDict()["seal_is_contract"];
+const onClickLeft = () => proxy.$router.push("/main/working");
+const onClickRight = () => {
+  proxy.$router.push({
+    path: "/main/processDtl",
+    query: {
+      flowKey: "contract_flow",
+    },
+  });
+};
+const actionType = ref(false);
+const actions = ref([
+  {
+    name: proxy.t("common.view"),
+    type: "1",
+  },
+  {
+    name: proxy.t("common.contractChange"),
+    type: "2",
+  },
+  {
+    name: proxy.t("common.cancel"),
+  },
+]);
+const req = ref({
+  pageNum: 1,
+  keyword: null,
+});
+const finished = ref(false);
+const onRefresh = () => {
+  req.value.pageNum = 1;
+  finished.value = false;
+  getList("refresh");
+};
+const loading = ref(false);
+const listData = ref([]);
+const getList = (type) => {
+  loading.value = true;
+  proxy
+    .post("/invoiceTaxDeduction/page", req.value)
+    .then((res) => {
+      listData.value =
+        type === "refresh"
+          ? res.data.rows
+          : listData.value.concat(res.data.rows);
+      if (req.value.pageNum * 10 >= res.data.total) {
+        finished.value = true;
+      }
+      req.value.pageNum++;
+      loading.value = false;
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+let rowData = ref({});
+
+const toDtl = (row) => {
+  proxy.$router.push({
+    path: "/main/processDtl",
+    query: {
+      flowKey: "invoice_tax_deduction_flow",
+      id: row.flowId,
+      processType: 20,
+      businessId: row.id,
+    },
+  });
+};
+
+const useMethodData = ref([
+  {
+    dictValue: "借章",
+    dictKey: "1",
+  },
+  {
+    dictValue: "盖章",
+    dictKey: "2",
+  },
+]);
+
+const statusData = ref([
+  {
+    label: "草稿",
+    value: 0,
+  },
+  {
+    label: "审批中",
+    value: 10,
+  },
+  {
+    label: "审批驳回",
+    value: 20,
+  },
+  {
+    label: "审批通过",
+    value: 30,
+  },
+  {
+    label: "作废",
+    value: 88,
+  },
+]);
+
+const listConfig = ref([
+  {
+    label: "流水号",
+    prop: "code",
+  },
+  {
+    label: "提交人",
+    prop: "createUserName",
+  },
+  {
+    label: "提交日期",
+    prop: "applyTime",
+  },
+  {
+    label: "抵扣金额",
+    prop: "amount",
+  },
+  {
+    label: "抵扣工资月份",
+    prop: "deductionSalaryMonth",
+  },
+  {
+    type: "slot",
+    label: "审批状态",
+    slotName: "status",
+  },
+]);
+</script>
+
+<style lang="scss" scoped>
+.list {
+  min-height: 70vh;
+}
+</style>

+ 179 - 0
src/views/oa/personalInvoice/index.vue

@@ -0,0 +1,179 @@
+<template>
+  <van-nav-bar :title="'个人电子发票提交'" left-text="" left-arrow @click-left="onClickLeft" @click-right="onClickRight">
+    <!-- <template #right>
+      {{ $t("common.add") }}
+    </template> -->
+  </van-nav-bar>
+  <van-search v-model="req.keyword" :placeholder="$t('common.pleaseEnterKeywords')" @search="onRefresh" />
+  <van-pull-refresh v-model="loading" @refresh="onRefresh">
+    <div class="list">
+      <van-list v-model:loading="loading" :finished="finished" :finished-text="$t('common.noMore')" @load="getList" style="margin-bottom: 60px">
+        <commonList :data="listData" @onClick="toDtl" :config="listConfig">
+
+          <template #useMethod="{row}">
+            <div style="width:100%">
+              {{dictKeyValue(row.useMethod,useMethodData)}}
+            </div>
+          </template>
+
+          <template #isContract="{row}">
+            <div style="width:100%">
+              {{dictKeyValue(row.isContract,sealIsContract)}}
+            </div>
+          </template>
+
+          <template #status="{row}">
+            <div style="width:100%">
+              {{dictValueLabel(row.status,statusData)}}
+            </div>
+          </template>
+
+        </commonList>
+      </van-list>
+    </div>
+  </van-pull-refresh>
+  <!-- <van-action-sheet v-model:show="actionType" :actions="actions" @select="onSelect" /> -->
+</template>
+<script setup>
+import { ref, getCurrentInstance } from "vue";
+import commonList from "@/components/common-list.vue";
+import { getAllDict } from "@/utils/auth";
+
+const proxy = getCurrentInstance().proxy;
+const sealIsContract = getAllDict()["seal_is_contract"];
+const onClickLeft = () => proxy.$router.push("/main/working");
+const onClickRight = () => {
+  proxy.$router.push({
+    path: "/main/processDtl",
+    query: {
+      flowKey: "contract_flow",
+    },
+  });
+};
+const actionType = ref(false);
+const actions = ref([
+  {
+    name: proxy.t("common.view"),
+    type: "1",
+  },
+  {
+    name: proxy.t("common.contractChange"),
+    type: "2",
+  },
+  {
+    name: proxy.t("common.cancel"),
+  },
+]);
+const req = ref({
+  pageNum: 1,
+  keyword: null,
+});
+const finished = ref(false);
+const onRefresh = () => {
+  req.value.pageNum = 1;
+  finished.value = false;
+  getList("refresh");
+};
+const loading = ref(false);
+const listData = ref([]);
+const getList = (type) => {
+  loading.value = true;
+  proxy
+    .post("/personalInvoice/page", req.value)
+    .then((res) => {
+      listData.value =
+        type === "refresh"
+          ? res.data.rows
+          : listData.value.concat(res.data.rows);
+      if (req.value.pageNum * 10 >= res.data.total) {
+        finished.value = true;
+      }
+      req.value.pageNum++;
+      loading.value = false;
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+let rowData = ref({});
+
+const toDtl = (row) => {
+  proxy.$router.push({
+    path: "/main/processDtl",
+    query: {
+      flowKey: "personal_invoice_flow",
+      id: row.flowId,
+      processType: 20,
+      businessId: row.id,
+    },
+  });
+};
+
+const useMethodData = ref([
+  {
+    dictValue: "借章",
+    dictKey: "1",
+  },
+  {
+    dictValue: "盖章",
+    dictKey: "2",
+  },
+]);
+
+const statusData = ref([
+  {
+    label: "草稿",
+    value: 0,
+  },
+  {
+    label: "审批中",
+    value: 10,
+  },
+  {
+    label: "审批驳回",
+    value: 20,
+  },
+  {
+    label: "审批通过",
+    value: 30,
+  },
+  {
+    label: "作废",
+    value: 88,
+  },
+]);
+
+const listConfig = ref([
+  {
+    label: "流水号",
+    prop: "code",
+  },
+  {
+    label: "提交人",
+    prop: "createUserName",
+  },
+  {
+    label: "提交日期",
+    prop: "applyTime",
+  },
+  {
+    label: "发票金额",
+    prop: "amount",
+  },
+  {
+    label: "摘要",
+    prop: "remark",
+  },
+  {
+    type: "slot",
+    label: "审批状态",
+    slotName: "status",
+  },
+]);
+</script>
+
+<style lang="scss" scoped>
+.list {
+  min-height: 70vh;
+}
+</style>

+ 298 - 0
src/views/oa/processingBill/add.vue

@@ -0,0 +1,298 @@
+<template>
+  <div class="form">
+    <van-nav-bar :title="$t('claim.name')" :left-text="$t('common.back')" left-arrow @click-left="onClickLeft">
+    </van-nav-bar>
+    <testForm v-model="formData.data" :formOption="formOption" :formConfig="formConfig" :rules="rules" @onSubmit="onSubmit" ref="formDom">
+      <template #file>
+        <div style="width:100%">
+          <div v-for="file in formData.data.fileList" :key="file.id" style="color: #409eff;cursor: pointer;"
+               @click="onPreviewFile(file.fileName,file.fileUrl)">
+            {{file.fileName}}
+          </div>
+        </div>
+      </template>
+    </testForm>
+  </div>
+</template>
+
+<script setup>
+import { ref, reactive, getCurrentInstance, onMounted, computed } from "vue";
+import { showSuccessToast, showFailToast } from "vant";
+import { useRoute } from "vue-router";
+import testForm from "@/components/testForm/index.vue";
+const proxy = getCurrentInstance().proxy;
+const route = useRoute();
+const contractorData = ref([]);
+const formDom = ref(null);
+const formData = reactive({
+  data: {},
+});
+const rules = {
+  contractId: [
+    {
+      required: true,
+      message: proxy.t("claim.contractCanNotBeEmpty"),
+    },
+  ],
+  money: [
+    {
+      required: true,
+      message: proxy.t("claim.relatedAmountCanNotBeEmpty"),
+    },
+  ],
+};
+const formOption = reactive({
+  readonly: false, //用于控制整个表单是否只读
+  disabled: false,
+  labelAlign: "top",
+  scroll: true,
+  labelWidth: "62pk",
+  submitBtnText: proxy.t("common.submit"),
+  hiddenSubmitBtn: false,
+  btnConfig: {
+    isNeed: true,
+    listTitle: proxy.t("claim.relatedContract"),
+    prop: "claimContractList",
+    plain: true,
+    listConfig: [
+      {
+        type: "input",
+        itemType: "text",
+        label: "认领时间",
+        prop: "createTime",
+      },
+      {
+        type: "input",
+        itemType: "text",
+        label: "认领人",
+        prop: "claimUserName",
+      },
+      {
+        type: "picker",
+        label: proxy.t("claim.contractCode"),
+        prop: "contractId",
+        itemType: "onePicker",
+        showPicker: false,
+        readonly: false,
+        fieldNames: {
+          text: "code",
+          value: "id",
+        },
+        data: [],
+      },
+      {
+        type: "input",
+        itemType: "number",
+        label: "认领金额",
+        prop: "money",
+      },
+    ],
+    clickFn: () => {
+      if (
+        formData.data.claimContractList &&
+        formData.data.claimContractList.length > 0
+      ) {
+        formData.data.claimContractList.push({
+          contractId: "",
+          contractCode: "",
+          money: "",
+        });
+      } else {
+        formData.data.claimContractList = [
+          {
+            contractId: "",
+            contractCode: "",
+            money: "",
+          },
+        ];
+      }
+    },
+  },
+});
+const formConfig = computed(() => [
+  {
+    type: "title",
+    title: "基本信息",
+  },
+  {
+    type: "input",
+    label: "提交时间",
+    prop: "applyTime",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "提交人",
+    prop: "createUserName",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "所属公司",
+    prop: "companyName",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "所属部门",
+    prop: "deptName",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "picker",
+    label: "承包单位",
+    prop: "contractorId",
+    itemType: "onePicker",
+    showPicker: false,
+    fieldNames: {
+      text: "label",
+      value: "value",
+    },
+    data: contractorData.value,
+    readonly: false,
+  },
+  {
+    type: "input",
+    label: "账期",
+    prop: "accountPeriod",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "账期金额",
+    prop: "accountPeriodAmount",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "预付金额",
+    prop: "prepaidAmount",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "最终金额",
+    prop: "finalAmount",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "说明",
+    prop: "remark",
+    itemType: "textarea",
+    readonly: true,
+  },
+  {
+    type: "slot",
+    label: "账单附件",
+    slotName: "file",
+  },
+]);
+const onClickLeft = () => history.back();
+const getDict = () => {
+  proxy
+    .post("/contractor/page", {
+      pageNum: 1,
+      pageSize: 9999,
+    })
+    .then((res) => {
+      contractorData.value = res.data.rows.map((item) => {
+        return {
+          label: item.name,
+          value: item.id,
+        };
+      });
+    });
+};
+onMounted(() => {
+  getDict();
+  formOption.btnConfig.isNeed = false;
+  formOption.readonly = true;
+  formOption.hiddenSubmitBtn = true;
+  proxy.post("/epibolyBill/detail", { id: route.query.id }).then(
+    (res) => {
+      formData.data = res.data;
+      let businessId = route.query.id;
+      proxy
+        .post("/fileInfo/getList", { businessIdList: [businessId] })
+        .then((res) => {
+          let fileObj = res.data;
+          if (fileObj[businessId] && fileObj[businessId].length > 0) {
+            formData.data.fileList = fileObj[businessId]
+              .filter((x) => x.businessType == "0")
+              .map((item) => {
+                return {
+                  ...item,
+                  name: item.fileName,
+                  url: item.fileUrl,
+                };
+              });
+          } else {
+            formData.data.fileList = [];
+          }
+        });
+    },
+    (err) => {
+      return showFailToast(err.message);
+    }
+  );
+});
+
+const onSubmit = () => {
+  if (route.query.isClaim != "1") {
+    if (formData.data.claimContractList.length > 0) {
+      let list = formData.data.claimContractList;
+      for (let i = 0; i < list.length; i++) {
+        const e = list[i];
+        if (!(Number(e.money) > 0)) {
+          return showFailToast(
+            proxy.t("claim.relatedAmountMustBeGreaterThanZero")
+          );
+        }
+      }
+      const total = list.reduce((total, x) => (total += Number(x.money)), 0);
+      if (total > Number(formData.data.waitAmount)) {
+        return showFailToast(
+          proxy.t("claim.relatedAmountTotalNotBeGreaterThanAccountAmount")
+        );
+      }
+      formData.data.amount = total;
+      proxy.post("/claim/add", formData.data).then(
+        () => {
+          showSuccessToast(proxy.t("common.operationSuccessful"));
+          setTimeout(() => {
+            onClickLeft();
+          }, 500);
+        },
+        (err) => {
+          return showFailToast(err.message);
+        }
+      );
+    } else {
+      return showFailToast(proxy.t("claim.addDetails"));
+    }
+  } else {
+    proxy.post("/claim/delete", { id: route.query.id }).then(
+      () => {
+        showSuccessToast(proxy.t("common.operationSuccessful"));
+        setTimeout(() => {
+          onClickLeft();
+        }, 500);
+      },
+      (err) => {
+        return showFailToast(err.message);
+      }
+    );
+  }
+};
+</script>
+<style lang="scss" scoped>
+</style>

+ 95 - 0
src/views/oa/processingBill/index.vue

@@ -0,0 +1,95 @@
+<template>
+  <van-nav-bar :title="'外包加工账单'" left-text="" left-arrow @click-left="onClickLeft">
+  </van-nav-bar>
+  <van-search v-model="req.keyword" :placeholder="$t('common.pleaseEnterKeywords')" @search="onRefresh" />
+  <van-pull-refresh v-model="loading" @refresh="onRefresh">
+    <div class="list">
+      <van-list v-model:loading="loading" :finished="finished" :finished-text="$t('common.noMore')" @load="getList" style="margin-bottom: 60px">
+        <commonList :data="listData" @onClick="toDtl" :config="listConfig"></commonList>
+      </van-list>
+    </div>
+  </van-pull-refresh>
+</template>
+<script setup>
+import { ref, getCurrentInstance } from "vue";
+import commonList from "@/components/common-list.vue";
+
+const proxy = getCurrentInstance().proxy;
+const onClickLeft = () => proxy.$router.push("/main/working");
+const req = ref({
+  pageNum: 1,
+  keyword: null,
+  dataType: "1",
+});
+const finished = ref(false);
+const onRefresh = () => {
+  req.value.pageNum = 1;
+  finished.value = false;
+  getList("refresh");
+};
+const loading = ref(false);
+const listData = ref([]);
+const getList = (type) => {
+  loading.value = true;
+  proxy
+    .post("/epibolyBill/page", req.value)
+    .then((res) => {
+      listData.value =
+        type === "refresh"
+          ? res.data.rows
+          : listData.value.concat(res.data.rows);
+      if (req.value.pageNum * 10 >= res.data.total) {
+        finished.value = true;
+      }
+      req.value.pageNum++;
+      loading.value = false;
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+const toDtl = (row) => {
+  proxy.$router.push({
+    path: "/main/processingBillAdd",
+    query: {
+      id: row.id,
+    },
+  });
+};
+const listConfig = ref([
+  {
+    label: "提交人",
+    prop: "createUserName",
+  },
+  {
+    label: "提交日期",
+    prop: "applyTime",
+  },
+  {
+    label: "承包单位",
+    prop: "contractorName",
+  },
+  {
+    label: "账期",
+    prop: "accountPeriod",
+  },
+  {
+    label: "账期金额",
+    prop: "accountPeriodAmount",
+  },
+  {
+    label: "预付金额",
+    prop: "prepaidAmount",
+  },
+  {
+    label: "最终金额",
+    prop: "finalAmount",
+  },
+]);
+</script>
+
+<style lang="scss" scoped>
+.list {
+  min-height: 70vh;
+}
+</style>

+ 163 - 0
src/views/oa/sealManage/index.vue

@@ -0,0 +1,163 @@
+<template>
+  <van-nav-bar :title="'印章管理'" left-text="" left-arrow @click-left="onClickLeft" @click-right="onClickRight">
+    <!-- <template #right>
+      {{ $t("common.add") }}
+    </template> -->
+  </van-nav-bar>
+  <van-search v-model="req.keyword" :placeholder="$t('common.pleaseEnterKeywords')" @search="onRefresh" />
+  <van-pull-refresh v-model="loading" @refresh="onRefresh">
+    <div class="list">
+      <van-list v-model:loading="loading" :finished="finished" :finished-text="$t('common.noMore')" @load="getList" style="margin-bottom: 60px">
+        <commonList :data="listData" :config="listConfig" :showMore="false">
+
+          <template #type="{row}">
+            <div style="width:100%">
+              {{dictKeyValue(row.type,sealType)}}
+            </div>
+          </template>
+
+        </commonList>
+      </van-list>
+    </div>
+  </van-pull-refresh>
+  <!-- <van-action-sheet v-model:show="actionType" :actions="actions" @select="onSelect" /> -->
+</template>
+<script setup>
+import { ref, getCurrentInstance } from "vue";
+import commonList from "@/components/common-list.vue";
+import { getAllDict } from "@/utils/auth";
+
+const proxy = getCurrentInstance().proxy;
+const sealType = getAllDict()["seal_type"];
+const onClickLeft = () => proxy.$router.push("/main/working");
+const onClickRight = () => {
+  proxy.$router.push({
+    path: "/main/processDtl",
+    query: {
+      flowKey: "contract_flow",
+    },
+  });
+};
+const actionType = ref(false);
+const actions = ref([
+  {
+    name: proxy.t("common.view"),
+    type: "1",
+  },
+  {
+    name: proxy.t("common.contractChange"),
+    type: "2",
+  },
+  {
+    name: proxy.t("common.cancel"),
+  },
+]);
+const req = ref({
+  pageNum: 1,
+  keyword: null,
+});
+const finished = ref(false);
+const onRefresh = () => {
+  req.value.pageNum = 1;
+  finished.value = false;
+  getList("refresh");
+};
+const loading = ref(false);
+const listData = ref([]);
+const getList = (type) => {
+  loading.value = true;
+  proxy
+    .post("/sealConfig/page", req.value)
+    .then((res) => {
+      listData.value =
+        type === "refresh"
+          ? res.data.rows
+          : listData.value.concat(res.data.rows);
+      if (req.value.pageNum * 10 >= res.data.total) {
+        finished.value = true;
+      }
+      req.value.pageNum++;
+      loading.value = false;
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+let rowData = ref({});
+
+const toDtl = (row) => {
+  proxy.$router.push({
+    path: "/main/processDtl",
+    query: {
+      flowKey: "seal_use_flow",
+      id: row.flowId,
+      processType: 20,
+      businessId: row.id,
+    },
+  });
+};
+
+const useMethodData = ref([
+  {
+    dictValue: "借章",
+    dictKey: "1",
+  },
+  {
+    dictValue: "盖章",
+    dictKey: "2",
+  },
+]);
+
+const statusData = ref([
+  {
+    label: "草稿",
+    value: 0,
+  },
+  {
+    label: "审批中",
+    value: 10,
+  },
+  {
+    label: "审批驳回",
+    value: 20,
+  },
+  {
+    label: "审批通过",
+    value: 30,
+  },
+  {
+    label: "作废",
+    value: 88,
+  },
+]);
+
+const listConfig = ref([
+  {
+    label: "印章名称",
+    prop: "name",
+  },
+  {
+    type: "slot",
+    label: "印章类型",
+    slotName: "type",
+  },
+  {
+    label: "存管人员",
+    prop: "custodyUserName",
+  },
+  {
+    label: "存管部门",
+    prop: "custodyDeptName",
+  },
+  {
+    label: "印章用途",
+    prop: "remark",
+  },
+]);
+</script>
+
+<style lang="scss" scoped>
+.list {
+  min-height: 70vh;
+}
+</style>

+ 162 - 0
src/views/oa/subsidyAmount/index.vue

@@ -0,0 +1,162 @@
+<template>
+  <van-nav-bar :title="'学历对应补贴金额'" left-text="" left-arrow @click-left="onClickLeft" @click-right="onClickRight">
+    <!-- <template #right>
+      {{ $t("common.add") }}
+    </template> -->
+  </van-nav-bar>
+  <van-search v-model="req.keyword" :placeholder="$t('common.pleaseEnterKeywords')" @search="onRefresh" />
+  <van-pull-refresh v-model="loading" @refresh="onRefresh">
+    <div class="list">
+      <van-list v-model:loading="loading" :finished="finished" :finished-text="$t('common.noMore')" @load="getList" style="margin-bottom: 60px">
+        <commonList :data="listData" :config="listConfig" :showMore="false">
+          <!-- @onClick="toDtl" -->
+          <template #useMethod="{row}">
+            <div style="width:100%">
+              {{dictKeyValue(row.useMethod,useMethodData)}}
+            </div>
+          </template>
+
+          <template #isContract="{row}">
+            <div style="width:100%">
+              {{dictKeyValue(row.isContract,sealIsContract)}}
+            </div>
+          </template>
+
+          <template #status="{row}">
+            <div style="width:100%">
+              {{dictValueLabel(row.status,statusData)}}
+            </div>
+          </template>
+
+        </commonList>
+      </van-list>
+    </div>
+  </van-pull-refresh>
+  <!-- <van-action-sheet v-model:show="actionType" :actions="actions" @select="onSelect" /> -->
+</template>
+<script setup>
+import { ref, getCurrentInstance } from "vue";
+import commonList from "@/components/common-list.vue";
+import { getAllDict } from "@/utils/auth";
+
+const proxy = getCurrentInstance().proxy;
+const sealIsContract = getAllDict()["seal_is_contract"];
+const onClickLeft = () => proxy.$router.push("/main/working");
+const onClickRight = () => {
+  proxy.$router.push({
+    path: "/main/processDtl",
+    query: {
+      flowKey: "contract_flow",
+    },
+  });
+};
+const actionType = ref(false);
+const actions = ref([
+  {
+    name: proxy.t("common.view"),
+    type: "1",
+  },
+  {
+    name: proxy.t("common.contractChange"),
+    type: "2",
+  },
+  {
+    name: proxy.t("common.cancel"),
+  },
+]);
+const req = ref({
+  pageNum: 1,
+  keyword: null,
+});
+const finished = ref(false);
+const onRefresh = () => {
+  req.value.pageNum = 1;
+  finished.value = false;
+  getList("refresh");
+};
+const loading = ref(false);
+const listData = ref([]);
+const getList = (type) => {
+  loading.value = true;
+  proxy
+    .post("/educationConfig/page", req.value)
+    .then((res) => {
+      listData.value =
+        type === "refresh"
+          ? res.data.rows
+          : listData.value.concat(res.data.rows);
+      if (req.value.pageNum * 10 >= res.data.total) {
+        finished.value = true;
+      }
+      req.value.pageNum++;
+      loading.value = false;
+    })
+    .catch(() => {
+      loading.value = false;
+    });
+};
+let rowData = ref({});
+
+const toDtl = (row) => {
+  proxy.$router.push({
+    path: "/main/processDtl",
+    query: {
+      flowKey: "seal_use_flow",
+      id: row.flowId,
+      processType: 20,
+      businessId: row.id,
+    },
+  });
+};
+
+const useMethodData = ref([
+  {
+    dictValue: "借章",
+    dictKey: "1",
+  },
+  {
+    dictValue: "盖章",
+    dictKey: "2",
+  },
+]);
+
+const statusData = ref([
+  {
+    label: "草稿",
+    value: 0,
+  },
+  {
+    label: "审批中",
+    value: 10,
+  },
+  {
+    label: "审批驳回",
+    value: 20,
+  },
+  {
+    label: "审批通过",
+    value: 30,
+  },
+  {
+    label: "作废",
+    value: 88,
+  },
+]);
+
+const listConfig = ref([
+  {
+    label: "学历名称",
+    prop: "name",
+  },
+  {
+    label: "学历补贴金额",
+    prop: "amount",
+  },
+]);
+</script>
+
+<style lang="scss" scoped>
+.list {
+  min-height: 70vh;
+}
+</style>

+ 1 - 1
src/views/processApproval/components/EncodingCombination.vue

@@ -96,7 +96,7 @@ const formConfig = reactive([
     type: "input",
     label: "描述商品编码组合",
     prop: "remark",
-    itemType: "text",
+    itemType: "textarea",
     readonly: true,
   },
 

+ 219 - 0
src/views/processApproval/components/InvoiceTaxDeduction.vue

@@ -0,0 +1,219 @@
+<template>
+  <div class="form">
+    <testForm v-model="formData.data" :formOption="formOption" :formConfig="formConfig" :rules="rules" ref="formDom">
+      <template #detail>
+        <div style="width:100%">
+          <div style="width:100%;overflow-x:auto;">
+            <table border class="table">
+              <thead>
+                <tr>
+                  <th style="min-width:130px;">发票附件(电子发票需上传PDF或OFD格式)</th>
+                  <th style="min-width:50px">金额</th>
+                </tr>
+              </thead>
+              <tbody v-if="formData.data.invoiceTaxDeductionDetailsList && formData.data.invoiceTaxDeductionDetailsList.length>0">
+                <tr v-for="(item,index) in formData.data.invoiceTaxDeductionDetailsList" :key="index">
+                  <td>
+                    <div v-for="file in item.fileList" :key="file.id" style="color: #409eff;cursor: pointer;"
+                         @click="onPreviewFile(file.fileName,file.fileUrl)">
+                      {{file.fileName}}
+                    </div>
+                  </td>
+                  <td>{{item.amount}}</td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </div>
+      </template>
+    </testForm>
+  </div>
+</template>
+
+<script setup>
+import {
+  ref,
+  getCurrentInstance,
+  onMounted,
+  defineProps,
+  defineExpose,
+  watch,
+  reactive,
+  toRefs,
+} from "vue";
+import { useRoute } from "vue-router";
+import testForm from "@/components/testForm/index.vue";
+import { getUserInfo } from "@/utils/auth";
+import { showFailToast } from "vant";
+// 接收父组件的传值
+const props = defineProps({
+  queryData: Object,
+});
+const refProps = toRefs(props);
+const proxy = getCurrentInstance().proxy;
+const route = useRoute();
+const active = ref(0);
+const tabsChange = () => {
+  active.value++;
+};
+const selectData = ref([]);
+const formData = reactive({
+  data: {},
+});
+const formDom = ref(null);
+const formOption = reactive({
+  readonly: false,
+  disabled: false,
+  labelAlign: "top",
+  scroll: true,
+  labelWidth: "62pk",
+  hiddenSubmitBtn: true,
+});
+const formConfig = reactive([
+  {
+    type: "title",
+    title: "基本信息",
+  },
+  {
+    type: "input",
+    label: "流水号",
+    prop: "code",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "提交日期",
+    prop: "applyTime",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "提交人",
+    prop: "createUserName",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "抵扣金额汇总",
+    prop: "amount",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "抵扣工资月份",
+    prop: "deductionSalaryMonth",
+    itemType: "text",
+    readonly: true,
+  },
+
+  {
+    type: "slot",
+    label: "抵扣明细",
+    slotName: "detail",
+  },
+]);
+
+const rules = {};
+
+const getDict = () => {
+  proxy
+    .post("/educationConfig/page", {
+      pageNum: 1,
+      pageSize: 999,
+    })
+    .then((res) => {
+      selectData.value = res.data.rows.map((x) => ({
+        ...x,
+        label: x.name,
+        value: x.id,
+      }));
+    });
+};
+// getDict();
+
+const status = ref(true);
+const handleSubmit = async () => {
+  if (status.value) {
+    return formData.data;
+  }
+};
+
+onMounted(() => {
+  if (route.query && route.query.businessId) {
+    formOption.readonly = true;
+    formOption.hiddenSubmitBtn = true;
+    let businessId = route.query.businessId;
+    proxy
+      .post("/invoiceTaxDeduction/detail", { id: businessId })
+      .then((res) => {
+        formData.data = res.data;
+        let ids = formData.data.invoiceTaxDeductionDetailsList.map((x) => x.id);
+        proxy.post("/fileInfo/getList", { businessIdList: ids }).then((res) => {
+          let fileObj = res.data;
+          if (Object.keys(fileObj).length > 0) {
+            for (
+              let i = 0;
+              i < formData.data.invoiceTaxDeductionDetailsList.length;
+              i++
+            ) {
+              const row = formData.data.invoiceTaxDeductionDetailsList[i];
+              for (const key in fileObj) {
+                if (row.id == key) {
+                  row.fileList = fileObj[key].map((item) => {
+                    return {
+                      ...item,
+                      name: item.fileName,
+                      url: item.fileUrl,
+                    };
+                  });
+                  break;
+                }
+              }
+            }
+          }
+        });
+      });
+  }
+});
+
+defineExpose({
+  handleSubmit,
+  tabsChange,
+});
+onMounted(() => {});
+</script>
+<style lang="scss" scoped>
+._title {
+  display: flex;
+  align-items: center;
+  font-size: 14px;
+  font-weight: 700;
+  margin-left: -10px;
+  .line {
+    width: 4px;
+    background-color: #0084ff;
+    height: 15px;
+    margin-right: 8px;
+  }
+}
+
+.table {
+  border-collapse: collapse;
+  border-spacing: 0;
+  width: 100%;
+  border-color: #ebeef5;
+  color: #606266;
+  thead tr th {
+    padding: 6px;
+    text-align: left;
+  }
+  td {
+    text-align: left;
+    padding: 6px;
+  }
+}
+</style>

+ 1 - 1
src/views/processApproval/components/MedicalAndsocialSecurity.vue

@@ -131,7 +131,7 @@ const formConfig = reactive([
     type: "input",
     label: "备注栏",
     prop: "remark",
-    itemType: "text",
+    itemType: "textarea",
     readonly: true,
   },
 

+ 170 - 0
src/views/processApproval/components/PersonalInvoice.vue

@@ -0,0 +1,170 @@
+<template>
+  <div class="form">
+    <testForm v-model="formData.data" :formOption="formOption" :formConfig="formConfig" :rules="rules" ref="formDom">
+      <template #file>
+        <div style="width:100%">
+          <div v-for="file in formData.data.fileList" :key="file.id" style="color: #409eff;cursor: pointer;"
+               @click="onPreviewFile(file.fileName,file.fileUrl)">
+            {{file.fileName}}
+          </div>
+        </div>
+      </template>
+    </testForm>
+  </div>
+</template>
+
+<script setup>
+import {
+  ref,
+  getCurrentInstance,
+  onMounted,
+  defineProps,
+  defineExpose,
+  watch,
+  reactive,
+  toRefs,
+} from "vue";
+import { useRoute } from "vue-router";
+import testForm from "@/components/testForm/index.vue";
+import { getUserInfo } from "@/utils/auth";
+import { showFailToast } from "vant";
+// 接收父组件的传值
+const props = defineProps({
+  queryData: Object,
+});
+const refProps = toRefs(props);
+const proxy = getCurrentInstance().proxy;
+const route = useRoute();
+const active = ref(0);
+const tabsChange = () => {
+  active.value++;
+};
+const selectData = ref([]);
+const formData = reactive({
+  data: {},
+});
+const formDom = ref(null);
+const formOption = reactive({
+  readonly: false,
+  disabled: false,
+  labelAlign: "top",
+  scroll: true,
+  labelWidth: "62pk",
+  hiddenSubmitBtn: true,
+});
+const formConfig = reactive([
+  {
+    type: "title",
+    title: "基本信息",
+  },
+  {
+    type: "input",
+    label: "流水号",
+    prop: "code",
+    itemType: "text",
+    readonly: true,
+  },
+
+  {
+    type: "input",
+    label: "提交人",
+    prop: "createUserName",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "input",
+    label: "发票金额",
+    prop: "amount",
+    itemType: "text",
+    readonly: true,
+  },
+  {
+    type: "slot",
+    label: "发票附件",
+    slotName: "file",
+  },
+  {
+    type: "input",
+    label: "摘要",
+    prop: "remark",
+    itemType: "textarea",
+    readonly: true,
+  },
+]);
+
+const rules = {};
+
+const getDict = () => {
+  proxy
+    .post("/educationConfig/page", {
+      pageNum: 1,
+      pageSize: 999,
+    })
+    .then((res) => {
+      selectData.value = res.data.rows.map((x) => ({
+        ...x,
+        label: x.name,
+        value: x.id,
+      }));
+    });
+};
+// getDict();
+
+const status = ref(true);
+const handleSubmit = async () => {
+  if (status.value) {
+    return formData.data;
+  }
+};
+
+onMounted(() => {
+  if (route.query && route.query.businessId) {
+    formOption.readonly = true;
+    formOption.hiddenSubmitBtn = true;
+    let businessId = route.query.businessId;
+    proxy.post("/personalInvoice/detail", { id: businessId }).then((res) => {
+      formData.data = res.data;
+      proxy
+        .post("/fileInfo/getList", { businessIdList: [businessId] })
+        .then((res) => {
+          let fileObj = res.data;
+          if (fileObj[businessId] && fileObj[businessId].length > 0) {
+            formData.data.fileList = fileObj[businessId]
+              .filter((x) => x.businessType == "0")
+              .map((item) => {
+                return {
+                  ...item,
+                  name: item.fileName,
+                  url: item.fileUrl,
+                };
+              });
+          } else {
+            formData.data.fileList = [];
+          }
+        });
+    });
+  }
+});
+
+defineExpose({
+  handleSubmit,
+  tabsChange,
+});
+onMounted(() => {});
+</script>
+<style lang="scss" scoped>
+._title {
+  display: flex;
+  align-items: center;
+  font-size: 14px;
+  font-weight: 700;
+  margin-left: -10px;
+  .line {
+    width: 4px;
+    background-color: #0084ff;
+    height: 15px;
+    margin-right: 8px;
+  }
+}
+</style>

+ 15 - 0
src/views/processApproval/processDtl.vue

@@ -119,6 +119,9 @@ import MedicalAndsocialSecurity from "./components/MedicalAndsocialSecurity";
 import EncodingCombination from "./components/EncodingCombination";
 import ActivityPriceInventory from "./components/ActivityPriceInventory";
 import InvoicingApplication from "./components/InvoicingApplication";
+import InvoiceTaxDeduction from "./components/InvoiceTaxDeduction";
+import PersonalInvoice from "./components/PersonalInvoice";
+
 import SendPurchase from "./components/SendPurchase";
 import SendPurchasePayment from "./components/SendPurchasePayment";
 import ContractAlteration from "./components/ContractAlteration";
@@ -269,6 +272,18 @@ let componentObj = ref({
     backUrl: "/main/working",
     tabsNum: 0,
   },
+  invoice_tax_deduction_flow: {
+    title: "电子发票抵税提交发起流程",
+    component: InvoiceTaxDeduction,
+    backUrl: "/main/working",
+    tabsNum: 0,
+  },
+  personal_invoice_flow: {
+    title: "个人电子发票提交发起流程",
+    component: PersonalInvoice,
+    backUrl: "/main/working",
+    tabsNum: 0,
+  },
 });
 
 let dialogVisible = ref(false);