index.vue 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <template>
  2. <div class="page-container">
  3. <PageTitle title="开票管理" />
  4. <SearchBar :form="searchForm" :filters="filters" placeholder="对账编号" />
  5. <el-table v-loading="loading" :data="tableData" border style="width: 100%" @selection-change="handleSelectionChange">
  6. <el-table-column type="selection" width="55" align="center" />
  7. <el-table-column prop="billNo" label="对账编号" min-width="130" align="center" />
  8. <el-table-column prop="billDate" label="对账日期" min-width="110" align="center" />
  9. <el-table-column prop="amount" label="对账单金额" min-width="110" align="center">
  10. <template #default="{ row }">¥{{ row.amount.toFixed(2) }}</template>
  11. </el-table-column>
  12. <el-table-column prop="billStatus" label="对账状态" min-width="90" align="center">
  13. <template #default="{ row }">
  14. {{ getDictLabel(statement_status, row.billStatus) }}
  15. </template>
  16. </el-table-column>
  17. <el-table-column label="操作" width="100" align="center">
  18. <!-- <template #default="{ row }">
  19. <el-button type="primary" link size="small" @click="handleView(row)">查看</el-button>
  20. </template> -->
  21. </el-table-column>
  22. </el-table>
  23. <div class="bottom-bar">
  24. <div class="summary">
  25. <span
  26. >已选择 <em>{{ selectedCount }}</em> 个对账单</span
  27. >
  28. <span class="total"
  29. >合计金额 <em>¥{{ totalAmount.toFixed(2) }}</em></span
  30. >
  31. <el-button type="primary" :disabled="selectedCount === 0" @click="handleApplyInvoice">申请开票</el-button>
  32. </div>
  33. </div>
  34. <div class="pagination-wrapper">
  35. <TablePagination v-model:page="pagination.page" v-model:pageSize="pagination.pageSize" :total="pagination.total" />
  36. </div>
  37. </div>
  38. </template>
  39. <script setup lang="ts">
  40. import { reactive, ref, computed, onMounted, watch } from 'vue';
  41. import { ElMessage, ElMessageBox } from 'element-plus';
  42. import { PageTitle, SearchBar, TablePagination } from '@/components';
  43. import { getStatementList, applyForInvoice } from '@/api/pc/enterprise/statement';
  44. import type { StatementOrder } from '@/api/pc/enterprise/statementTypes';
  45. import { get } from 'http';
  46. const { proxy } = getCurrentInstance() as ComponentInternalInstance;
  47. const { invoice_issuance_status, statement_status, payment_status } = toRefs<any>(
  48. proxy?.useDict('invoice_issuance_status', 'statement_status', 'payment_status')
  49. );
  50. const searchForm = reactive({
  51. keyword: '',
  52. dateRange: [],
  53. invoiceStatus: ''
  54. });
  55. const form = reactive({
  56. statementOrderIds: []
  57. });
  58. const invoiceStatusOptions = ref([{ label: '全部', value: '' }]);
  59. const filters = ref([{ field: 'invoiceStatus', label: '开票状态', options: invoiceStatusOptions.value }]);
  60. const pagination = reactive({ page: 1, pageSize: 5, total: 0 });
  61. const tableData = ref<any[]>([]);
  62. const loading = ref(false);
  63. const selectedRows = ref<any[]>([]);
  64. // 加载对账单列表
  65. const loadStatementList = async () => {
  66. try {
  67. loading.value = true;
  68. const res = await getStatementList({
  69. pageNum: pagination.page,
  70. pageSize: pagination.pageSize,
  71. statementOrderNo: searchForm.keyword,
  72. isInvoiceStatus: searchForm.invoiceStatus,
  73. statementStatus: '2'
  74. });
  75. if (res.code === 200 && res.rows) {
  76. tableData.value = res.rows.map((item: StatementOrder) => ({
  77. id: item.id,
  78. billNo: item.statementOrderNo,
  79. billDate: item.statementDate,
  80. amount: parseFloat(item.amount as any) || 0,
  81. billStatus: item.statementStatus,
  82. invoiceStatus: item.isInvoiceStatus,
  83. payStatus: item.isPaymentStatus
  84. }));
  85. pagination.total = res.total || 0;
  86. }
  87. } catch (error) {
  88. console.error('加载对账单列表失败:', error);
  89. ElMessage.error('加载对账单列表失败');
  90. } finally {
  91. loading.value = false;
  92. }
  93. };
  94. const getDictLabel = (dictOptions: any[], value: string) => {
  95. if (!dictOptions || !value) return value;
  96. const dict = dictOptions.find((item) => item.value === value);
  97. return dict ? dict.label : value;
  98. };
  99. // 监听分页变化
  100. watch(
  101. () => [pagination.page, pagination.pageSize],
  102. () => {
  103. loadStatementList();
  104. }
  105. );
  106. // 监听搜索条件变化
  107. watch(
  108. () => [searchForm.keyword, searchForm.invoiceStatus],
  109. () => {
  110. pagination.page = 1;
  111. loadStatementList();
  112. }
  113. );
  114. // // 加载字典数据
  115. // const loadDictData = async () => {
  116. // try {
  117. // const res = await getDictByType('invoice_issuance_status');
  118. // if (res.data) {
  119. // invoiceStatusOptions.value = [
  120. // { label: '全部', value: '' },
  121. // ...res.data.map((item) => ({
  122. // label: item.dictLabel,
  123. // value: item.dictValue
  124. // }))
  125. // ];
  126. // filters.value[0].options = invoiceStatusOptions.value;
  127. // }
  128. // } catch (error) {
  129. // console.error('加载字典数据失败:', error);
  130. // }
  131. // };
  132. // 页面加载时获取数据
  133. onMounted(() => {
  134. // loadDictData();
  135. loadStatementList();
  136. });
  137. // 处理选择变化
  138. const handleSelectionChange = (selection: any[]) => {
  139. selectedRows.value = selection;
  140. };
  141. // 计算选中数量
  142. const selectedCount = computed(() => selectedRows.value.length);
  143. // 计算总金额
  144. const totalAmount = computed(() => {
  145. return selectedRows.value.reduce((sum, item) => sum + item.amount, 0);
  146. });
  147. const handleView = (row: any) => {
  148. ElMessage.info(`查看对账单:${row.billNo}`);
  149. };
  150. const handleApplyInvoice = async () => {
  151. try {
  152. form.statementOrderIds = selectedRows.value.map((row) => row.id);
  153. if (!form.statementOrderIds) {
  154. ElMessage.warning('请选择要申请的对账单');
  155. return;
  156. }
  157. const billNos = selectedRows.value.map((row) => row.billNo).join('、');
  158. await ElMessageBox.confirm(`确定要为以下对账单申请开票吗?\n${billNos}`, '提示', {
  159. confirmButtonText: '确定',
  160. cancelButtonText: '取消',
  161. type: 'warning'
  162. });
  163. // TODO: 调用申请开票接口
  164. await applyForInvoice(form);
  165. ElMessage.success('申请开票成功');
  166. loadStatementList();
  167. } catch (error) {
  168. if (error !== 'cancel') {
  169. console.error('申请开票失败:', error);
  170. ElMessage.error('申请开票失败');
  171. }
  172. }
  173. };
  174. </script>
  175. <style scoped>
  176. .bottom-bar {
  177. margin-top: 16px;
  178. padding: 16px;
  179. background: #fafafa;
  180. border: 1px solid #eee;
  181. border-radius: 4px;
  182. display: flex;
  183. justify-content: flex-end;
  184. }
  185. .summary {
  186. display: flex;
  187. align-items: center;
  188. gap: 20px;
  189. }
  190. .summary span {
  191. font-size: 14px;
  192. color: #666;
  193. }
  194. .summary em {
  195. color: #e60012;
  196. font-style: normal;
  197. font-weight: bold;
  198. }
  199. .summary .total em {
  200. font-size: 16px;
  201. }
  202. .pagination-wrapper {
  203. margin-top: 16px;
  204. display: flex;
  205. justify-content: flex-end;
  206. }
  207. </style>