marketingActivityIndex.js 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  1. // @ts-check
  2. import {
  3. getList,
  4. getDetail,
  5. update,
  6. approveWithSmartRecord,
  7. getApprovalRecords,
  8. getApprovalRecordDetail,
  9. addApprovalRecord,
  10. updateApprovalRecord,
  11. saveApprovalRecord,
  12. getActivityAttachments
  13. } from '@/api/order/marketing-activity'
  14. import { formatFileSize } from '@/util/util'
  15. import { mapGetters } from 'vuex'
  16. import {
  17. ACTIVITY_TYPE,
  18. APPROVAL_STATUS,
  19. FILE_TYPE,
  20. ACTIVITY_TYPE_OPTIONS,
  21. APPROVAL_STATUS_OPTIONS,
  22. getApprovalStatusLabel,
  23. getApprovalStatusType as getStatusType,
  24. getFileTypeIcon as getFileIcon
  25. } from '@/constants/marketing-activity'
  26. import { getActivityTypeType, getApprovalStatusType } from '../../../constants'
  27. /**
  28. * @typedef {import('../types').MarketingActivityRecord} MarketingActivityRecord
  29. * @typedef {import('../types').ActivityAttachment} ActivityAttachment
  30. * @typedef {import('../types').ApprovalRecord} ApprovalRecord
  31. * @typedef {import('../types').MarketingActivityComponent} MarketingActivityComponent
  32. * @typedef {import('../types').PageInfo} PageInfo
  33. * @typedef {import('../types').MarketingActivityForm} MarketingActivityForm
  34. * @typedef {import('../types').MarketingActivityQueryParams} MarketingActivityQueryParams
  35. */
  36. /**
  37. * @typedef {Object} ApprovalRecordAddParams
  38. * @property {string|number} activityId
  39. * @property {string} activityCode
  40. * @property {number} approvalStatus
  41. * @property {string} approvalRemark
  42. * @property {string|number} approverId
  43. * @property {string} approverName
  44. * @property {string} approvalTime
  45. */
  46. /**
  47. * @typedef {Object} UserInfo
  48. * @property {string|number} user_id
  49. * @property {string|number} userId
  50. * @property {string} user_name
  51. * @property {string} userName
  52. * @property {string} name
  53. */
  54. /**
  55. * 营销活动管理混入
  56. * @this {MarketingActivityComponent & Vue}
  57. */
  58. export default {
  59. data() {
  60. return {
  61. /**
  62. * 详情加载状态
  63. * @type {boolean}
  64. */
  65. detailLoading: false,
  66. /**
  67. * 图片预览弹窗配置
  68. * @type {Object}
  69. */
  70. imagePreviewDialog: {
  71. visible: false,
  72. imageUrl: '',
  73. fileName: '',
  74. currentAttachment: null
  75. },
  76. /**
  77. * 查看弹窗显示状态
  78. * @type {boolean}
  79. */
  80. viewDialogVisible: false,
  81. /**
  82. * 当前查看的活动详情
  83. * @type {MarketingActivityItem|null}
  84. */
  85. currentViewActivity: null,
  86. /**
  87. * 附件列表数据
  88. * @type {Array<ActivityAttachmentItem>}
  89. */
  90. attachmentsList: [],
  91. /**
  92. * 附件加载状态
  93. * @type {boolean}
  94. */
  95. attachmentsLoading: false,
  96. /**
  97. * 审批记录对话框配置
  98. * @type {Object}
  99. */
  100. approvalRecordsDialog: {
  101. visible: false,
  102. loading: false,
  103. activityId: '',
  104. activityCode: '',
  105. activityTitle: '',
  106. data: [],
  107. page: {
  108. current: 1,
  109. size: 10,
  110. total: 0
  111. }
  112. },
  113. /**
  114. * 表格数据
  115. * @type {MarketingActivityRecord[]}
  116. */
  117. data: [],
  118. /**
  119. * 查询参数
  120. * @type {MarketingActivityQueryParams}
  121. */
  122. query: {},
  123. /**
  124. * 表单数据
  125. * @type {MarketingActivityRecord}
  126. */
  127. form: {},
  128. /**
  129. * 选中的数据列表
  130. * @type {MarketingActivityRecord[]}
  131. */
  132. selectionList: [],
  133. /**
  134. * 表格加载状态
  135. * @type {boolean}
  136. */
  137. loading: true,
  138. /**
  139. * 分页配置
  140. * @type {Object}
  141. */
  142. page: {
  143. pageSize: 10,
  144. currentPage: 1,
  145. total: 0
  146. },
  147. /**
  148. * 审批对话框配置
  149. * @type {Object}
  150. */
  151. approvalDialog: {
  152. visible: false,
  153. loading: false,
  154. title: ''
  155. },
  156. /**
  157. * 审批表单数据
  158. * @type {Object}
  159. */
  160. approvalForm: {
  161. id: '',
  162. title: '',
  163. customerName: '',
  164. approvalStatus: 1,
  165. approvalRemark: ''
  166. },
  167. /**
  168. * 审批表单验证规则
  169. * @type {Object}
  170. */
  171. approvalRules: {
  172. approvalRemark: [
  173. { required: true, message: '请输入审批意见', trigger: 'blur' },
  174. { min: 5, message: '审批意见至少5个字符', trigger: 'blur' },
  175. { max: 500, message: '审批意见不能超过500个字符', trigger: 'blur' }
  176. ]
  177. },
  178. /**
  179. * 表格配置
  180. * @type {Object}
  181. */
  182. option: {
  183. height: 'auto',
  184. calcHeight: 30,
  185. tip: false,
  186. searchShow: true,
  187. searchMenuSpan: 18,
  188. searchIndex: 3,
  189. border: true,
  190. index: true,
  191. viewBtn: true,
  192. editBtn: false,
  193. delBtn: false,
  194. addBtn: false,
  195. column: [
  196. {
  197. label: '活动编码',
  198. prop: 'activityCode',
  199. minWidth: 120,
  200. search: true,
  201. fixed: true
  202. },
  203. {
  204. label: '活动标题',
  205. prop: 'title',
  206. minWidth: 200,
  207. search: true,
  208. overHidden: true
  209. },
  210. {
  211. label: '客户名称',
  212. prop: 'customerName',
  213. minWidth: 150,
  214. search: true,
  215. overHidden: true
  216. },
  217. {
  218. label: '联系人',
  219. prop: 'contactName',
  220. minWidth: 100,
  221. overHidden: true
  222. },
  223. {
  224. label: '联系电话',
  225. prop: 'contactPhone',
  226. minWidth: 120,
  227. overHidden: true
  228. },
  229. {
  230. label: '活动类型',
  231. prop: 'activityType',
  232. minWidth: 100,
  233. search: true,
  234. type: 'select',
  235. dicData: ACTIVITY_TYPE_OPTIONS
  236. },
  237. {
  238. label: '活动时间',
  239. prop: 'activityPeriod',
  240. minWidth: 180,
  241. slot: true,
  242. sortable: false,
  243. search: false
  244. },
  245. {
  246. label: '促销价格',
  247. prop: 'promotionPrice',
  248. minWidth: 120,
  249. slot: true,
  250. sortable: true
  251. },
  252. {
  253. label: '审批状态',
  254. prop: 'approvalStatus',
  255. minWidth: 100,
  256. slot: true,
  257. search: true,
  258. type: 'select',
  259. dicData: APPROVAL_STATUS_OPTIONS
  260. },
  261. {
  262. label: '审批人',
  263. prop: 'approverName',
  264. minWidth: 100,
  265. overHidden: true
  266. },
  267. {
  268. label: '审批时间',
  269. prop: 'approvalTime',
  270. minWidth: 150,
  271. type: 'datetime',
  272. format: 'yyyy-MM-dd HH:mm:ss',
  273. valueFormat: 'yyyy-MM-dd HH:mm:ss'
  274. },
  275. {
  276. label: '创建时间',
  277. prop: 'createTime',
  278. minWidth: 150,
  279. type: 'datetime',
  280. format: 'yyyy-MM-dd HH:mm:ss',
  281. valueFormat: 'yyyy-MM-dd HH:mm:ss',
  282. addDisplay: false,
  283. editDisplay: false,
  284. viewDisplay: true
  285. },
  286. {
  287. label: '更新时间',
  288. prop: 'updateTime',
  289. minWidth: 150,
  290. type: 'datetime',
  291. format: 'yyyy-MM-dd HH:mm:ss',
  292. valueFormat: 'yyyy-MM-dd HH:mm:ss',
  293. addDisplay: false,
  294. editDisplay: false,
  295. viewDisplay: true
  296. },
  297. {
  298. label: '活动描述',
  299. prop: 'description',
  300. minWidth: 200,
  301. type: 'textarea',
  302. overHidden: true,
  303. span: 24,
  304. addDisplay: false,
  305. editDisplay: false,
  306. viewDisplay: true
  307. },
  308. {
  309. label: '审批备注',
  310. prop: 'approvalRemark',
  311. minWidth: 200,
  312. type: 'textarea',
  313. overHidden: true,
  314. span: 24,
  315. addDisplay: false,
  316. editDisplay: false,
  317. viewDisplay: true
  318. }
  319. ]
  320. },
  321. /**
  322. * 权限列表
  323. * @type {Object}
  324. */
  325. permissionList: {
  326. addBtn: false,
  327. viewBtn: false,
  328. delBtn: false,
  329. editBtn: false
  330. }
  331. }
  332. },
  333. computed: {
  334. ...mapGetters(['permission', 'userInfo']),
  335. /**
  336. * 选中的ID列表
  337. * @returns {string} 逗号分隔的ID字符串
  338. */
  339. ids() {
  340. const ids = []
  341. this.selectionList.forEach((ele) => {
  342. ids.push(ele.id)
  343. })
  344. return ids.join(',')
  345. }
  346. },
  347. methods: {
  348. /**
  349. * 判断是否为图片文件
  350. * @this {MarketingActivityComponent & Vue}
  351. * @param {string} fileType - 文件类型
  352. * @returns {boolean} 是否为图片文件
  353. */
  354. isImageFile(fileType) {
  355. if (!fileType) return false
  356. const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg']
  357. return imageTypes.includes(fileType.toLowerCase())
  358. },
  359. /**
  360. * 预览图片
  361. * @this {MarketingActivityComponent & Vue}
  362. * @param {ActivityAttachmentItem} attachment - 附件信息
  363. * @returns {void}
  364. */
  365. handlePreviewImage(attachment) {
  366. if (!this.isImageFile(attachment.fileType)) {
  367. this.$message.warning('该文件不是图片格式,无法预览')
  368. return
  369. }
  370. if (!attachment.fileUrl) {
  371. this.$message.warning('图片链接不存在')
  372. return
  373. }
  374. this.imagePreviewDialog = {
  375. visible: true,
  376. imageUrl: attachment.fileUrl.trim(),
  377. fileName: attachment.fileName,
  378. currentAttachment: attachment
  379. }
  380. },
  381. /**
  382. * 关闭图片预览弹窗
  383. * @this {MarketingActivityComponent & Vue}
  384. * @returns {void}
  385. */
  386. handleCloseImagePreview() {
  387. this.imagePreviewDialog = {
  388. visible: false,
  389. imageUrl: '',
  390. fileName: '',
  391. currentAttachment: null
  392. }
  393. },
  394. /**
  395. * 处理缩略图加载错误
  396. * @this {MarketingActivityComponent & Vue}
  397. * @param {Event} event - 错误事件
  398. * @returns {void}
  399. */
  400. handleImageError(event) {
  401. const target = event.target
  402. if (target) {
  403. target.style.display = 'none'
  404. const parent = target.parentNode
  405. if (parent && !parent.querySelector('.error-icon')) {
  406. const errorIcon = document.createElement('i')
  407. errorIcon.className = 'el-icon-picture-outline error-icon'
  408. errorIcon.style.fontSize = '24px'
  409. errorIcon.style.color = '#ccc'
  410. parent.appendChild(errorIcon)
  411. }
  412. }
  413. },
  414. /**
  415. * 处理预览图片加载错误
  416. * @this {MarketingActivityComponent & Vue}
  417. * @param {Event} event - 错误事件
  418. * @returns {void}
  419. */
  420. handlePreviewImageError(event) {
  421. this.$message.error('图片加载失败')
  422. const target = event.target
  423. if (target) {
  424. target.style.display = 'none'
  425. }
  426. },
  427. /**
  428. * 关闭查看弹窗
  429. * @this {MarketingActivityComponent & Vue}
  430. * @returns {void}
  431. */
  432. handleCloseViewDialog() {
  433. this.viewDialogVisible = false
  434. this.currentViewActivity = null
  435. this.attachmentsList = []
  436. // 同时关闭图片预览弹窗
  437. this.handleCloseImagePreview()
  438. },
  439. /**
  440. * 加载活动附件列表
  441. * @this {MarketingActivityComponent & Vue}
  442. * @param {string|number} activityId - 活动ID
  443. * @returns {Promise<void>}
  444. */
  445. async loadActivityAttachments(activityId) {
  446. if (!activityId) return
  447. this.attachmentsLoading = true
  448. try {
  449. const response = await getActivityAttachments(1, 100, activityId)
  450. if (response.data.success) {
  451. this.attachmentsList = response.data.data.records || []
  452. } else {
  453. this.$message.error('获取附件列表失败')
  454. this.attachmentsList = []
  455. }
  456. } catch (error) {
  457. console.error('获取附件列表失败:', error)
  458. this.$message.error('获取附件列表失败')
  459. this.attachmentsList = []
  460. } finally {
  461. this.attachmentsLoading = false
  462. }
  463. },
  464. /**
  465. * 预览附件
  466. * @this {MarketingActivityComponent & Vue}
  467. * @param {ActivityAttachmentItem} attachment - 附件信息
  468. * @returns {void}
  469. */
  470. handleViewAttachment(attachment) {
  471. if (attachment.fileUrl) {
  472. window.open(attachment.fileUrl.trim(), '_blank')
  473. } else {
  474. this.$message.warning('文件链接不存在')
  475. }
  476. },
  477. /**
  478. * 下载附件
  479. * @this {MarketingActivityComponent & Vue}
  480. * @param {ActivityAttachmentItem} attachment - 附件信息
  481. * @returns {void}
  482. */
  483. handleDownloadAttachment(attachment) {
  484. if (attachment.fileUrl) {
  485. const link = document.createElement('a')
  486. link.href = attachment.fileUrl.trim()
  487. link.download = attachment.fileName
  488. link.target = '_blank'
  489. document.body.appendChild(link)
  490. link.click()
  491. document.body.removeChild(link)
  492. } else {
  493. this.$message.warning('文件链接不存在')
  494. }
  495. },
  496. formatFileSize,
  497. /**
  498. * 获取文件类型图标
  499. * @this {MarketingActivityComponent & Vue}
  500. * @param {string} fileType - 文件类型
  501. * @returns {string} 图标类名
  502. */
  503. getFileTypeIcon(fileType) {
  504. return getFileIcon(fileType)
  505. },
  506. /**
  507. * 获取审批状态文本
  508. * @this {MarketingActivityComponent & Vue}
  509. * @param {number} status - 审批状态
  510. * @returns {string} 状态文本
  511. */
  512. getApprovalStatusText(status) {
  513. return getApprovalStatusLabel(status)
  514. },
  515. /**
  516. * 获取审批状态类型
  517. * @this {MarketingActivityComponent & Vue}
  518. * @param {number} status - 审批状态
  519. * @returns {string} 状态类型
  520. */
  521. getApprovalStatusType(status) {
  522. return getStatusType(status)
  523. },
  524. /**
  525. * 查看审批记录
  526. * @this {MarketingActivityComponent & Vue}
  527. * @param {MarketingActivityRecord} row - 营销活动记录
  528. */
  529. async handleViewApprovalRecords(row) {
  530. this.approvalRecordsDialog.visible = true
  531. this.approvalRecordsDialog.activityId = row.id
  532. this.approvalRecordsDialog.activityCode = row.activityCode
  533. this.approvalRecordsDialog.activityTitle = row.title
  534. this.approvalRecordsDialog.page.current = 1
  535. this.approvalRecordsDialog.page.size = 10
  536. await this.loadApprovalRecords()
  537. },
  538. /**
  539. * 加载审批记录数据
  540. * @this {MarketingActivityComponent & Vue}
  541. */
  542. async loadApprovalRecords() {
  543. try {
  544. this.approvalRecordsDialog.loading = true
  545. const response = await getApprovalRecords(
  546. this.approvalRecordsDialog.page.current,
  547. this.approvalRecordsDialog.page.size,
  548. this.approvalRecordsDialog.activityId
  549. )
  550. if (response.data.success) {
  551. const { records, total, current, size } = response.data.data
  552. this.approvalRecordsDialog.data = records || []
  553. this.approvalRecordsDialog.page.total = total || 0
  554. this.approvalRecordsDialog.page.current = current || 1
  555. this.approvalRecordsDialog.page.size = size || 10
  556. } else {
  557. this.$message.error(response.data.msg || '获取审批记录失败')
  558. this.approvalRecordsDialog.data = []
  559. this.approvalRecordsDialog.page.total = 0
  560. }
  561. } catch (error) {
  562. console.error('获取审批记录失败:', error)
  563. this.$message.error('获取审批记录失败,请稍后重试')
  564. this.approvalRecordsDialog.data = []
  565. this.approvalRecordsDialog.page.total = 0
  566. } finally {
  567. this.approvalRecordsDialog.loading = false
  568. }
  569. },
  570. /**
  571. * 审批记录分页大小变化
  572. * @this {MarketingActivityComponent & Vue}
  573. * @param {number} size - 新的分页大小
  574. */
  575. async handleApprovalRecordsSizeChange(size) {
  576. this.approvalRecordsDialog.page.size = size
  577. this.approvalRecordsDialog.page.current = 1
  578. await this.loadApprovalRecords()
  579. },
  580. /**
  581. * 审批记录当前页变化
  582. * @this {MarketingActivityComponent & Vue}
  583. * @param {number} current - 新的当前页
  584. */
  585. async handleApprovalRecordsCurrentChange(current) {
  586. this.approvalRecordsDialog.page.current = current
  587. await this.loadApprovalRecords()
  588. },
  589. /**
  590. * 重置审批记录对话框
  591. * @this {MarketingActivityComponent & Vue}
  592. */
  593. resetApprovalRecordsDialog() {
  594. this.approvalRecordsDialog.visible = false
  595. this.approvalRecordsDialog.loading = false
  596. this.approvalRecordsDialog.activityId = ''
  597. this.approvalRecordsDialog.activityCode = ''
  598. this.approvalRecordsDialog.activityTitle = ''
  599. this.approvalRecordsDialog.data = []
  600. this.approvalRecordsDialog.page = {
  601. current: 1,
  602. size: 10,
  603. total: 0
  604. }
  605. },
  606. /**
  607. * 查看详情
  608. * @this {MarketingActivityComponent & Vue}
  609. * @param {MarketingActivityRecord} row - 行数据
  610. * @returns {Promise<void>}
  611. */
  612. async handleView(row) {
  613. this.viewDialogVisible = true
  614. this.currentViewActivity = null
  615. this.attachmentsList = []
  616. this.detailLoading = true
  617. try {
  618. // 获取活动详情
  619. const detailRes = await getDetail(row.id)
  620. if (detailRes.data.success) {
  621. this.currentViewActivity = detailRes.data.data
  622. // 同时加载附件数据
  623. await this.loadActivityAttachments(row.id)
  624. } else {
  625. this.$message.error('获取活动详情失败')
  626. }
  627. } catch (error) {
  628. console.error('获取活动详情失败:', error)
  629. this.$message.error('获取活动详情失败')
  630. } finally {
  631. this.detailLoading = false
  632. }
  633. },
  634. /**
  635. * 处理审批操作
  636. * @this {MarketingActivityComponent & Vue}
  637. * @param {MarketingActivityRecord} row - 行数据
  638. * @param {number} approvalStatus - 审批状态 2-通过 3-拒绝
  639. * @returns {void}
  640. */
  641. handleApprove(row, approvalStatus) {
  642. this.approvalForm = {
  643. id: row.id,
  644. title: row.title,
  645. customerName: row.customerName,
  646. approvalStatus,
  647. approvalRemark: ''
  648. }
  649. this.approvalDialog.title = approvalStatus === APPROVAL_STATUS.APPROVED
  650. ? getApprovalStatusLabel(APPROVAL_STATUS.APPROVED)
  651. : getApprovalStatusLabel(APPROVAL_STATUS.REJECTED)
  652. this.approvalDialog.visible = true
  653. },
  654. /**
  655. * 提交审批(智能审批记录管理)
  656. * @this {MarketingActivityComponent & Vue}
  657. */
  658. async submitApproval() {
  659. try {
  660. // 表单验证
  661. const valid = await this.$refs.approvalForm.validate()
  662. if (!valid) {
  663. return
  664. }
  665. this.approvalDialog.loading = true
  666. // 构建审批参数
  667. const approvalParams = {
  668. id: this.approvalForm.id,
  669. approvalStatus: this.approvalForm.approvalStatus,
  670. approvalRemark: this.approvalForm.approvalRemark
  671. }
  672. // 获取当前用户信息
  673. const currentUserInfo = {
  674. userId: this.userInfo.user_id || this.userInfo.userId,
  675. userName: this.userInfo.user_name || this.userInfo.userName || this.userInfo.name
  676. }
  677. // 执行智能审批操作(包含智能审批记录管理)
  678. const response = await approveWithSmartRecord(approvalParams, currentUserInfo)
  679. if (response.data.success) {
  680. this.$message.success('审批操作成功')
  681. this.approvalDialog.visible = false
  682. this.resetApprovalDialog()
  683. // 刷新列表数据
  684. await this.onLoad(this.page)
  685. } else {
  686. this.$message.error(response.data.msg || '审批操作失败')
  687. }
  688. } catch (error) {
  689. console.error('审批操作失败:', error)
  690. this.$message.error('审批操作失败,请稍后重试')
  691. } finally {
  692. this.approvalDialog.loading = false
  693. }
  694. },
  695. /**
  696. * 重置审批对话框
  697. * @this {MarketingActivityComponent & Vue}
  698. * @returns {void}
  699. */
  700. resetApprovalDialog() {
  701. this.approvalForm = {
  702. id: '',
  703. title: '',
  704. customerName: '',
  705. approvalStatus: 1,
  706. approvalRemark: ''
  707. }
  708. if (this.$refs.approvalForm) {
  709. this.$refs.approvalForm.resetFields()
  710. }
  711. },
  712. /**
  713. * 新增、编辑、查看前的回调
  714. * @this {MarketingActivityComponent & Vue}
  715. * @param {Function} done - 完成回调
  716. * @param {string} type - 操作类型
  717. * @returns {Promise<void>}
  718. */
  719. async beforeOpen(done, type) {
  720. if (['edit', 'view'].includes(type)) {
  721. try {
  722. const res = await getDetail(this.form.id)
  723. this.form = res.data.data
  724. } catch (error) {
  725. console.error('获取详情失败:', error)
  726. this.$message.error('获取详情失败')
  727. }
  728. }
  729. done()
  730. },
  731. /**
  732. * 删除操作
  733. * @this {MarketingActivityComponent & Vue}
  734. * @param {MarketingActivityRecord} row - 行数据
  735. * @returns {Promise<void>}
  736. */
  737. async rowDel(row) {
  738. try {
  739. await this.$confirm('确定将选择数据删除?', {
  740. confirmButtonText: '确定',
  741. cancelButtonText: '取消',
  742. type: 'warning'
  743. })
  744. // 注意:根据接口文档,没有删除接口,这里可能需要调用状态更新
  745. this.$message.warning('删除功能暂未开放')
  746. } catch (error) {
  747. console.error('删除失败:', error)
  748. }
  749. },
  750. /**
  751. * 批量删除
  752. * @this {MarketingActivityComponent & Vue}
  753. * @returns {Promise<void>}
  754. */
  755. async handleDelete() {
  756. if (this.selectionList.length === 0) {
  757. this.$message.warning('请选择至少一条数据')
  758. return
  759. }
  760. try {
  761. await this.$confirm('确定将选择数据删除?', {
  762. confirmButtonText: '确定',
  763. cancelButtonText: '取消',
  764. type: 'warning'
  765. })
  766. // 注意:根据接口文档,没有删除接口,这里可能需要调用状态更新
  767. this.$message.warning('删除功能暂未开放')
  768. } catch (error) {
  769. console.error('批量删除失败:', error)
  770. }
  771. },
  772. /**
  773. * 更新操作
  774. * @this {MarketingActivityComponent & Vue}
  775. * @param {MarketingActivityRecord} row - 行数据
  776. * @param {number} index - 行索引
  777. * @param {Function} done - 完成回调
  778. * @param {Function} loading - 加载状态回调
  779. * @returns {Promise<void>}
  780. */
  781. async rowUpdate(row, index, done, loading) {
  782. try {
  783. loading()
  784. await update(row)
  785. done()
  786. this.$message.success('操作成功')
  787. await this.onLoad(this.page)
  788. } catch (error) {
  789. loading()
  790. console.error('更新失败:', error)
  791. this.$message.error('操作失败')
  792. }
  793. },
  794. /**
  795. * 新增操作
  796. * @this {MarketingActivityComponent & Vue}
  797. * @param {MarketingActivityRecord} row - 行数据
  798. * @param {Function} done - 完成回调
  799. * @param {Function} loading - 加载状态回调
  800. * @returns {Promise<void>}
  801. */
  802. async rowSave(row, done, loading) {
  803. // 根据接口文档,没有新增接口,这里暂不实现
  804. loading()
  805. this.$message.warning('新增功能暂未开放')
  806. done()
  807. },
  808. /**
  809. * 搜索回调
  810. * @this {MarketingActivityComponent & Vue}
  811. * @param {MarketingActivityQueryParams} params - 搜索参数
  812. * @param {Function} done - 完成回调
  813. * @returns {void}
  814. */
  815. searchChange(params, done) {
  816. this.query = params
  817. this.page.currentPage = 1
  818. this.onLoad(this.page)
  819. done()
  820. },
  821. /**
  822. * 搜索重置回调
  823. * @this {MarketingActivityComponent & Vue}
  824. * @returns {void}
  825. */
  826. searchReset() {
  827. this.query = {}
  828. this.page.currentPage = 1
  829. this.onLoad(this.page)
  830. },
  831. /**
  832. * 选择改变回调
  833. * @this {MarketingActivityComponent & Vue}
  834. * @param {MarketingActivityRecord[]} list - 选中的数据列表
  835. * @returns {void}
  836. */
  837. selectionChange(list) {
  838. this.selectionList = list
  839. },
  840. /**
  841. * 清空选择回调
  842. * @this {MarketingActivityComponent & Vue}
  843. * @returns {void}
  844. */
  845. selectionClear() {
  846. this.selectionList = []
  847. this.$refs.crud.toggleSelection()
  848. },
  849. /**
  850. * 当前页改变回调
  851. * @this {MarketingActivityComponent & Vue}
  852. * @param {number} currentPage - 当前页码
  853. * @returns {void}
  854. */
  855. currentChange(currentPage) {
  856. this.page.currentPage = currentPage
  857. },
  858. /**
  859. * 页大小改变回调
  860. * @this {MarketingActivityComponent & Vue}
  861. * @param {number} pageSize - 页大小
  862. * @returns {void}
  863. */
  864. sizeChange(pageSize) {
  865. this.page.pageSize = pageSize
  866. },
  867. /**
  868. * 刷新回调
  869. * @this {MarketingActivityComponent & Vue}
  870. * @returns {void}
  871. */
  872. refreshChange() {
  873. this.onLoad(this.page)
  874. },
  875. /**
  876. * 数据加载
  877. * @this {MarketingActivityComponent & Vue}
  878. * @param {Object} page - 分页参数
  879. * @param {Object} [params] - 查询参数
  880. * @returns {Promise<void>}
  881. */
  882. async onLoad(page, params) {
  883. this.loading = true
  884. try {
  885. const response = await getList(
  886. page.currentPage || 1,
  887. page.pageSize || 10,
  888. Object.assign(params || {}, this.query)
  889. )
  890. if (response.data && response.data.success) {
  891. const data = response.data.data
  892. this.data = data.records || []
  893. this.page.total = data.total || 0
  894. } else {
  895. this.data = []
  896. this.page.total = 0
  897. this.$message.warning('获取数据失败')
  898. }
  899. } catch (error) {
  900. this.data = []
  901. this.page.total = 0
  902. console.error('加载数据失败:', error)
  903. this.$message.error('加载数据失败,请稍后重试')
  904. } finally {
  905. this.loading = false
  906. }
  907. },
  908. /**
  909. * 手动保存审批记录(用于特殊场景)
  910. * @this {MarketingActivityComponent & Vue}
  911. * @param {string|number} activityId - 活动ID
  912. * @param {Object} approvalData - 审批数据
  913. */
  914. async handleSaveApprovalRecord(activityId, approvalData) {
  915. try {
  916. // 获取当前用户信息
  917. const currentUserInfo = {
  918. userId: this.userInfo.user_id || this.userInfo.userId,
  919. userName: this.userInfo.user_name || this.userInfo.userName || this.userInfo.name
  920. }
  921. const response = await saveApprovalRecord(
  922. activityId,
  923. currentUserInfo.userId,
  924. approvalData
  925. )
  926. if (response.data && response.data.success) {
  927. this.$message.success('审批记录保存成功')
  928. // 如果审批记录弹窗是打开的,刷新审批记录列表
  929. if (this.approvalRecordsDialog.visible) {
  930. await this.loadApprovalRecords()
  931. }
  932. } else {
  933. this.$message.error(response.data?.msg || '审批记录保存失败')
  934. }
  935. } catch (error) {
  936. console.error('保存审批记录失败:', error)
  937. this.$message.error('保存审批记录失败,请稍后重试')
  938. }
  939. }
  940. },
  941. /**
  942. * 组件挂载后初始化
  943. * @returns {void}
  944. */
  945. mounted() {
  946. this.onLoad(this.page)
  947. }
  948. }