hurx пре 2 недеља
родитељ
комит
4813e1dce2

+ 76 - 0
src/api/bill/invoiceApplication/index.ts

@@ -0,0 +1,76 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { InvoiceApplicationVO, InvoiceApplicationForm, InvoiceApplicationQuery } from '@/api/bill/invoiceApplication/types';
+
+/**
+ * 查询开票申请单列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listInvoiceApplication = (query?: InvoiceApplicationQuery): AxiosPromise<InvoiceApplicationVO[]> => {
+  return request({
+    url: '/bill/invoiceApplication/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询开票申请单详细
+ * @param id
+ */
+export const getInvoiceApplication = (id: string | number): AxiosPromise<InvoiceApplicationVO> => {
+  return request({
+    url: '/bill/invoiceApplication/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增开票申请单
+ * @param data
+ */
+export const addInvoiceApplication = (data: InvoiceApplicationForm) => {
+  return request({
+    url: '/bill/invoiceApplication',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改开票申请单
+ * @param data
+ */
+export const updateInvoiceApplication = (data: InvoiceApplicationForm) => {
+  return request({
+    url: '/bill/invoiceApplication',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除开票申请单
+ * @param id
+ */
+export const delInvoiceApplication = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/bill/invoiceApplication/' + id,
+    method: 'delete'
+  });
+};
+
+/**
+ * 审核开票申请
+ * @param id
+ * @param orderStatus
+ */
+export function auditApplication(data: InvoiceApplicationForm) {
+  return request({
+    url: '/bill/invoiceApplication/auditApplication',
+    method: 'put',
+    data: data
+  });
+}

+ 395 - 0
src/api/bill/invoiceApplication/types.ts

@@ -0,0 +1,395 @@
+export interface InvoiceApplicationVO {
+  /**
+   * 主键ID
+   */
+  id: string | number;
+
+  /**
+   * 开票申请单号
+   */
+  applicationNo: string;
+
+  /**
+   * 客户ID
+   */
+  customerId: string | number;
+
+  /**
+   * 客户名称
+   */
+  customerName: string;
+
+  /**
+   * 发票类型
+   */
+  invoiceType: string;
+
+  /**
+   * 发票抬头
+   */
+  invoiceTitle: string;
+
+  /**
+   * 纳税人识别号/统一社会信用代码
+   */
+  taxNumber: string;
+
+  /**
+   * 注册地址
+   */
+  regAddress: string;
+
+  /**
+   * 注册电话
+   */
+  regPhone: string;
+
+  /**
+   * 开户银行
+   */
+  bankName: string;
+
+  /**
+   * 银行账号
+   */
+  bankAccount: string;
+
+  /**
+   * 接收发票邮箱 (用于电票)
+   */
+  receiverEmail: string;
+
+  /**
+   * 接收短信手机号
+   */
+  receiverPhone: string;
+
+  /**
+   * 申请开票金额 (不含税)
+   */
+  applyAmount: number;
+
+  /**
+   * 申请税额
+   */
+  applyTaxAmount: number;
+
+  /**
+   * 价税合计总金额
+   */
+  totalAmount: number;
+
+  /**
+   * 关联的对账单ID集合
+   */
+  statementIds: string | number;
+
+  /**
+   * 申请备注/特殊要求
+   */
+  remark: string;
+
+  /**
+   * 申请状态: 0-待审核, 1-审核通过, 2-已驳回, 3-开票中, 4-已完成, 5-已取消
+   */
+  status: string;
+
+  /**
+   * 审核人ID
+   */
+  auditUserId: string | number;
+
+  /**
+   * 审核时间
+   */
+  auditTime: string;
+
+  /**
+   * 审核意见/驳回原因
+   */
+  auditRemark: string;
+
+  /**
+   * 审核通过后生成的正式发票单据ID (关联 statement_invoice.id)
+   */
+  finalInvoiceId: string | number;
+
+  /**
+   * 正式发票代码 (开票后回填)
+   */
+  invoiceCode: string;
+
+  /**
+   * 正式发票号码 (开票后回填)
+   */
+  invoiceNumber: string;
+
+  /**
+   * 正式开票日期
+   */
+  invoiceDate: string;
+}
+
+export interface InvoiceApplicationForm extends BaseEntity {
+  /**
+   * 主键ID
+   */
+  id?: string | number;
+
+  /**
+   * 开票申请单号
+   */
+  applicationNo?: string;
+
+  /**
+   * 客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 客户名称
+   */
+  customerName?: string;
+
+  /**
+   * 发票类型
+   */
+  invoiceType?: string;
+
+  /**
+   * 发票抬头
+   */
+  invoiceTitle?: string;
+
+  /**
+   * 纳税人识别号/统一社会信用代码
+   */
+  taxNumber?: string;
+
+  /**
+   * 注册地址
+   */
+  regAddress?: string;
+
+  /**
+   * 注册电话
+   */
+  regPhone?: string;
+
+  /**
+   * 开户银行
+   */
+  bankName?: string;
+
+  /**
+   * 银行账号
+   */
+  bankAccount?: string;
+
+  /**
+   * 接收发票邮箱 (用于电票)
+   */
+  receiverEmail?: string;
+
+  /**
+   * 接收短信手机号
+   */
+  receiverPhone?: string;
+
+  /**
+   * 申请开票金额 (不含税)
+   */
+  applyAmount?: number;
+
+  /**
+   * 申请税额
+   */
+  applyTaxAmount?: number;
+
+  /**
+   * 价税合计总金额
+   */
+  totalAmount?: number;
+
+  /**
+   * 关联的对账单ID集合
+   */
+  statementIds?: string | number;
+
+  /**
+   * 申请备注/特殊要求
+   */
+  remark?: string;
+
+  /**
+   * 申请状态: 0-待审核, 1-审核通过, 2-已驳回, 3-开票中, 4-已完成, 5-已取消
+   */
+  status?: string;
+
+  /**
+   * 审核人ID
+   */
+  auditUserId?: string | number;
+
+  /**
+   * 审核时间
+   */
+  auditTime?: string;
+
+  /**
+   * 审核意见/驳回原因
+   */
+  auditRemark?: string;
+
+  /**
+   * 审核通过后生成的正式发票单据ID (关联 statement_invoice.id)
+   */
+  finalInvoiceId?: string | number;
+
+  /**
+   * 正式发票代码 (开票后回填)
+   */
+  invoiceCode?: string;
+
+  /**
+   * 正式发票号码 (开票后回填)
+   */
+  invoiceNumber?: string;
+
+  /**
+   * 正式开票日期
+   */
+  invoiceDate?: string;
+}
+
+export interface InvoiceApplicationQuery extends PageQuery {
+  /**
+   * 开票申请单号
+   */
+  applicationNo?: string;
+
+  /**
+   * 客户ID
+   */
+  customerId?: string | number;
+
+  /**
+   * 客户名称
+   */
+  customerName?: string;
+
+  /**
+   * 发票类型
+   */
+  invoiceType?: string;
+
+  /**
+   * 发票抬头
+   */
+  invoiceTitle?: string;
+
+  /**
+   * 纳税人识别号/统一社会信用代码
+   */
+  taxNumber?: string;
+
+  /**
+   * 注册地址
+   */
+  regAddress?: string;
+
+  /**
+   * 注册电话
+   */
+  regPhone?: string;
+
+  /**
+   * 开户银行
+   */
+  bankName?: string;
+
+  /**
+   * 银行账号
+   */
+  bankAccount?: string;
+
+  /**
+   * 接收发票邮箱 (用于电票)
+   */
+  receiverEmail?: string;
+
+  /**
+   * 接收短信手机号
+   */
+  receiverPhone?: string;
+
+  /**
+   * 申请开票金额 (不含税)
+   */
+  applyAmount?: number;
+
+  /**
+   * 申请税额
+   */
+  applyTaxAmount?: number;
+
+  /**
+   * 价税合计总金额
+   */
+  totalAmount?: number;
+
+  /**
+   * 关联的对账单ID集合
+   */
+  statementIds?: string | number;
+
+  /**
+   * 申请状态: 0-待审核, 1-审核通过, 2-已驳回, 3-开票中, 4-已完成, 5-已取消
+   */
+  status?: string;
+
+  /**
+   * 审核人ID
+   */
+  auditUserId?: string | number;
+
+  /**
+   * 审核时间
+   */
+  auditTime?: string;
+
+  /**
+   * 审核意见/驳回原因
+   */
+  auditRemark?: string;
+
+  /**
+   * 审核通过后生成的正式发票单据ID (关联 statement_invoice.id)
+   */
+  finalInvoiceId?: string | number;
+
+  /**
+   * 正式发票代码 (开票后回填)
+   */
+  invoiceCode?: string;
+
+  /**
+   * 正式发票号码 (开票后回填)
+   */
+  invoiceNumber?: string;
+
+  /**
+   * 正式开票日期
+   */
+  invoiceDate?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 63 - 0
src/api/bill/reconApplication/index.ts

@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ReconApplicationVO, ReconApplicationForm, ReconApplicationQuery } from '@/api/bill/reconApplication/types';
+
+/**
+ * 查询对账申请列表
+ * @param query
+ * @returns {*}
+ */
+
+export const listReconApplication = (query?: ReconApplicationQuery): AxiosPromise<ReconApplicationVO[]> => {
+  return request({
+    url: '/bill/reconApplication/list',
+    method: 'get',
+    params: query
+  });
+};
+
+/**
+ * 查询对账申请详细
+ * @param id
+ */
+export const getReconApplication = (id: string | number): AxiosPromise<ReconApplicationVO> => {
+  return request({
+    url: '/bill/reconApplication/' + id,
+    method: 'get'
+  });
+};
+
+/**
+ * 新增对账申请
+ * @param data
+ */
+export const addReconApplication = (data: ReconApplicationForm) => {
+  return request({
+    url: '/bill/reconApplication',
+    method: 'post',
+    data: data
+  });
+};
+
+/**
+ * 修改对账申请
+ * @param data
+ */
+export const updateReconApplication = (data: ReconApplicationForm) => {
+  return request({
+    url: '/bill/reconApplication',
+    method: 'put',
+    data: data
+  });
+};
+
+/**
+ * 删除对账申请
+ * @param id
+ */
+export const delReconApplication = (id: string | number | Array<string | number>) => {
+  return request({
+    url: '/bill/reconApplication/' + id,
+    method: 'delete'
+  });
+};

+ 110 - 0
src/api/bill/reconApplication/types.ts

@@ -0,0 +1,110 @@
+export interface ReconApplicationVO {
+  /**
+   * 主键
+   */
+  id: string | number;
+
+  /**
+   * 对账单号
+   */
+  reconNo: string;
+
+  /**
+   * 总金额
+   */
+  totalAmount: number;
+
+  /**
+   * 申请日期
+   */
+  applyDate: string;
+
+  /**
+   * 申请对账订单id
+   */
+  orderIds: string | number;
+
+  /**
+   * 申请状态: 0-未开, 1-已开
+   */
+  status: string;
+
+  /**
+   * 备注
+   */
+  remark: string;
+}
+
+export interface ReconApplicationForm extends BaseEntity {
+  /**
+   * 主键
+   */
+  id?: string | number;
+
+  /**
+   * 对账单号
+   */
+  reconNo?: string;
+
+  /**
+   * 总金额
+   */
+  totalAmount?: number;
+
+  /**
+   * 申请日期
+   */
+  applyDate?: string;
+
+  /**
+   * 申请对账订单id
+   */
+  orderIds?: string | number;
+
+  /**
+   * 申请状态: 0-未开, 1-已开
+   */
+  status?: string;
+
+  /**
+   * 备注
+   */
+  remark?: string;
+}
+
+export interface ReconApplicationQuery extends PageQuery {
+  /**
+   * 对账单号
+   */
+  reconNo?: string;
+
+  /**
+   * 总金额
+   */
+  totalAmount?: number;
+
+  /**
+   * 申请日期
+   */
+  applyDate?: string;
+
+  /**
+   * 申请对账订单id
+   */
+  orderIds?: string | number;
+
+  /**
+   * 申请状态: 0-未开, 1-已开
+   */
+  status?: string;
+
+  /**
+   * 平台标识
+   */
+  platformCode?: string;
+
+  /**
+   * 日期范围参数
+   */
+  params?: any;
+}

+ 167 - 0
src/views/bill/invoiceApplication/addAndEditDrawer.vue

@@ -0,0 +1,167 @@
+<template>
+  <el-drawer v-model="visible" :title="title" :size="'70%'" :before-close="handleClose" destroy-on-close :close-on-click-modal="true">
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="180px">
+      <el-form-item label="发票类型" prop="invoiceType">
+        <el-select v-model="form.invoiceType" placeholder="请选择发票类型">
+          <el-option v-for="dict in invoice_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="发票抬头" prop="invoiceTitle">
+        <el-input v-model="form.invoiceTitle" placeholder="请输入发票抬头" />
+      </el-form-item>
+      <el-form-item label="纳税人识别号" prop="taxNumber">
+        <el-input v-model="form.taxNumber" placeholder="请输入纳税人识别号/统一社会信用代码" />
+      </el-form-item>
+      <el-form-item label="注册地址" prop="regAddress">
+        <el-input v-model="form.regAddress" placeholder="请输入注册地址" />
+      </el-form-item>
+      <el-form-item label="注册电话" prop="regPhone">
+        <el-input v-model="form.regPhone" placeholder="请输入注册电话" />
+      </el-form-item>
+      <el-form-item label="开户银行" prop="bankName">
+        <el-input v-model="form.bankName" placeholder="请输入开户银行" />
+      </el-form-item>
+      <el-form-item label="银行账号" prop="bankAccount">
+        <el-input v-model="form.bankAccount" placeholder="请输入银行账号" />
+      </el-form-item>
+      <el-form-item label="接收短信手机号" prop="receiverPhone">
+        <el-input v-model="form.receiverPhone" placeholder="请输入接收短信手机号" />
+      </el-form-item>
+      <el-form-item label="申请开票金额 (不含税)" prop="applyAmount">
+        <el-input v-model="form.applyAmount" placeholder="请输入申请开票金额 (不含税)" />
+      </el-form-item>
+      <el-form-item label="申请税额" prop="applyTaxAmount">
+        <el-input v-model="form.applyTaxAmount" placeholder="请输入申请税额" />
+      </el-form-item>
+      <el-form-item label="价税合计总金额" prop="totalAmount">
+        <el-input v-model="form.totalAmount" placeholder="请输入价税合计总金额" />
+      </el-form-item>
+      <el-form-item label="申请备注" prop="remark">
+        <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div class="drawer-footer">
+        <el-button @click="handleClose">取 消</el-button>
+        <el-button :loading="buttonLoading" type="primary" @click="handleSubmit">确 定</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, toRefs, getCurrentInstance, ComponentInternalInstance, watch } from 'vue';
+import { InvoiceApplicationForm } from '@/api/bill/invoiceApplication/types';
+import { addInvoiceApplication, updateInvoiceApplication } from '@/api/bill/invoiceApplication';
+import { ElMessage } from 'element-plus';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { invoice_application_status, invoice_type } = toRefs<any>(proxy?.useDict('invoice_application_status', 'invoice_type'));
+
+interface Props {
+  modelValue: boolean;
+  title?: string;
+  formData?: InvoiceApplicationForm;
+}
+
+interface Emits {
+  (e: 'update:modelValue', value: boolean): void;
+  (e: 'success'): void;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  title: '添加开票申请单'
+});
+
+const emit = defineEmits<Emits>();
+
+const formRef = ref();
+const buttonLoading = ref(false);
+
+const visible = ref(false);
+
+const initFormData: InvoiceApplicationForm = {
+  id: undefined,
+  applicationNo: undefined,
+  customerId: undefined,
+  customerName: undefined,
+  invoiceType: undefined,
+  invoiceTitle: undefined,
+  taxNumber: undefined,
+  regAddress: undefined,
+  regPhone: undefined,
+  bankName: undefined,
+  bankAccount: undefined,
+  receiverEmail: undefined,
+  receiverPhone: undefined,
+  applyAmount: undefined,
+  applyTaxAmount: undefined,
+  totalAmount: undefined,
+  statementIds: undefined,
+  remark: undefined,
+  status: undefined,
+  auditUserId: undefined,
+  auditTime: undefined,
+  auditRemark: undefined,
+  finalInvoiceId: undefined,
+  invoiceCode: undefined,
+  invoiceNumber: undefined,
+  invoiceDate: undefined
+};
+
+const form = ref<InvoiceApplicationForm>({ ...initFormData });
+
+const rules = {
+  invoiceType: [{ required: true, message: '发票类型不能为空', trigger: 'change' }]
+};
+
+// 监听modelValue变化
+watch(
+  () => props.modelValue,
+  (val) => {
+    visible.value = val;
+    if (val && props.formData) {
+      form.value = { ...props.formData };
+    } else if (val) {
+      form.value = { ...initFormData };
+    }
+  }
+);
+
+watch(visible, (val) => {
+  emit('update:modelValue', val);
+});
+
+const handleClose = () => {
+  visible.value = false;
+  formRef.value?.resetFields();
+};
+
+const handleSubmit = async () => {
+  await formRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      try {
+        if (form.value.id) {
+          await updateInvoiceApplication(form.value);
+        } else {
+          await addInvoiceApplication(form.value);
+        }
+        ElMessage.success('操作成功');
+        visible.value = false;
+        emit('success');
+      } finally {
+        buttonLoading.value = false;
+      }
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.drawer-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+</style>

+ 287 - 0
src/views/bill/invoiceApplication/index.vue

@@ -0,0 +1,287 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="110px">
+            <el-form-item label="开票申请单号" prop="applicationNo">
+              <el-input v-model="queryParams.applicationNo" placeholder="请输入开票申请单号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <!-- <el-form-item label="客户ID" prop="customerId">
+              <el-input v-model="queryParams.customerId" placeholder="请输入客户ID" clearable @keyup.enter="handleQuery" />
+            </el-form-item> -->
+
+            <el-form-item label="发票类型" prop="invoiceType">
+              <el-select v-model="queryParams.invoiceType" placeholder="请选择发票类型" clearable>
+                <el-option v-for="dict in invoice_type" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="发票抬头" prop="invoiceTitle">
+              <el-input v-model="queryParams.invoiceTitle" placeholder="请输入发票抬头" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+
+            <el-form-item label="申请状态" prop="status">
+              <el-select v-model="queryParams.status" placeholder="请选择申请状态" clearable>
+                <el-option v-for="dict in invoice_application_status" :key="dict.value" :label="dict.label" :value="dict.value" />
+              </el-select>
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['bill:invoiceApplication:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['bill:invoiceApplication:edit']"
+              >修改</el-button
+            >
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['bill:invoiceApplication:remove']"
+              >删除</el-button
+            >
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['bill:invoiceApplication:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="invoiceApplicationList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="开票申请单号" align="center" prop="applicationNo" />
+        <el-table-column label="客户名称" align="center" prop="customerName" />
+        <el-table-column label="发票类型" align="center" prop="invoiceType">
+          <template #default="scope">
+            <dict-tag :options="invoice_type" :value="scope.row.invoiceType" />
+          </template>
+        </el-table-column>
+        <el-table-column label="发票抬头" align="center" prop="invoiceTitle" />
+        <el-table-column label="纳税人识别号" align="center" prop="taxNumber" />
+        <el-table-column label="注册地址" align="center" prop="regAddress" />
+        <el-table-column label="注册电话" align="center" prop="regPhone" />
+        <el-table-column label="开户银行" align="center" prop="bankName" />
+        <el-table-column label="银行账号" align="center" prop="bankAccount" />
+        <el-table-column label="申请开票金额" align="center" prop="applyAmount" />
+        <el-table-column label="申请税额" align="center" prop="applyTaxAmount" />
+        <el-table-column label="总金额" align="center" prop="totalAmount" />
+        <el-table-column label="申请备注" align="center" prop="remark" />
+        <el-table-column label="申请状态" align="center" prop="status">
+          <template #default="scope">
+            <dict-tag :options="invoice_application_status" :value="scope.row.status" />
+          </template>
+        </el-table-column>
+        <el-table-column label="审核人ID" align="center" prop="auditUserId" />
+        <el-table-column label="审核时间" align="center" prop="auditTime" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.auditTime, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="审核意见" align="center" prop="auditRemark" />
+
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <!-- <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['bill:invoiceApplication:edit']">编辑</el-button> -->
+            <el-button link type="primary" icon="Edit" @click="handleAudit(scope.row)" v-hasPermi="['bill:invoiceApplication:edit']">审核</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['bill:invoiceApplication:remove']"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改开票申请单抽屉 -->
+    <AddAndEditDrawer v-model="drawerVisible" :title="drawerTitle" :form-data="currentFormData" @success="handleDrawerSuccess" />
+
+    <!-- 审核对话框 -->
+    <el-dialog v-model="auditDialogVisible" title="审核开票申请" width="500px" append-to-body>
+      <el-form ref="auditFormRef" :model="auditForm" label-width="100px">
+        <el-form-item label="审核结果" prop="status">
+          <el-select v-model="auditForm.status" placeholder="请选择审核结果">
+            <el-option v-for="dict in invoice_application_status" :key="dict.value" :label="dict.label" :value="dict.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="审核意见" prop="auditRemark">
+          <el-input v-model="auditForm.auditRemark" type="textarea" :rows="4" placeholder="请输入审核意见" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="auditDialogVisible = false">取 消</el-button>
+        <el-button type="primary" @click="handleAuditSubmit">确 定</el-button>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="InvoiceApplication" lang="ts">
+import { listInvoiceApplication, getInvoiceApplication, delInvoiceApplication, auditApplication } from '@/api/bill/invoiceApplication';
+import AddAndEditDrawer from './invoiceApplyDrawer.vue';
+import { InvoiceApplicationVO, InvoiceApplicationQuery, InvoiceApplicationForm } from '@/api/bill/invoiceApplication/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { invoice_application_status, invoice_type } = toRefs<any>(proxy?.useDict('invoice_application_status', 'invoice_type'));
+
+const invoiceApplicationList = ref<InvoiceApplicationVO[]>([]);
+const drawerVisible = ref(false);
+const drawerTitle = ref('');
+const currentFormData = ref<InvoiceApplicationForm>();
+const auditDialogVisible = ref(false);
+const auditForm = ref<InvoiceApplicationForm>({});
+const auditFormRef = ref<ElFormInstance>();
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+
+const data = reactive<PageData<InvoiceApplicationForm, InvoiceApplicationQuery>>({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    applicationNo: undefined,
+    customerId: undefined,
+    customerName: undefined,
+    invoiceType: undefined,
+    invoiceTitle: undefined,
+    taxNumber: undefined,
+    regAddress: undefined,
+    regPhone: undefined,
+    bankName: undefined,
+    bankAccount: undefined,
+    receiverEmail: undefined,
+    receiverPhone: undefined,
+    applyAmount: undefined,
+    applyTaxAmount: undefined,
+    totalAmount: undefined,
+    statementIds: undefined,
+    status: undefined,
+    auditUserId: undefined,
+    auditTime: undefined,
+    auditRemark: undefined,
+    finalInvoiceId: undefined,
+    invoiceCode: undefined,
+    invoiceNumber: undefined,
+    invoiceDate: undefined,
+    platformCode: undefined,
+    params: {}
+  },
+  rules: {}
+});
+
+const { queryParams } = toRefs(data);
+
+/** 查询开票申请单列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listInvoiceApplication(queryParams.value);
+  invoiceApplicationList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+/** 抽屉成功回调 */
+const handleDrawerSuccess = () => {
+  getList();
+};
+
+/** 审核按钮操作 */
+const handleAudit = (row: InvoiceApplicationVO) => {
+  auditForm.value = {
+    id: row.id,
+    status: undefined,
+    auditRemark: ''
+  };
+  auditDialogVisible.value = true;
+};
+
+/** 审核提交 */
+const handleAuditSubmit = async () => {
+  if (!auditForm.value.status) {
+    proxy?.$modal.msgWarning('请选择审核结果');
+    return;
+  }
+  try {
+    await auditApplication(auditForm.value);
+    proxy?.$modal.msgSuccess('审核成功');
+    auditDialogVisible.value = false;
+    await getList();
+  } catch (error) {
+    console.error('审核失败:', error);
+  }
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: InvoiceApplicationVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  currentFormData.value = undefined;
+  drawerTitle.value = '添加开票申请单';
+  drawerVisible.value = true;
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: InvoiceApplicationVO) => {
+  const _id = row?.id || ids.value[0];
+  const res = await getInvoiceApplication(_id);
+  currentFormData.value = res.data;
+  drawerTitle.value = '修改开票申请单';
+  drawerVisible.value = true;
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: InvoiceApplicationVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除开票申请单编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delInvoiceApplication(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'bill/invoiceApplication/export',
+    {
+      ...queryParams.value
+    },
+    `invoiceApplication_${new Date().getTime()}.xlsx`
+  );
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 167 - 0
src/views/bill/invoiceApplication/invoiceApplyDrawer.vue

@@ -0,0 +1,167 @@
+<template>
+  <el-drawer v-model="visible" :title="title" :size="'70%'" :before-close="handleClose" destroy-on-close :close-on-click-modal="true">
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="180px">
+      <el-form-item label="发票类型" prop="invoiceType">
+        <el-select v-model="form.invoiceType" placeholder="请选择发票类型">
+          <el-option v-for="dict in invoice_type" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+        </el-select>
+      </el-form-item>
+      <el-form-item label="发票抬头" prop="invoiceTitle">
+        <el-input v-model="form.invoiceTitle" placeholder="请输入发票抬头" />
+      </el-form-item>
+      <el-form-item label="纳税人识别号" prop="taxNumber">
+        <el-input v-model="form.taxNumber" placeholder="请输入纳税人识别号/统一社会信用代码" />
+      </el-form-item>
+      <el-form-item label="注册地址" prop="regAddress">
+        <el-input v-model="form.regAddress" placeholder="请输入注册地址" />
+      </el-form-item>
+      <el-form-item label="注册电话" prop="regPhone">
+        <el-input v-model="form.regPhone" placeholder="请输入注册电话" />
+      </el-form-item>
+      <el-form-item label="开户银行" prop="bankName">
+        <el-input v-model="form.bankName" placeholder="请输入开户银行" />
+      </el-form-item>
+      <el-form-item label="银行账号" prop="bankAccount">
+        <el-input v-model="form.bankAccount" placeholder="请输入银行账号" />
+      </el-form-item>
+      <el-form-item label="接收短信手机号" prop="receiverPhone">
+        <el-input v-model="form.receiverPhone" placeholder="请输入接收短信手机号" />
+      </el-form-item>
+      <el-form-item label="申请开票金额 (不含税)" prop="applyAmount">
+        <el-input v-model="form.applyAmount" placeholder="请输入申请开票金额 (不含税)" />
+      </el-form-item>
+      <el-form-item label="申请税额" prop="applyTaxAmount">
+        <el-input v-model="form.applyTaxAmount" placeholder="请输入申请税额" />
+      </el-form-item>
+      <el-form-item label="价税合计总金额" prop="totalAmount">
+        <el-input v-model="form.totalAmount" placeholder="请输入价税合计总金额" />
+      </el-form-item>
+      <el-form-item label="申请备注/特殊要求" prop="remark">
+        <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div class="drawer-footer">
+        <el-button @click="handleClose">取 消</el-button>
+        <el-button :loading="buttonLoading" type="primary" @click="handleSubmit">确 定</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup lang="ts">
+import { ref, reactive, toRefs, getCurrentInstance, ComponentInternalInstance, watch } from 'vue';
+import { InvoiceApplicationForm } from '@/api/bill/invoiceApplication/types';
+import { addInvoiceApplication, updateInvoiceApplication } from '@/api/bill/invoiceApplication';
+import { ElMessage } from 'element-plus';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { invoice_application_status, invoice_type } = toRefs<any>(proxy?.useDict('invoice_application_status', 'invoice_type'));
+
+interface Props {
+  modelValue: boolean;
+  title?: string;
+  formData?: InvoiceApplicationForm;
+}
+
+interface Emits {
+  (e: 'update:modelValue', value: boolean): void;
+  (e: 'success'): void;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  title: '添加开票申请单'
+});
+
+const emit = defineEmits<Emits>();
+
+const formRef = ref();
+const buttonLoading = ref(false);
+
+const visible = ref(false);
+
+const initFormData: InvoiceApplicationForm = {
+  id: undefined,
+  applicationNo: undefined,
+  customerId: undefined,
+  customerName: undefined,
+  invoiceType: undefined,
+  invoiceTitle: undefined,
+  taxNumber: undefined,
+  regAddress: undefined,
+  regPhone: undefined,
+  bankName: undefined,
+  bankAccount: undefined,
+  receiverEmail: undefined,
+  receiverPhone: undefined,
+  applyAmount: undefined,
+  applyTaxAmount: undefined,
+  totalAmount: undefined,
+  statementIds: undefined,
+  remark: undefined,
+  status: undefined,
+  auditUserId: undefined,
+  auditTime: undefined,
+  auditRemark: undefined,
+  finalInvoiceId: undefined,
+  invoiceCode: undefined,
+  invoiceNumber: undefined,
+  invoiceDate: undefined
+};
+
+const form = ref<InvoiceApplicationForm>({ ...initFormData });
+
+const rules = {
+  invoiceType: [{ required: true, message: '发票类型不能为空', trigger: 'change' }]
+};
+
+// 监听modelValue变化
+watch(
+  () => props.modelValue,
+  (val) => {
+    visible.value = val;
+    if (val && props.formData) {
+      form.value = { ...props.formData };
+    } else if (val) {
+      form.value = { ...initFormData };
+    }
+  }
+);
+
+watch(visible, (val) => {
+  emit('update:modelValue', val);
+});
+
+const handleClose = () => {
+  visible.value = false;
+  formRef.value?.resetFields();
+};
+
+const handleSubmit = async () => {
+  await formRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      try {
+        if (form.value.id) {
+          await updateInvoiceApplication(form.value);
+        } else {
+          await addInvoiceApplication(form.value);
+        }
+        ElMessage.success('操作成功');
+        visible.value = false;
+        emit('success');
+      } finally {
+        buttonLoading.value = false;
+      }
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.drawer-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+</style>

+ 189 - 0
src/views/bill/reconApplication/index.vue

@@ -0,0 +1,189 @@
+<template>
+  <div class="p-2">
+    <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+      <div v-show="showSearch" class="mb-[10px]">
+        <el-card shadow="hover">
+          <el-form ref="queryFormRef" :model="queryParams" :inline="true">
+            <el-form-item label="对账单号" prop="reconNo">
+              <el-input v-model="queryParams.reconNo" placeholder="请输入对账单号" clearable @keyup.enter="handleQuery" />
+            </el-form-item>
+            <el-form-item label="申请日期" prop="applyDate">
+              <el-date-picker clearable v-model="queryParams.applyDate" type="date" value-format="YYYY-MM-DD" placeholder="请选择申请日期" />
+            </el-form-item>
+            <el-form-item>
+              <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+              <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+            </el-form-item>
+          </el-form>
+        </el-card>
+      </div>
+    </transition>
+
+    <el-card shadow="never">
+      <template #header>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['bill:reconApplication:add']">新增</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['bill:reconApplication:edit']"
+              >修改</el-button
+            >
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['bill:reconApplication:remove']"
+              >删除</el-button
+            >
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['bill:reconApplication:export']">导出</el-button>
+          </el-col>
+          <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+        </el-row>
+      </template>
+
+      <el-table v-loading="loading" border :data="reconApplicationList" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" align="center" />
+        <el-table-column label="主键" align="center" prop="id" v-if="true" />
+        <el-table-column label="对账单号" align="center" prop="reconNo" />
+        <el-table-column label="总金额" align="center" prop="totalAmount" />
+        <el-table-column label="申请日期" align="center" prop="applyDate" width="180">
+          <template #default="scope">
+            <span>{{ parseTime(scope.row.applyDate, '{y}-{m}-{d}') }}</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="申请状态" align="center" prop="status" />
+        <el-table-column label="备注" align="center" prop="remark" />
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+          <template #default="scope">
+            <el-button link type="primary" icon="Edit" @click="handleAudit(scope.row)" v-hasPermi="['bill:reconApplication:edit']">审核</el-button>
+            <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['bill:reconApplication:remove']"
+              >删除</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+
+      <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
+    </el-card>
+    <!-- 添加或修改对账申请抽屉 -->
+    <ReconApplyDrawer v-model="drawerVisible" :title="drawerTitle" :form-data="currentFormData" @success="handleDrawerSuccess" />
+  </div>
+</template>
+
+<script setup name="ReconApplication" lang="ts">
+import { listReconApplication, getReconApplication, delReconApplication } from '@/api/bill/reconApplication';
+import ReconApplyDrawer from './reconApplyDrawer.vue';
+import { ReconApplicationVO, ReconApplicationQuery, ReconApplicationForm } from '@/api/bill/reconApplication/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+
+const reconApplicationList = ref<ReconApplicationVO[]>([]);
+const drawerVisible = ref(false);
+const drawerTitle = ref('');
+const currentFormData = ref<ReconApplicationForm>();
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+
+const queryFormRef = ref<ElFormInstance>();
+
+const data = reactive<PageData<ReconApplicationForm, ReconApplicationQuery>>({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    reconNo: undefined,
+    totalAmount: undefined,
+    applyDate: undefined,
+    orderIds: undefined,
+    status: undefined,
+    platformCode: undefined,
+    params: {}
+  },
+  rules: {}
+});
+
+const { queryParams } = toRefs(data);
+
+/** 查询对账申请列表 */
+const getList = async () => {
+  loading.value = true;
+  const res = await listReconApplication(queryParams.value);
+  reconApplicationList.value = res.rows;
+  total.value = res.total;
+  loading.value = false;
+};
+
+/** 抽屉成功回调 */
+const handleDrawerSuccess = () => {
+  getList();
+};
+
+/** 搜索按钮操作 */
+const handleQuery = () => {
+  queryParams.value.pageNum = 1;
+  getList();
+};
+
+/** 重置按钮操作 */
+const resetQuery = () => {
+  queryFormRef.value?.resetFields();
+  handleQuery();
+};
+
+/** 多选框选中数据 */
+const handleSelectionChange = (selection: ReconApplicationVO[]) => {
+  ids.value = selection.map((item) => item.id);
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+};
+
+/** 新增按钮操作 */
+const handleAdd = () => {
+  currentFormData.value = undefined;
+  drawerTitle.value = '添加对账申请';
+  drawerVisible.value = true;
+};
+
+/** 修改按钮操作 */
+const handleUpdate = async (row?: ReconApplicationVO) => {
+  const _id = row?.id || ids.value[0];
+  const res = await getReconApplication(_id);
+  currentFormData.value = res.data;
+  drawerTitle.value = '修改对账申请';
+  drawerVisible.value = true;
+};
+
+/** 修改按钮操作 */
+const handleAudit = async (row?: ReconApplicationVO) => {
+  const _id = row?.id || ids.value[0];
+};
+
+/** 删除按钮操作 */
+const handleDelete = async (row?: ReconApplicationVO) => {
+  const _ids = row?.id || ids.value;
+  await proxy?.$modal.confirm('是否确认删除对账申请编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
+  await delReconApplication(_ids);
+  proxy?.$modal.msgSuccess('删除成功');
+  await getList();
+};
+
+/** 导出按钮操作 */
+const handleExport = () => {
+  proxy?.download(
+    'bill/reconApplication/export',
+    {
+      ...queryParams.value
+    },
+    `reconApplication_${new Date().getTime()}.xlsx`
+  );
+};
+
+onMounted(() => {
+  getList();
+});
+</script>

+ 113 - 0
src/views/bill/reconApplication/reconApplyDrawer.vue

@@ -0,0 +1,113 @@
+<template>
+  <el-drawer v-model="visible" :title="title" :size="'70%'" :before-close="handleClose" destroy-on-close :close-on-click-modal="true">
+    <el-form ref="formRef" :model="form" :rules="rules" label-width="150px">
+      <el-form-item label="总金额" prop="totalAmount">
+        <el-input v-model="form.totalAmount" placeholder="请输入总金额" />
+      </el-form-item>
+      <el-form-item label="申请日期" prop="applyDate">
+        <el-date-picker clearable v-model="form.applyDate" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择申请日期">
+        </el-date-picker>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+      </el-form-item>
+    </el-form>
+    <template #footer>
+      <div class="drawer-footer">
+        <el-button @click="handleClose">取 消</el-button>
+        <el-button :loading="buttonLoading" type="primary" @click="handleSubmit">确 定</el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup lang="ts">
+import { ref, watch } from 'vue';
+import { ReconApplicationForm } from '@/api/bill/reconApplication/types';
+import { addReconApplication, updateReconApplication } from '@/api/bill/reconApplication';
+import { ElMessage } from 'element-plus';
+
+interface Props {
+  modelValue: boolean;
+  title?: string;
+  formData?: ReconApplicationForm;
+}
+
+interface Emits {
+  (e: 'update:modelValue', value: boolean): void;
+  (e: 'success'): void;
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  title: '添加对账申请'
+});
+
+const emit = defineEmits<Emits>();
+
+const formRef = ref();
+const buttonLoading = ref(false);
+const visible = ref(false);
+
+const initFormData: ReconApplicationForm = {
+  id: undefined,
+  reconNo: undefined,
+  totalAmount: undefined,
+  applyDate: undefined,
+  orderIds: undefined,
+  status: undefined,
+  remark: undefined
+};
+
+const form = ref<ReconApplicationForm>({ ...initFormData });
+
+const rules = {};
+
+watch(
+  () => props.modelValue,
+  (val) => {
+    visible.value = val;
+    if (val && props.formData) {
+      form.value = { ...props.formData };
+    } else if (val) {
+      form.value = { ...initFormData };
+    }
+  }
+);
+
+watch(visible, (val) => {
+  emit('update:modelValue', val);
+});
+
+const handleClose = () => {
+  visible.value = false;
+  formRef.value?.resetFields();
+};
+
+const handleSubmit = async () => {
+  await formRef.value?.validate(async (valid: boolean) => {
+    if (valid) {
+      buttonLoading.value = true;
+      try {
+        if (form.value.id) {
+          await updateReconApplication(form.value);
+        } else {
+          await addReconApplication(form.value);
+        }
+        ElMessage.success('操作成功');
+        visible.value = false;
+        emit('success');
+      } finally {
+        buttonLoading.value = false;
+      }
+    }
+  });
+};
+</script>
+
+<style scoped lang="scss">
+.drawer-footer {
+  display: flex;
+  justify-content: flex-end;
+  gap: 10px;
+}
+</style>

+ 12 - 12
src/views/bill/statementInvoice/addInvoiceDialog.vue

@@ -172,21 +172,21 @@ const beforeUpload = (file: any) => {
   return isLt50M;
 };
 
-/** 上传成功回调 */
-const handleUploadSuccess = (response: any, uploadFile: any) => {
+function handleUploadSuccess(response: any, file: any, fileListParam: any[]) {
   if (response.code === 200) {
-    uploadFile.url = response.data.url;
-    nextTick(() => {
-      form.value.invoiceAnnex = fileList.value
-        .map((f) => f.url)
-        .filter(Boolean)
-        .join(',');
-    });
-    proxy?.$modal.msgSuccess('上传成功');
+    // 更新 fileList
+    fileList.value = fileListParam;
+    // 收集所有已上传成功的文件URL
+    const urls = fileListParam
+      .filter((f: any) => f.response?.code === 200 || f.url)
+      .map((f: any) => f.response?.data?.url || f.url)
+      .filter(Boolean);
+    form.value.invoiceAnnex = urls.join(',');
+    proxy?.$modal.msgSuccess('文件上传成功');
   } else {
-    proxy?.$modal.msgError(response.msg || '上传失败');
+    proxy?.$modal.msgError(response.msg || '文件上传失败');
   }
-};
+}
 
 /** 删除文件 */
 const handleRemoveUploadFile = (uploadFile: any) => {