index.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. import { getClaimList, getClaimDetail, getClaimAttachments, getClaimAuditList, addClaimAudit, updateClaimAudit, removeClaimAudit } from '@/api/claim/index'
  2. import { formatFileSize } from '@/util/util'
  3. import { mapGetters } from 'vuex'
  4. export default {
  5. data() {
  6. return {
  7. form: {},
  8. query: {},
  9. loading: true,
  10. page: {
  11. pageSize: 10,
  12. currentPage: 1,
  13. total: 0
  14. },
  15. selectionList: [],
  16. detailVisible: false,
  17. attachmentVisible: false,
  18. auditVisible: false,
  19. auditFormVisible: false,
  20. claimDetail: null,
  21. attachmentList: [],
  22. auditList: [],
  23. attachmentLoading: false,
  24. auditLoading: false,
  25. auditFormLoading: false,
  26. currentClaimRow: null,
  27. auditFormMode: 'add', // 'add' | 'edit'
  28. // 图片预览相关状态
  29. imagePreviewVisible: false,
  30. previewImageUrl: '',
  31. previewImageList: [],
  32. currentPreviewIndex: 0,
  33. // 视频预览相关状态
  34. videoPreviewVisible: false,
  35. previewVideoUrl: '',
  36. auditForm: {
  37. id: null,
  38. claimId: null,
  39. claimNo: '',
  40. auditResult: null,
  41. auditAmount: 0,
  42. reasonDetail: '',
  43. auditorId: null,
  44. auditorName: '',
  45. auditTime: '',
  46. feedbackChannel: '',
  47. feedbackDesc: '',
  48. feedbackTime: '',
  49. appealStatus: 0,
  50. appealResult: '',
  51. appealTime: ''
  52. },
  53. auditFormRules: {
  54. auditResult: [
  55. { required: true, message: '请选择审核结果', trigger: 'change' }
  56. ],
  57. auditAmount: [
  58. { required: true, message: '请输入审核金额', trigger: 'blur' }
  59. ],
  60. reasonDetail: [
  61. { required: true, message: '请输入审核说明', trigger: 'blur' },
  62. { min: 10, message: '审核说明至少10个字符', trigger: 'blur' }
  63. ],
  64. auditorName: [
  65. { required: true, message: '请输入审核人姓名', trigger: 'blur' }
  66. ],
  67. auditTime: [
  68. { required: true, message: '请选择审核时间', trigger: 'change' }
  69. ]
  70. },
  71. option: {
  72. height: 'auto',
  73. calcHeight: 30,
  74. tip: false,
  75. searchShow: true,
  76. searchMenuSpan: 6,
  77. border: true,
  78. index: true,
  79. indexLabel: '序号',
  80. selection: true,
  81. viewBtn: false,
  82. editBtn: false,
  83. delBtn: false,
  84. addBtn: false,
  85. column: [
  86. {
  87. label: '理赔编号',
  88. prop: 'claimNo',
  89. search: true
  90. },
  91. {
  92. label: '来源类型',
  93. prop: 'claimSourceType',
  94. type: 'select',
  95. dicData: [
  96. { label: '经销商', value: 1 },
  97. { label: '门店', value: 2 }
  98. ],
  99. search: true,
  100. slot: true
  101. },
  102. {
  103. label: '来源名称',
  104. prop: 'sourceName',
  105. search: true
  106. },
  107. {
  108. label: '来源编码',
  109. prop: 'sourceCode',
  110. search: true
  111. },
  112. {
  113. label: '消费者姓名',
  114. prop: 'consumerName',
  115. search: true
  116. },
  117. {
  118. label: '消费者电话',
  119. prop: 'consumerPhone',
  120. search: true
  121. },
  122. {
  123. label: '轮胎编号',
  124. prop: 'tyreNo',
  125. search: true
  126. },
  127. {
  128. label: '轮胎规格',
  129. prop: 'tyreSpecs'
  130. },
  131. {
  132. label: '理赔金额',
  133. prop: 'claimAmount',
  134. type: 'number'
  135. },
  136. {
  137. label: '审核状态',
  138. prop: 'auditStatus',
  139. type: 'select',
  140. dicData: [
  141. { label: '待审核', value: 0 },
  142. { label: '审核通过', value: 1 },
  143. { label: '审核拒绝', value: 2 }
  144. ],
  145. search: true,
  146. slot: true
  147. },
  148. {
  149. label: '提交时间',
  150. prop: 'submitTime',
  151. type: 'datetime',
  152. format: 'yyyy-MM-dd HH:mm:ss',
  153. valueFormat: 'yyyy-MM-dd HH:mm:ss'
  154. }
  155. ]
  156. },
  157. data: []
  158. }
  159. },
  160. computed: {
  161. ...mapGetters(['permission'])
  162. },
  163. methods: {
  164. /**
  165. * 获取列表数据
  166. * @param {Object} page - 分页参数
  167. * @param {Object} params - 查询参数
  168. */
  169. async onLoad(page, params = {}) {
  170. try {
  171. this.loading = true
  172. const res = await getClaimList(page.currentPage, page.pageSize, Object.assign(params, this.query))
  173. const data = res.data.data
  174. this.page.total = data.total
  175. this.data = data.records
  176. } catch (error) {
  177. console.error('获取理赔列表失败:', error)
  178. this.$message.error('获取理赔列表失败')
  179. } finally {
  180. this.loading = false
  181. }
  182. },
  183. /**
  184. * 搜索
  185. * @param {Object} params - 搜索参数
  186. * @param {Function} done - 完成回调
  187. */
  188. searchChange(params, done) {
  189. this.query = params
  190. this.onLoad(this.page, params)
  191. done()
  192. },
  193. /**
  194. * 搜索重置
  195. */
  196. searchReset() {
  197. this.query = {}
  198. this.onLoad(this.page)
  199. },
  200. /**
  201. * 选择改变
  202. * @param {Array} list - 选中的列表
  203. */
  204. selectionChange(list) {
  205. this.selectionList = list
  206. },
  207. /**
  208. * 当前页改变
  209. * @param {number} currentPage - 当前页码
  210. */
  211. currentChange(currentPage) {
  212. this.page.currentPage = currentPage
  213. },
  214. /**
  215. * 页大小改变
  216. * @param {number} pageSize - 页大小
  217. */
  218. sizeChange(pageSize) {
  219. this.page.pageSize = pageSize
  220. },
  221. /**
  222. * 刷新
  223. */
  224. refreshChange() {
  225. this.onLoad(this.page, this.query)
  226. },
  227. /**
  228. * 查看详情
  229. * @param {Object} row - 行数据
  230. */
  231. async handleDetail(row) {
  232. try {
  233. const res = await getClaimDetail(row.id)
  234. this.claimDetail = res.data.data
  235. this.detailVisible = true
  236. } catch (error) {
  237. console.error('获取理赔详情失败:', error)
  238. this.$message.error('获取理赔详情失败')
  239. }
  240. },
  241. /**
  242. * 查看附件
  243. * @param {Object} row - 行数据
  244. */
  245. async handleAttachments(row) {
  246. try {
  247. this.attachmentLoading = true
  248. this.attachmentVisible = true
  249. const res = await getClaimAttachments(1, 1000, row.id)
  250. this.attachmentList = res.data.data.records || []
  251. } catch (error) {
  252. console.error('获取理赔附件失败:', error)
  253. this.$message.error('获取理赔附件失败')
  254. } finally {
  255. this.attachmentLoading = false
  256. }
  257. },
  258. /**
  259. * 查看审核记录
  260. * @param {Object} row - 行数据
  261. */
  262. async handleAudit(row) {
  263. try {
  264. this.currentClaimRow = row
  265. this.auditLoading = true
  266. this.auditVisible = true
  267. const res = await getClaimAuditList(1, 100, row.id)
  268. this.auditList = res.data.data.records || []
  269. } catch (error) {
  270. console.error('获取审核记录失败:', error)
  271. this.$message.error('获取审核记录失败')
  272. } finally {
  273. this.auditLoading = false
  274. }
  275. },
  276. /**
  277. * 新增审核记录
  278. */
  279. handleAddAudit() {
  280. this.auditFormMode = 'add'
  281. this.resetAuditForm()
  282. this.auditForm.claimId = this.currentClaimRow.id
  283. this.auditForm.claimNo = this.currentClaimRow.claimNo
  284. this.auditFormVisible = true
  285. },
  286. /**
  287. * 编辑审核记录
  288. * @param {Object} row - 审核记录数据
  289. */
  290. handleEditAudit(row) {
  291. this.auditFormMode = 'edit'
  292. this.auditForm = {
  293. id: row.id,
  294. claimId: row.claimId,
  295. claimNo: row.claimNo,
  296. auditResult: row.auditResult,
  297. auditAmount: row.auditAmount,
  298. reasonDetail: row.reasonDetail,
  299. auditorId: row.auditorId,
  300. auditorName: row.auditorName,
  301. auditTime: row.auditTime,
  302. feedbackChannel: row.feedbackChannel || '',
  303. feedbackDesc: row.feedbackDesc || '',
  304. feedbackTime: row.feedbackTime || '',
  305. appealStatus: row.appealStatus || 0,
  306. appealResult: row.appealResult || '',
  307. appealTime: row.appealTime || ''
  308. }
  309. this.auditFormVisible = true
  310. },
  311. /**
  312. * 删除审核记录
  313. * @param {Object} row - 审核记录数据
  314. */
  315. async handleDeleteAudit(row) {
  316. try {
  317. await this.$confirm('确定删除该审核记录吗?', '提示', {
  318. confirmButtonText: '确定',
  319. cancelButtonText: '取消',
  320. type: 'warning'
  321. })
  322. await removeClaimAudit(row.id)
  323. this.$message.success('删除成功')
  324. this.refreshAuditList()
  325. } catch (error) {
  326. if (error !== 'cancel') {
  327. console.error('删除审核记录失败:', error)
  328. this.$message.error('删除审核记录失败')
  329. }
  330. }
  331. },
  332. /**
  333. * 保存审核记录
  334. */
  335. async handleSaveAudit() {
  336. try {
  337. const valid = await this.$refs.auditFormRef.validate()
  338. if (!valid) return
  339. this.auditFormLoading = true
  340. // 设置审核人ID(这里可以从用户信息中获取)
  341. if (!this.auditForm.auditorId) {
  342. this.auditForm.auditorId = 10001 // 默认审核人ID,实际应该从当前登录用户获取
  343. }
  344. if (this.auditFormMode === 'add') {
  345. await addClaimAudit(this.auditForm)
  346. this.$message.success('新增审核记录成功')
  347. } else {
  348. await updateClaimAudit(this.auditForm)
  349. this.$message.success('更新审核记录成功')
  350. }
  351. this.auditFormVisible = false
  352. this.refreshAuditList()
  353. } catch (error) {
  354. console.error('保存审核记录失败:', error)
  355. this.$message.error('保存审核记录失败')
  356. } finally {
  357. this.auditFormLoading = false
  358. }
  359. },
  360. /**
  361. * 重置审核表单
  362. */
  363. resetAuditForm() {
  364. this.auditForm = {
  365. id: null,
  366. claimId: null,
  367. claimNo: '',
  368. auditResult: null,
  369. auditAmount: 0,
  370. reasonDetail: '',
  371. auditorId: null,
  372. auditorName: '',
  373. auditTime: '',
  374. feedbackChannel: '',
  375. feedbackDesc: '',
  376. feedbackTime: '',
  377. appealStatus: 0,
  378. appealResult: '',
  379. appealTime: ''
  380. }
  381. this.$nextTick(() => {
  382. if (this.$refs.auditFormRef) {
  383. this.$refs.auditFormRef.clearValidate()
  384. }
  385. })
  386. },
  387. /**
  388. * 刷新审核记录列表
  389. */
  390. async refreshAuditList() {
  391. if (!this.currentClaimRow) return
  392. try {
  393. this.auditLoading = true
  394. const res = await getClaimAuditList(1, 100, this.currentClaimRow.id)
  395. this.auditList = res.data.data.records || []
  396. } catch (error) {
  397. console.error('刷新审核记录失败:', error)
  398. this.$message.error('刷新审核记录失败')
  399. } finally {
  400. this.auditLoading = false
  401. }
  402. },
  403. /**
  404. * 下载文件
  405. * @param {Object} file - 文件信息
  406. */
  407. downloadFile(file) {
  408. window.open(file.fileUrl)
  409. },
  410. /**
  411. * 判断文件是否为图片
  412. * @param {string} fileName - 文件名
  413. * @returns {boolean} 是否为图片
  414. */
  415. isImageFile(fileName) {
  416. if (!fileName) return false
  417. const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg']
  418. const extension = fileName.toLowerCase().substring(fileName.lastIndexOf('.'))
  419. return imageExtensions.includes(extension)
  420. },
  421. /**
  422. * 判断文件是否为视频
  423. * @param {string} fileName - 文件名
  424. * @returns {boolean} 是否为视频
  425. */
  426. isVideoFile(fileName) {
  427. if (!fileName) return false
  428. const videoExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm', '.mkv']
  429. const extension = fileName.toLowerCase().substring(fileName.lastIndexOf('.'))
  430. return videoExtensions.includes(extension)
  431. },
  432. /**
  433. * 预览图片
  434. * @param {Object} file - 文件信息
  435. * @param {number} index - 当前图片索引
  436. */
  437. previewImage(file, index = 0) {
  438. if (this.isVideoFile(file.fileName)) {
  439. // 视频预览
  440. this.previewVideoUrl = file.fileUrl
  441. this.videoPreviewVisible = true
  442. } else if (this.isImageFile(file.fileName)) {
  443. // 图片预览
  444. const imageFiles = this.attachmentList.filter(item => this.isImageFile(item.fileName))
  445. this.previewImageList = imageFiles.map(item => item.fileUrl)
  446. this.currentPreviewIndex = imageFiles.findIndex(item => item.id === file.id)
  447. this.previewImageUrl = file.fileUrl
  448. this.imagePreviewVisible = true
  449. }
  450. },
  451. /**
  452. * 关闭图片预览
  453. */
  454. closeImagePreview() {
  455. this.imagePreviewVisible = false
  456. this.previewImageUrl = ''
  457. this.previewImageList = []
  458. this.currentPreviewIndex = 0
  459. },
  460. /**
  461. * 关闭视频预览
  462. */
  463. closeVideoPreview() {
  464. this.videoPreviewVisible = false
  465. this.previewVideoUrl = ''
  466. },
  467. /**
  468. * 处理图片加载错误
  469. * @param {Event} event - 错误事件
  470. */
  471. handleImageError(event) {
  472. event.target.src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjQwIiBoZWlnaHQ9IjQwIiBmaWxsPSIjRjVGNUY1Ii8+CjxwYXRoIGQ9Ik0yMCAyNkM5LjUgMjYgMSAxNy41IDEgN0MxIDMuNSA0IDEgNyAxSDMzQzM2IDEgMzkgMy41IDM5IDdDMzkgMTcuNSAzMC41IDI2IDIwIDI2WiIgZmlsbD0iI0NDQ0NDQyIvPgo8L3N2Zz4K'
  473. },
  474. // 添加公共方法引用
  475. formatFileSize,
  476. /**
  477. * 获取审核状态类型
  478. * @param {number} status - 审核状态
  479. * @returns {string} 状态类型
  480. */
  481. getAuditStatusType(status) {
  482. const typeMap = {
  483. 0: 'warning',
  484. 1: 'success',
  485. 2: 'danger'
  486. }
  487. return typeMap[status] || 'info'
  488. },
  489. /**
  490. * 获取审核状态文本
  491. * @param {number} status - 审核状态
  492. * @returns {string} 状态文本
  493. */
  494. getAuditStatusText(status) {
  495. const textMap = {
  496. 0: '待审核',
  497. 1: '审核通过',
  498. 2: '审核拒绝'
  499. }
  500. return textMap[status] || '未知'
  501. },
  502. /**
  503. * 获取审核结果类型
  504. * @param {number} result - 审核结果
  505. * @returns {string} 结果类型
  506. */
  507. getAuditResultType(result) {
  508. const typeMap = {
  509. 1: 'success',
  510. 2: 'danger'
  511. }
  512. return typeMap[result] || 'info'
  513. },
  514. /**
  515. * 处理视频加载错误
  516. * @param {Event} event - 错误事件
  517. */
  518. handleVideoError(event) {
  519. console.error('视频加载失败:', event)
  520. this.$message.error('视频加载失败,请检查视频文件')
  521. },
  522. /**
  523. * 获取审核结果文本
  524. * @param {number} result - 审核结果
  525. * @returns {string} 结果文本
  526. */
  527. getAuditResultText(result) {
  528. const textMap = {
  529. 1: '通过',
  530. 2: '拒绝'
  531. }
  532. return textMap[result] || '未知'
  533. }
  534. }
  535. }