index.vue 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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 } 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 invoiceStatusOptions = ref([{ label: '全部', value: '' }]);
  56. const filters = ref([{ field: 'invoiceStatus', label: '开票状态', options: invoiceStatusOptions.value }]);
  57. const pagination = reactive({ page: 1, pageSize: 5, total: 0 });
  58. const tableData = ref<any[]>([]);
  59. const loading = ref(false);
  60. const selectedRows = ref<any[]>([]);
  61. // 加载对账单列表
  62. const loadStatementList = async () => {
  63. try {
  64. loading.value = true;
  65. const res = await getStatementList({
  66. pageNum: pagination.page,
  67. pageSize: pagination.pageSize,
  68. statementOrderNo: searchForm.keyword,
  69. isInvoiceStatus: searchForm.invoiceStatus,
  70. statementStatus: '2'
  71. });
  72. if (res.code === 200 && res.rows) {
  73. tableData.value = res.rows.map((item: StatementOrder) => ({
  74. id: item.id,
  75. billNo: item.statementOrderNo,
  76. billDate: item.statementDate,
  77. amount: parseFloat(item.amount as any) || 0,
  78. billStatus: item.statementStatus,
  79. invoiceStatus: item.isInvoiceStatus,
  80. payStatus: item.isPaymentStatus
  81. }));
  82. pagination.total = res.total || 0;
  83. }
  84. } catch (error) {
  85. console.error('加载对账单列表失败:', error);
  86. ElMessage.error('加载对账单列表失败');
  87. } finally {
  88. loading.value = false;
  89. }
  90. };
  91. const getDictLabel = (dictOptions: any[], value: string) => {
  92. if (!dictOptions || !value) return value;
  93. const dict = dictOptions.find((item) => item.value === value);
  94. return dict ? dict.label : value;
  95. };
  96. // 监听分页变化
  97. watch(
  98. () => [pagination.page, pagination.pageSize],
  99. () => {
  100. loadStatementList();
  101. }
  102. );
  103. // 监听搜索条件变化
  104. watch(
  105. () => [searchForm.keyword, searchForm.invoiceStatus],
  106. () => {
  107. pagination.page = 1;
  108. loadStatementList();
  109. }
  110. );
  111. // // 加载字典数据
  112. // const loadDictData = async () => {
  113. // try {
  114. // const res = await getDictByType('invoice_issuance_status');
  115. // if (res.data) {
  116. // invoiceStatusOptions.value = [
  117. // { label: '全部', value: '' },
  118. // ...res.data.map((item) => ({
  119. // label: item.dictLabel,
  120. // value: item.dictValue
  121. // }))
  122. // ];
  123. // filters.value[0].options = invoiceStatusOptions.value;
  124. // }
  125. // } catch (error) {
  126. // console.error('加载字典数据失败:', error);
  127. // }
  128. // };
  129. // 页面加载时获取数据
  130. onMounted(() => {
  131. // loadDictData();
  132. loadStatementList();
  133. });
  134. // 处理选择变化
  135. const handleSelectionChange = (selection: any[]) => {
  136. selectedRows.value = selection;
  137. };
  138. // 计算选中数量
  139. const selectedCount = computed(() => selectedRows.value.length);
  140. // 计算总金额
  141. const totalAmount = computed(() => {
  142. return selectedRows.value.reduce((sum, item) => sum + item.amount, 0);
  143. });
  144. const handleView = (row: any) => {
  145. ElMessage.info(`查看对账单:${row.billNo}`);
  146. };
  147. const handleApplyInvoice = async () => {
  148. try {
  149. const billNos = selectedRows.value.map((row) => row.billNo).join('、');
  150. await ElMessageBox.confirm(`确定要为以下对账单申请开票吗?\n${billNos}`, '提示', {
  151. confirmButtonText: '确定',
  152. cancelButtonText: '取消',
  153. type: 'warning'
  154. });
  155. // TODO: 调用申请开票接口
  156. ElMessage.success('申请开票成功');
  157. loadStatementList();
  158. } catch (error) {
  159. if (error !== 'cancel') {
  160. console.error('申请开票失败:', error);
  161. ElMessage.error('申请开票失败');
  162. }
  163. }
  164. };
  165. </script>
  166. <style scoped>
  167. .bottom-bar {
  168. margin-top: 16px;
  169. padding: 16px;
  170. background: #fafafa;
  171. border: 1px solid #eee;
  172. border-radius: 4px;
  173. display: flex;
  174. justify-content: flex-end;
  175. }
  176. .summary {
  177. display: flex;
  178. align-items: center;
  179. gap: 20px;
  180. }
  181. .summary span {
  182. font-size: 14px;
  183. color: #666;
  184. }
  185. .summary em {
  186. color: #e60012;
  187. font-style: normal;
  188. font-weight: bold;
  189. }
  190. .summary .total em {
  191. font-size: 16px;
  192. }
  193. .pagination-wrapper {
  194. margin-top: 16px;
  195. display: flex;
  196. justify-content: flex-end;
  197. }
  198. </style>