index.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. <template>
  2. <div class="entry-container">
  3. <!-- <div
  4. class="search-wrap"
  5. ref="searchWrapRef"
  6. >
  7. <el-form
  8. :model="state.queryParams"
  9. ref="queryRef"
  10. >
  11. <el-form-item prop="serialNo">
  12. <el-select
  13. v-model="state.queryParams.feeType"
  14. style="width: 100%"
  15. placeholder="费用类型"
  16. clearable
  17. @change="search"
  18. >
  19. <el-option
  20. v-for="item in FeeTypeList"
  21. :key="item.id"
  22. :label="item.name"
  23. :value="item.id"
  24. ></el-option>
  25. </el-select>
  26. </el-form-item>
  27. <el-form-item prop="serialNo">
  28. <el-select
  29. v-model="state.queryParams.feeStatus"
  30. style="width: 100%"
  31. placeholder="费用状态"
  32. clearable
  33. @change="search"
  34. >
  35. <el-option
  36. label="已支付"
  37. value="20"
  38. ></el-option>
  39. <el-option
  40. label="未支付"
  41. value="10"
  42. ></el-option>
  43. </el-select>
  44. </el-form-item>
  45. <el-form-item prop="serialNo">
  46. <el-date-picker
  47. v-model="state.queryParams.feeTime"
  48. type="date"
  49. style="width: 100%"
  50. placeholder="费用时间"
  51. clearable
  52. @change="search"
  53. />
  54. </el-form-item>
  55. </el-form>
  56. <div style="text-align: right">
  57. <el-button
  58. @click="handleExport"
  59. style="height: 25px"
  60. type="primary"
  61. >
  62. 导出
  63. </el-button>
  64. </div>
  65. </div> -->
  66. <div class="list-container">
  67. <van-list
  68. v-model:loading="state.loading"
  69. :finished="state.finished"
  70. finished-text="没有更多了"
  71. @load="onLoad"
  72. >
  73. <van-cell
  74. v-for="item in state.pageList"
  75. :key="item"
  76. >
  77. <template #default>
  78. <div class="list">
  79. <header class="flex justify-between">
  80. <strong class="title">{{ `${item.userName}的费用流水` }}</strong>
  81. <van-tag
  82. v-if="item.approveStatus == ApproveStatus.WAIT_SUBMIT"
  83. type="warning"
  84. >
  85. 待提交
  86. </van-tag>
  87. <van-tag
  88. v-else-if="item.approveStatus == ApproveStatus.APPROVING"
  89. type="primary"
  90. >
  91. 审核中
  92. </van-tag>
  93. <van-tag
  94. v-else-if="item.approveStatus == ApproveStatus.PASS"
  95. type="success"
  96. >
  97. 通过
  98. </van-tag>
  99. <van-tag
  100. v-else-if="item.approveStatus == ApproveStatus.REVOKE"
  101. type="success"
  102. >
  103. 撤销
  104. </van-tag>
  105. <van-tag
  106. v-else-if="item.approveStatus == ApproveStatus.REFUSE"
  107. type="danger"
  108. >
  109. 拒绝
  110. </van-tag>
  111. </header>
  112. <p class="inst-title">
  113. <span>费用类型</span>
  114. <span class="title ml8">{{ formatterFboType(item) }}</span>
  115. </p>
  116. <p class="inst-title">
  117. <span>费用时间</span>
  118. <span class="title ml8">
  119. {{ item.fbdStartDate ? dayjs(item.fbdStartDate).format('YYYY-MM-DD') : '' }} ~
  120. {{ item.fbdEndDate ? dayjs(item.fbdEndDate).format('YYYY-MM-DD') : '' }}
  121. </span>
  122. </p>
  123. <p class="inst-title">
  124. <span>确认时间</span>
  125. <span class="title ml8">
  126. {{ item.confirmTime ? dayjs(item.confirmTime).format('YYYY-MM-DD') : '' }}
  127. </span>
  128. </p>
  129. <p class="inst-title">
  130. <span>总计金额</span>
  131. <span class="title ml8">{{ item.fboActualAmount }} 元</span>
  132. </p>
  133. <p class="inst-title">
  134. <span>状态</span>
  135. <span class="title ml8">
  136. {{ formatterFboStatus(item) }}
  137. </span>
  138. </p>
  139. <footer class="flex justify-between mt16"></footer>
  140. </div>
  141. </template>
  142. </van-cell>
  143. </van-list>
  144. </div>
  145. <DetailModal
  146. :showDialog="showDetailDialog"
  147. :isReturnCageList="false"
  148. ref="detailModalRef"
  149. @close="() => (showDetailDialog = false)"
  150. />
  151. <ReturnCageDialog
  152. ref="returnCageDialogRef"
  153. :currentRefundableItemNumber="currentRefundableItemNumber"
  154. :getTableData="handleRefresh"
  155. />
  156. </div>
  157. </template>
  158. <script lang="ts" setup>
  159. import { reactive, ref, onMounted, defineAsyncComponent, ComponentPublicInstance } from 'vue'
  160. import to from 'await-to-js'
  161. import dayjs from 'dayjs'
  162. import { formatDate, formatToChineseDate } from '/@/utils/formatTime'
  163. import { ApproveStatus, ApproveStatusList, MyCageType, FeeTypeList } from '/@/constants/pageConstants'
  164. import { usePlatAnimalCageApplicationApi } from '/@/api/platform/animal'
  165. import { useFinaceApi } from '/@/api/finace'
  166. import { useBillApi } from '/@/api/instr/finance/bill'
  167. import { useUserInfos } from '/@/hooks/useUserInfos'
  168. interface ReturnCageDialogInstance extends ComponentPublicInstance {
  169. handleOpenRefundableDialog: (id: number) => void
  170. }
  171. interface DetailModalInstance extends ComponentPublicInstance {
  172. initForm: (id: number) => void
  173. }
  174. const DetailModal = defineAsyncComponent(() => import('/@/view/animal/application/components/Detail.vue'))
  175. const ReturnCageDialog = defineAsyncComponent(
  176. () => import('/@/view/animal/application/components/ReturnCageDialog.vue'),
  177. )
  178. const { userInfos } = useUserInfos()
  179. const platAnimalCageApplicationApi = usePlatAnimalCageApplicationApi()
  180. const finaceApi = useFinaceApi()
  181. const billApi = useBillApi()
  182. const returnCageDialogRef = ref<ReturnCageDialogInstance>()
  183. const detailModalRef = ref<DetailModalInstance>()
  184. const showDetailDialog = ref<boolean>(false)
  185. const activeStatus = ref<MyCageType>(MyCageType.MINE_CAGE)
  186. const currentRefundableItemNumber = ref<number>(0)
  187. const state = reactive({
  188. pageList: [],
  189. loading: false,
  190. finished: false,
  191. queryParams: {
  192. pageNum: 1,
  193. pageSize: 10,
  194. id: null,
  195. },
  196. })
  197. const formatApproveStatus = (status: number) => {
  198. return ApproveStatusList.find((item) => item.id === status)?.name || ''
  199. }
  200. const handleRefundable = (row: any) => {
  201. currentRefundableItemNumber.value = row.number
  202. returnCageDialogRef.value.handleOpenRefundableDialog(row.id)
  203. }
  204. const handleRefresh = () => {
  205. resetQueryParams()
  206. onLoad()
  207. }
  208. const resetQueryParams = () => {
  209. ;(state.pageList = []),
  210. (state.loading = false),
  211. (state.finished = false),
  212. (state.queryParams = {
  213. pageNum: 1,
  214. pageSize: 10,
  215. id: null,
  216. })
  217. }
  218. const onLoad = async (isSearch?: boolean) => {
  219. state.loading = true
  220. let param = state.queryParams
  221. param.id = userInfos.value.id
  222. const [err, res]: ToResponse = await to(billApi.getFinBillableOrderList(param))
  223. state.loading = false
  224. if (err) return
  225. const list = res?.data?.list || []
  226. if (!isSearch) {
  227. for (const item of list) {
  228. state.pageList.push(item)
  229. }
  230. state.queryParams.pageNum++
  231. if (list.length < state.queryParams.pageSize) {
  232. state.finished = true
  233. }
  234. } else {
  235. state.pageList = list
  236. }
  237. }
  238. const handleCheckDetail = (row: any) => {
  239. detailModalRef.value.initForm(row.id)
  240. showDetailDialog.value = true
  241. }
  242. const search = () => {
  243. onLoad(true)
  244. }
  245. const formatterFboType = (row: any) => {
  246. if (row.fboBizCode.startsWith('WT')) {
  247. return '技术服务计费'
  248. } else if (row.fboBizCode.startsWith('YY')) {
  249. return '仪器预约费用'
  250. } else if (row.fboBizCode.startsWith('PR')) {
  251. return '平台入室费用'
  252. } else if (row.fboBizCode.startsWith('AM')) {
  253. return '动物管理费用'
  254. } else {
  255. return '其他管理费用'
  256. }
  257. }
  258. // 10计费中 20待确认 30已确认 40 已上账 50 已报销/结算 90 已取消
  259. const formatterFboStatus = (row: any) => {
  260. switch (row.fboStatus) {
  261. case '10':
  262. return '计费中'
  263. case '20':
  264. return '待确认'
  265. case '30':
  266. return '已确认'
  267. case '40':
  268. return '已上账'
  269. case '50':
  270. return '已报销/结算'
  271. case '90':
  272. return '已取消'
  273. default:
  274. return '-'
  275. }
  276. }
  277. const handleExport = async () => {}
  278. onMounted(() => {
  279. onLoad()
  280. })
  281. </script>
  282. <style lang="scss" scoped>
  283. .entry-container {
  284. position: relative;
  285. display: flex;
  286. flex-direction: column;
  287. .search-wrap {
  288. background: #fff;
  289. margin-bottom: 10px;
  290. padding: 15px;
  291. }
  292. .list-container {
  293. overflow-y: auto;
  294. padding: 10px;
  295. border-radius: 4px;
  296. flex: 1;
  297. }
  298. .van-list {
  299. .van-cell {
  300. background-color: #fff;
  301. + .van-cell {
  302. margin-top: 10px;
  303. }
  304. header,
  305. footer {
  306. color: #333;
  307. }
  308. .title {
  309. flex: 1;
  310. white-space: nowrap;
  311. overflow: hidden;
  312. text-overflow: ellipsis;
  313. text-align: left;
  314. }
  315. .inst-title {
  316. color: #333;
  317. text-align: left;
  318. flex: 1;
  319. overflow: hidden;
  320. white-space: nowrap;
  321. text-overflow: ellipsis;
  322. margin-top: 4px;
  323. span:first-child {
  324. color: rgb(120, 120, 120);
  325. }
  326. }
  327. .time {
  328. color: #f69a4d;
  329. }
  330. }
  331. }
  332. }
  333. </style>